<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="http://ka-hearth.learnerpages.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://ka-hearth.learnerpages.com/" rel="alternate" type="text/html" /><updated>2024-05-24T01:49:58+00:00</updated><id>http://ka-hearth.learnerpages.com/feed.xml</id><title type="html">KA Hearth</title><subtitle>A small blog where Matthias posted thoughts on things happening around Khan Academy. (Archived)</subtitle><entry><title type="html">Using ES6 in KA HTML</title><link href="http://ka-hearth.learnerpages.com/posts/using-es6-in-ka-html" rel="alternate" type="text/html" title="Using ES6 in KA HTML" /><published>2020-10-18T00:00:00+00:00</published><updated>2020-10-18T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/using-es6-in-ka-html</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/using-es6-in-ka-html"><![CDATA[<h4 id="intro">Intro</h4>
<p>Using ES6 in the KA webpage environment is obviously desirable. And unlike the Processing.JS environment, it’s quite feasible.</p>

<p>For detail on how and why KA parses your HTML, see <a href="bypassing-slowparse">this post</a>, which seeks to answer how to disable Slowparse for large swaths of HTML.</p>

<h4 id="the-trick">The trick</h4>
<p>If, however, you merely want to disable KA’s parsing of your Javascript, you can put your Javascript inside a script tag with the type set to <code class="language-plaintext highlighter-rouge">application/javascript</code>.</p>

<p>Unfortunately, because KA doesn’t completely clear the window before re-running code, you can’t use <code class="language-plaintext highlighter-rouge">const</code> or <code class="language-plaintext highlighter-rouge">let</code>.</p>

<p>This technique also has the benefit/risk of bypassing KA’s infinite loop protection.</p>

<h4 id="how-it-works">How it works</h4>
<p>Slowparse tries to follow the HTML spec as closely as possible, so it ignores <code class="language-plaintext highlighter-rouge">script</code> blocks that don’t have a <code class="language-plaintext highlighter-rouge">script</code> type set to <code class="language-plaintext highlighter-rouge">text/javascript</code> (or unset of course). Browsers, on the other hand, will run code with a <code class="language-plaintext highlighter-rouge">script</code> that is any of the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types">valid MIME types</a> (or unset, or an empty string).</p>

<h4 id="example">Example</h4>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;</span>Example<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
    <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"application/javascript"</span><span class="nt">&gt;</span>
        <span class="c1">// `var` because `let` and `const` still don't work  </span>
        <span class="kd">var</span> <span class="nx">test</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello</span><span class="dl">"</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="nx">test</span><span class="p">();</span>
    <span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[Intro Using ES6 in the KA webpage environment is obviously desirable. And unlike the Processing.JS environment, it’s quite feasible.]]></summary></entry><entry><title type="html">The Events of September 22nd (or “The 3 hours I was banned”)</title><link href="http://ka-hearth.learnerpages.com/posts/events-of-september-22nd" rel="alternate" type="text/html" title="The Events of September 22nd (or “The 3 hours I was banned”)" /><published>2020-10-16T00:00:00+00:00</published><updated>2020-10-16T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/events-of-september-22nd</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/events-of-september-22nd"><![CDATA[<p>A lot happened on September 22nd. It is here arranged chronologically.</p>

<ol>
  <li><a href="https://www.khanacademy.org/profile/kaid_677522439299681569675958">Legolas</a> posted an <a href="https://support.khanacademy.org/hc/en-us/community/posts/360073354352-KA-Guardian-system-improvements">article</a> to the community help center. In summary, it called for
    <ul>
      <li>More transparency after Guardian actions (e.g. messaging banned people why they were banned)</li>
      <li>More consistency around Guardian action</li>
      <li>More appropriate disciplinary actions following breaking the rules (e.g. not hiding all programs after discussion infringements)</li>
    </ul>
  </li>
  <li>I posted a follow-up comment. It included:
    <ul>
      <li>A comment on the length of time over which KA has had issues with moderation</li>
      <li>An appeal for the most highly voted program on KA to be restored</li>
      <li>A list of prominent community members who had been banned. Here is that list:
        <ul>
          <li>HFM4</li>
          <li>TJ</li>
          <li><a href="https://www.khanacademy.org/profile/kaid_486291797225131982323911">Light Runner</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_806005010494028487929883">Gamechief999</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_587121826918705844471320">The #1 Base 12 Proponent</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_455920429074646065838008">Jett Burns</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_1167230140884859457175747">Loki</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_901380113796617843784450">Thomas Li</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_55939052732362825785511">Prometheus</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_757721856896775939251306">Matthias</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_98250319499372249175870">Isaac Emerald</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_145655330786057731504264">Green Ghost</a></li>
          <li><a href="https://www.khanacademy.org/profile/kaid_79492645558798574591143">BB-8 (Squishy Caterpillar)</a></li>
        </ul>

        <p><strong><em>To disclaim: I am not commenting on the fairness of these bans.</em></strong></p>
      </li>
    </ul>
  </li>
  <li>Legolas’s comment and my comment were edited to remove information about people’s bans.
    <ul>
      <li>Apparently moderators in the Help Center can edit comments</li>
      <li>The original comments I saved <a href="hc-post-backups">here</a>.</li>
      <li>Legolas’s comment was edited to remove any reference to #1 Base 12 Proponent and Isaac Emerald.</li>
      <li>The list of users, as well as the reference to UTD were removed from my comment</li>
      <li>Faile Lundberg, the Community Liaison, <a href="https://support.khanacademy.org/hc/en-us/community/posts/360073354352/comments/360012850051">commented</a>. Some excerpts:
        <ul>
          <li>“Several posts…mention specific users…in connection with banning actions,…which violates our Community Guidelines”</li>
          <li>“We’re actively considering how we can incorporate your feedback.”</li>
          <li>“a link to information about our <a href="https://support.khanacademy.org/hc/en-us/articles/115003343971-Why-was-I-banned-">Ban Appeal form</a>,”</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>I was banned from Khan Academy, and all programs over 30 votes were hidden. (~5:30 PM EDT)
    <ul>
      <li>Terra Magma was removed from the top-list</li>
      <li>I did not receive a guardian message or any communication indicating why this would be</li>
    </ul>
  </li>
  <li>Photonic Symmetry posted a <a href="https://support.khanacademy.org/hc/en-us/community/posts/360073354352/comments/360012933452">comment</a> pointing the irony of banning me while we attempted to discuss unfair bans</li>
  <li>
    <p>Faile Lundberg reached out to me, both on Zendesk and with a Guardian message to clarify the reason for my ban. (8:39 PM EDT)</p>

    <blockquote>
      <p>I worked with our Guardians to look at what prompted the recent ban on your account, and it looks like it was due to a link in the comments of one of your programs that advertised off-site content (it was removed by moderation yesterday).</p>
    </blockquote>

    <blockquote>
      <p>This was a minor offense and you haven’t had any interactions with the Guardians in a year, so I don’t think a ban was warranted, and we’ve reversed it.</p>
    </blockquote>

    <ul>
      <li>I had indeed posted some comments with offsite links that showed up on the first page of my discussion history, and that is indeed in violation of KA’s rules</li>
      <li>However, it is difficult to believe that it is a coincidence that this wasn’t an issue until now, and is now ban worthy.</li>
      <li>Faile Lundberg did indeed un-ban me, and unhid all my programs.
        <ul>
          <li>This is possibly the first time KA has unbanned and unhid a user’s programs, proving that it is possible</li>
          <li>Most of my programs are now marked as Guardian approved, which is interesting</li>
        </ul>
      </li>
      <li>I, of course, thanked her, and mentioned that there were many KA users in a very similar position to me who had not been banned</li>
    </ul>
  </li>
  <li>Faile Lundberg posted another <a href="https://support.khanacademy.org/hc/en-us/community/posts/360073354352/comments/360012941432">comment</a> on the main thread, stating that “I’ll be bringing the concerns you’ve raised…to the team”</li>
</ol>

<p>And we waited.</p>

<p>A couple days ago, October 12th, Faile Lundberg <a href="https://support.khanacademy.org/hc/en-us/community/posts/360073354352/comments/360013146692">commented</a> again on the thread, posting their resolution. In short, it was a commitment to better train Guardians to moderate and communicate more clearly and consistently. Additionally, she mentions that guardian applications have been re-opened.</p>

<p>Concerns were raised. Legolas in particular describes the community’s feelings well, when he says,</p>

<blockquote>
  <p>I think my first two points were addressed quite well.</p>
</blockquote>

<blockquote>
  <p>However, I was wondering if the team happens to have any response about my third point, which is assigning more appropriate disciplinary actions to bans</p>
</blockquote>

<p>How KA further responds or implements what they’ve promised, remains to be seen.</p>

<!-- KA Hearth discussion: https://discord.com/channels/591883693857964042/591884090601635840/757840114293407754

ka-chat: https://discord.com/channels/372895163279998976/704720248208883762/757817332075724890-->]]></content><author><name></name></author><summary type="html"><![CDATA[A lot happened on September 22nd. It is here arranged chronologically.]]></summary></entry><entry><title type="html">Backups of censored help center posts</title><link href="http://ka-hearth.learnerpages.com/posts/hc-post-backups" rel="alternate" type="text/html" title="Backups of censored help center posts" /><published>2020-10-16T00:00:00+00:00</published><updated>2020-10-16T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/hc-post-backups</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/hc-post-backups"><![CDATA[<p>This is a source for <a href="events-of-september-22nd">this</a> post.</p>

<h3 id="legolass-original-post">Legolas’s Original Post</h3>

<p>Hey there,
Many of the older members of the KA computing platform know who I am, but some of the more recent additions to the community may be less aware of who I am so I’ll give a quick introduction to give a bit of credibility to this post.
I’ve been an active member of the KA community for five years now. I used the math section through high school, I used the SAT prep to prepare for college entry, and throughout it all I was a programmer in the KA computer programming community. I was one of the people who created graphics and programs that newer people looked up to, and over the years I collected a large following of supporters of the KACP area. Two or three years ago I also became a support advocate and helped out here on the help center when I could. Now I’m a junior in college. While I’m not as active as I wish I could be, I make programs every now and then and have kept up a daily streak of more than 1300 days. I also am the owner of the largest Discord server dedicated to KA with hundreds of members joined. All that goes to say, I would say I’m an experienced, mature user of the community who has contributed and received significantly from the site. I really appreciate what KA has given me and I’d like to give back in any way I can. Which leads me to this post.
As I became more and more involved with KA, especially when I started the Discord server two years ago, I began to hear stories from members of the community regarding the guardians on the site. Personally, I really appreciate the force of Guardians. It takes a lot of dedication to moderate a website at all, not to mention one filled with younger people.
Throughout all the shared experiences and personal observations I’ve come up with a list of changes that I believe are necessary for the Guardian system. The Guardians are intended to be a group of moderators enforcing the rules to keep everyone safe. This includes child-accounting underage users, banning users engaging in inappropriate activities, and moderating chatting like tips and thanks and questions.
Obviously, that’s a great thing. It’s important to have a group of people behind the scenes helping to do this. It’s beneficial to KA as well to recruit volunteers to perform these tasks. And KA has measures taken to ensure that Guardians who are hired are indeed working to make Khan Academy a better place. But at the end of the day, there are issues with the Guardian system. What I’ve pondered and discussed for months are three simple problems which have simple solutions. I’ll go into more detail about these problems below the bullet points.</p>

<ul>
  <li>Guardians need more transparency</li>
  <li>Guardians need more consistency</li>
  <li>Guardians need more appropriate disciplinary actions</li>
</ul>

<p><strong>1. Guardians need more transparency</strong></p>

<p>The Guardian position is all about making sure users are following the Guidelines. For example, if a Guardian finds evidence that a user is underage then the user is child-accounted. However, the Guardians have the ability to perform actions like these without the user even knowing what happened. There is the ability for a Guardian to send a special “Guardian message” but there is no way to respond to the message if the user is confused or has questions about what the message is about. I believe that the Guardian system should be much more transparent. Every time a significant action (Ban, child-account, etc) happens, a Guardian message should be mandatory. I’m not aware of a place where there are records of Guardian actions on accounts, but if there is no recording system there should be one to hold Guardians accountable. In addition, there should be a contact within the Guardian message for the user to be able to contact either the Guardian or a Help Center representative for more clarification regarding the Guardian message. With the current system, abuse of power is very possible, and according to some accounts I have heard, it may already exist.</p>

<p><strong>2. Guardians need more consistency</strong></p>

<p>Disciplinary actions are necessary according to the nature of Khan Academy. It’s important to not only incorporate more transparency but also more consistency regarding the actions taken on users. From many accounts I’ve heard over the years, the Guardian system is inappropriately inconsistent with discipline, especially regarding bans and warnings. I’ve heard of some users given warning after warning without further consequences, while others are banned for minor infractions. If there was more transparency regarding these actions, I believe the problem of inconsistent discipline would be solved. Ideally, reasons for each action would be recorded along with any communication regarding the action. Therefore, consistency would be encouraged as a secondary consequence of transparency.</p>

<p><strong>3. Guardians need more appropriate disciplinary actions</strong></p>

<p>I think there are two common actions which Guardians do that are excluded from this point: Discussion edits and child-accounting. For obvious reasons these are not really actions that can be inappropriately used. On the other hand, banning is an action that can be and has been used in ways far exceeding the “crime.”</p>

<p>Since this is one of the most important points I will include several examples of how banning has been inappropriately used to discipline users.</p>

<p>Banning is considered the ultimate punishment besides actually deleting a user’s account. As far as I know, there are multiple levels of a ban that last varying amounts of time. During a ban, the user’s discussion ability is removed, and projects above a certain vote limit are hidden.</p>

<p>That might sound fine, but at the end of the day, it really isn’t.</p>

<p>Several years ago, a user called the #1 Base 12 Proponent (#1B12) was banned. As it says in his current bio, #1B12 wasn’t exactly the most polite user. He was known for making some harsh comments before his ban. However, there is another factor in the mix. #1B12 was also the creator of the top program in the whole KACP community with ten thousand votes, and multiple more projects with thousands of votes. When he was banned, these projects were hidden, permanently. Some of these projects were the core programs in the community, inspiring, entertaining, and educating literally thousands of students.</p>

<p>Isaac Emerald was also a popular programmer who contributed many, many programs as well. Most of them had hundreds or thousands of votes. For years, Isaac Emerald was one of the most inspiring programmers contributing some of KA’s best projects. Hundreds and hundreds of users learned from his code. However, Isaac released a project with religious hints over the summer. The project was hidden, and Isaac spoke up. He was promptly banned, with all of his projects hidden.</p>

<p>#1 Base 12 Proponent and Isaac Emerald were both well known programmers who made mistakes that may have warranted disciplinary action. But did their relatively minor crimes deserve the destruction of literal years of work and dedication? After their bans, both of the promising programmers went inactive, never to return. And they are only two users out of many who have had projects hidden and work lost from view forever.</p>

<p>Bans should only apply to discussion privileges. Inappropriate projects should be hidden of course, but discussion-based breaking of the guidelines should be corrected by removing those privileges.</p>

<p>Khan Academy is intended to nurture users and help them grow in their skills in whatever subject they are learning. How does hiding years of work help one learn anything except that one can be punished severely for a minor infraction?</p>

<p>None of my above points were made with a grievance towards Khan Academy. For years I’ve been a mature user and haven’t been affected at all by how the Guardians are moderating the site. My points for how KA needs improving come from a sense of wishing the site to be better.</p>

<p>Thanks for reading,</p>

<p>Legolas Greenleaf</p>

<p>Support Advocate and KA User</p>

<h3 id="my-original-post">My Original Post</h3>

<p>I agree wholeheartedly with Legolas. I want to emphasize the scope of this issue.</p>
<ol>
  <li>This has been going on for years. I first criticized the lack of transparency from guardian actions in <a href="https://www.khanacademy.org/computer-programming/ka-api-info-and-links/4621185492058112?qa_expand_key=ag5zfmtoYW4tYWNhZGVteXJkCxIIVXNlckRhdGEiQXVzZXJfaWRfa2V5X2h0dHA6Ly9nb29nbGVpZC5raGFuYWNhZGVteS5vcmcvMTA2ODY2MDYzOTg2MTY3ODM3ODkxDAsSCEZlZWRiYWNrGICAgKCE35YKDA">Jun 2016</a>, when Light Runner was banned for the first time, and many discussions of his ban were removed, all for unstated reasons. This issue has only gotten worse, in part as KA has moved from volunteers to contracted moderators. This shift has negatively effected the KA CP section, if not the site as a whole.</li>
  <li>The sheer number of prominent community users who have been banned. To be clear, these bans are in some cases warranted, but in all cases there is no official reason given. I do not wish for these users to be unbanned necessarily, merely that KA would unhide some programs, and show more discretion going forward. My informal list of users that I knew that have been banned:
    <ul>
      <li>HFM4</li>
      <li><a href="https://www.khanacademy.org/profile/kaid_486291797225131982323911">Light Runner</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_806005010494028487929883">Gamechief999</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_587121826918705844471320">The #1 Base 12 Proponent</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_302535497648085796213399">TJ</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_455920429074646065838008">Jett Burns</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_1167230140884859457175747">Loki</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_901380113796617843784450">Thomas Li</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_55939052732362825785511">Prometheus</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_757721856896775939251306">Matthias</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_98250319499372249175870">Isaac Emerald</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_145655330786057731504264">Green Ghost</a></li>
      <li><a href="https://www.khanacademy.org/profile/kaid_79492645558798574591143">BB-8 (Squishy Caterpillar)</a></li>
    </ul>
  </li>
</ol>

<p>Again, many of these users deserved to be banned, or have been unbanned. But they had a magnitude of popularity on Khan such that I think their programs should be restored and the reasons for their bans disclosed.</p>

<p>In particular, I would like Ultimate Tower Defense, which is currently the most voted program on Khan, to be restored. It would be a shame if it was passed in votes because its creator was rude. Not to mention the fact that it has been years since it was hidden.</p>

<p>Thank you, for recognizing the importance of communication in education,</p>

<p>Matthias</p>

<p>KA Computer Science Volunteer</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is a source for this post.]]></summary></entry><entry><title type="html">Audio thumbnails patched</title><link href="http://ka-hearth.learnerpages.com/posts/audio-thumbnails-update" rel="alternate" type="text/html" title="Audio thumbnails patched" /><published>2020-07-24T00:00:00+00:00</published><updated>2020-07-24T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/audio-thumbnails-update</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/audio-thumbnails-update"><![CDATA[<p>This is a followup to a previous <a href="/posts/custom-audio">post</a>, which described how it was possible to upload arbitrary base64 data to KA as a program image (“thumbnail” or “screenshot”).</p>

<p>KA has patched out this behavior, by adding a check to the type of data that you are uploading.</p>

<p>Attempting to upload data of a different type, yeilds a 400 error with the following message:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bad data supplied: Image must be png or gif format
</code></pre></div></div>

<p>Uploading animated GIFs still works, and this language implies that this behavior is intential.</p>

<p>(They are not verifying that the image data is valid, merely that it is an image. Uploading an invalid/corrupted PNG with an intact header is allowed. The file type that you send e.g. “data:image/png;base64,” is ignored, only the base64 data is used.)</p>

<p><a href="https://khanacademy.org/profile/kaid_901380113796617843784450">Thomas Li</a>, the inspiration for this technique, was able to continue to load arbitrary audio less-directly, by storing it in the code of another program. <a href="https://www.khanacademy.org/computer-programming/play-buffer-v21/5998595453304832">Example</a> (probably hidden by now).</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is a followup to a previous post, which described how it was possible to upload arbitrary base64 data to KA as a program image (“thumbnail” or “screenshot”).]]></summary></entry><entry><title type="html">A Python script to perform the screenshot hack</title><link href="http://ka-hearth.learnerpages.com/posts/script-to-upload-screenshots" rel="alternate" type="text/html" title="A Python script to perform the screenshot hack" /><published>2020-07-24T00:00:00+00:00</published><updated>2020-07-24T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/script-to-upload-screenshots</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/script-to-upload-screenshots"><![CDATA[<p>I wrote a small Python script to perform the screenshot hack. I realize I still haven’t written a post about the hack, but I won’t at this time. I merely wanted a place to share this code.</p>

<p>It is a Python 3 script, requiring no dependencies. This is only useful to you if you know how to run Python code from a command line.</p>

<p>It also requires you to extract the full cookie string from Khan Academy. <code class="language-plaintext highlighter-rouge">document.cookie</code> doesn’t include HttpOnly cookies like <code class="language-plaintext highlighter-rouge">KAID</code>, which are important. I recommend finding a request in the network tab of the browser debug tools, and copying the text of the Cookie header.</p>

<p>It will look for a file titled <code class="language-plaintext highlighter-rouge">image.png</code> or <code class="language-plaintext highlighter-rouge">image.gif</code> in the same directory.</p>

<p>It will look for a <code class="language-plaintext highlighter-rouge">cookie.txt</code> file to extract cookies from, and will prompt you to paste a cookie at the command line if it doesn’t exist.</p>

<p>It will prompt for the ID of the program on which to perform the hack.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c1">#!/usr/bin/env python3
</span>
<span class="c1">### Copyright Matthias Saihttam 2020
### The following script is provided with no warranty, express or implied. It may break at any time, and I do not provide support for it.
</span>
<span class="kn">import</span> <span class="nn">urllib.request</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">import</span> <span class="nn">getopt</span><span class="p">,</span> <span class="n">sys</span>

<span class="n">opts</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="n">getopt</span><span class="p">.</span><span class="n">getopt</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="s">""</span><span class="p">,</span> <span class="p">[</span><span class="s">"debug"</span><span class="p">])</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">debug</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">"--debug"</span>
    <span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"debug on"</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">IndexError</span><span class="p">:</span>
    <span class="n">debug</span> <span class="o">=</span> <span class="bp">False</span>

<span class="c1"># Load an image
</span><span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"image.png"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">b64_string</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()).</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
        <span class="n">image_type</span> <span class="o">=</span> <span class="s">"image/png"</span> <span class="c1"># This is ignored by KA, but I set it to be nice.
</span><span class="k">except</span> <span class="nb">IOError</span><span class="p">:</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"image.gif"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">b64_string</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()).</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
        <span class="n">image_type</span> <span class="o">=</span> <span class="s">"image/gif"</span>

<span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"cookie.txt"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">cookie_str</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">except</span> <span class="nb">IOError</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Cookie string for the author of the program: "</span><span class="p">)</span>
    <span class="n">cookie_str</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>

<span class="n">cookie_data</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">([[</span><span class="n">m</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">e</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"="</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">cookie_str</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">";"</span><span class="p">)])</span>
<span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">cookie_data</span><span class="p">)</span>

<span class="c1"># Prompt for program ID
</span><span class="n">program_id</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Program id? "</span><span class="p">)</span>

<span class="c1"># Look up the program
</span><span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">Request</span><span class="p">(</span><span class="sa">f</span><span class="s">"https://www.khanacademy.org/api/internal/scratchpads/</span><span class="si">{</span><span class="n">program_id</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>  <span class="n">method</span><span class="o">=</span><span class="s">"GET"</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">{</span>
    <span class="s">"X-KA-FKEY"</span><span class="p">:</span> <span class="n">cookie_data</span><span class="p">[</span><span class="s">"fkey"</span><span class="p">],</span>
    <span class="s">"Cookie"</span><span class="p">:</span> <span class="n">cookie_str</span>
<span class="p">})</span>

<span class="k">with</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
    <span class="n">program_data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">read</span><span class="p">())</span>

<span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">image_type</span><span class="p">)</span>

<span class="c1"># Upload the image
</span><span class="n">request_data</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"title"</span><span class="p">:</span> <span class="n">program_data</span><span class="p">[</span><span class="s">"title"</span><span class="p">],</span>
    <span class="s">"revision"</span><span class="p">:</span> <span class="p">{</span>
        <span class="s">"code"</span><span class="p">:</span> <span class="n">program_data</span><span class="p">[</span><span class="s">"revision"</span><span class="p">][</span><span class="s">"code"</span><span class="p">],</span>
        <span class="s">"image_url"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"data:</span><span class="si">{</span><span class="n">image_type</span><span class="si">}</span><span class="s">;base64,</span><span class="si">{</span><span class="n">b64_string</span><span class="si">}</span><span class="s">"</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"X-KA-FKEY"</span><span class="p">:</span> <span class="n">cookie_data</span><span class="p">[</span><span class="s">"fkey"</span><span class="p">],</span>
    <span class="s">"Cookie"</span><span class="p">:</span> <span class="n">cookie_str</span><span class="p">,</span>
    <span class="s">"Content-Type"</span><span class="p">:</span> <span class="s">"application/json"</span>
<span class="p">}</span>

<span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">Request</span><span class="p">(</span>
    <span class="sa">f</span><span class="s">"https://www.khanacademy.org/api/internal/scratchpads/</span><span class="si">{</span><span class="n">program_id</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
    <span class="n">method</span><span class="o">=</span><span class="s">"PUT"</span><span class="p">,</span>
    <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span>
    <span class="n">data</span><span class="o">=</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">request_data</span><span class="p">).</span><span class="n">encode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">res</span><span class="p">:</span>
        <span class="n">res_text</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">res</span><span class="p">.</span><span class="n">status</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">"Success! Screenshot has been uploaded. It's located at:"</span><span class="p">)</span>
            <span class="k">print</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">res_text</span><span class="p">)[</span><span class="s">"imageUrl"</span><span class="p">])</span>
        <span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">status</span><span class="p">)</span>
            <span class="k">print</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">res_text</span><span class="p">),</span> <span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">))</span>
            <span class="k">print</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">info</span><span class="p">())</span>
<span class="k">except</span> <span class="n">urllib</span><span class="p">.</span><span class="n">error</span><span class="p">.</span><span class="n">HTTPError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Uploading failed!"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">read</span><span class="p">())</span>
    <span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">code</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">info</span><span class="p">())</span>
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[I wrote a small Python script to perform the screenshot hack. I realize I still haven’t written a post about the hack, but I won’t at this time. I merely wanted a place to share this code.]]></summary></entry><entry><title type="html">Child account status is now checked through in the API</title><link href="http://ka-hearth.learnerpages.com/posts/child-account-security-changes" rel="alternate" type="text/html" title="Child account status is now checked through in the API" /><published>2020-06-18T00:00:00+00:00</published><updated>2020-06-18T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/child-account-security-changes</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/child-account-security-changes"><![CDATA[<p>Child accounts on KA can perform limited actions, like they cannot comment on programs. Previously, this was only checked on the client side, and by running some code, it was trivial to allow a child account to comment like a normal user.</p>

<p>Following a Hacker1 report I made in February of 2019 which mentioned this issue, KA has notified me that it has now been fixed. And indeed in my test I was met with a 401 Unauthorized error when attempting to comment while logged to a child account.</p>

<p>It’s good to see that KA is taking the time to fix backend API issues in the move to graphQL.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Child accounts on KA can perform limited actions, like they cannot comment on programs. Previously, this was only checked on the client side, and by running some code, it was trivial to allow a child account to comment like a normal user.]]></summary></entry><entry><title type="html">OurJSEditor (v1.0.0)</title><link href="http://ka-hearth.learnerpages.com/posts/launching-ourjseditor" rel="alternate" type="text/html" title="OurJSEditor (v1.0.0)" /><published>2019-12-31T00:00:00+00:00</published><updated>2019-12-31T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/launching-ourjseditor</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/launching-ourjseditor"><![CDATA[<p>A project I’ve been working on for the past 3 years now, OurJSEditor, is entering the second stage of its life. Version 1.0.0 of this website launches today, Dec 31, 2019. It aims to replicate and extend the community features from the computing section of KA. In particular:</p>
<ol>
  <li>Improve on KA’s community management. At least 3 of the 8 current Challenge Council members have been banned from the website at some point. KA continues to tighten moderation and stifle conversation, recently by disallowing links.</li>
  <li>Improve on the live editor. The live editor has not received new features or even bug fixes in years. Processing.js is archived. It’s very difficult to write a large-scale game or modern ES6 Javascript. OurJSEditor has native editor settings, support for ES6, and is flexible, allowing anything from Markdown to P5.js.</li>
  <li>Improve on KA’s website. OurJSEditor is designed to be lightweight, with the home page loading 34kb, compared to KA’s 1,200kb (113kb vs. 7,676kb total). And it’s entirely open source.</li>
  <li>Other countless features, like the ability to subscribe to a user natively. And as OJSE is in active development, it will only get better.</li>
</ol>

<p>OurJSEditor was originally founded Feb. 13th, 2017, after Khan Academy shut down the live editor to community contributions, and rudely closed all open pull requests. A small group of KA members bet that we could make a website that matched KA’s editor, using <em>only</em> community contributions. I took that project and ran with it, paying for server hosting costs and doing most all of the development. However, the entire website’s code remains open source (<a href="https://github.com/OurJSEditor/OurJSEditor">Github</a>), and contributions will always be welcome.</p>

<p>If this sounds interesting to you, I encourage you to head over to <a href="https://ourjseditor.com">OurJSEditor.com</a> and checkout some of the cool programs people there have been making. You can make an account to vote or comment on programs you like. And then try making a program yourself.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A project I’ve been working on for the past 3 years now, OurJSEditor, is entering the second stage of its life. Version 1.0.0 of this website launches today, Dec 31, 2019. It aims to replicate and extend the community features from the computing section of KA. In particular: Improve on KA’s community management. At least 3 of the 8 current Challenge Council members have been banned from the website at some point. KA continues to tighten moderation and stifle conversation, recently by disallowing links. Improve on the live editor. The live editor has not received new features or even bug fixes in years. Processing.js is archived. It’s very difficult to write a large-scale game or modern ES6 Javascript. OurJSEditor has native editor settings, support for ES6, and is flexible, allowing anything from Markdown to P5.js. Improve on KA’s website. OurJSEditor is designed to be lightweight, with the home page loading 34kb, compared to KA’s 1,200kb (113kb vs. 7,676kb total). And it’s entirely open source. Other countless features, like the ability to subscribe to a user natively. And as OJSE is in active development, it will only get better.]]></summary></entry><entry><title type="html">Leaving the KA Challenge Council</title><link href="http://ka-hearth.learnerpages.com/posts/leaving-challenge-council" rel="alternate" type="text/html" title="Leaving the KA Challenge Council" /><published>2019-12-31T00:00:00+00:00</published><updated>2019-12-31T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/leaving-challenge-council</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/leaving-challenge-council"><![CDATA[<p>Unfortunately, my time on the Challenge Council has come to an end. My daily use of Khan Academy has declined since I joined the council 2 years ago. And recently I haven’t been particularly active on the Challenge Council.</p>

<p>As I step away from KA and the Challenge Council, I will be focusing instead on other projects, like <strong><a href="launching-ourjseditor">launching OurJSEditor</a></strong>. I am not leaving the community, and will continue to use KA, maintain the KA Extension, and hopefully enter a contest or make more programs on KA.</p>

<p>The Challenge Council is left in capable hands, and I look forward to seeing the contest prompts for next year.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Unfortunately, my time on the Challenge Council has come to an end. My daily use of Khan Academy has declined since I joined the council 2 years ago. And recently I haven’t been particularly active on the Challenge Council.]]></summary></entry><entry><title type="html">KA Public API Deprecated</title><link href="http://ka-hearth.learnerpages.com/posts/KA-API-Depreciation" rel="alternate" type="text/html" title="KA Public API Deprecated" /><published>2019-11-06T00:00:00+00:00</published><updated>2019-11-06T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/KA-API-Depreciation</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/KA-API-Depreciation"><![CDATA[<p>Yesterday, KA <a href="https://github.com/Khan/khan-api/commit/f35d8aee5cb4c1fdfc19c3b024b69868cae2286d">updated</a> the Github repository holding documentation for their publicly available API to contain a deprecation notice. It contains a timeline including when various endpoints will be deprecated, which I have included below. These deprecations begin in just 2 months from today, although KA giving some notice is better than none.</p>

<table>
  <thead>
    <tr>
      <th><strong>Endpoints</strong></th>
      <th><strong>When deprecated:</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>/api/v1/badges/*</td>
      <td>January 6, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/badges/*</td>
      <td>January 6, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/user/*</td>
      <td>January 6, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/playlists/*</td>
      <td>July 1, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/topictree</td>
      <td>July 1, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/topics/*</td>
      <td>July 1, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/videos/*</td>
      <td>July 1, 2020</td>
    </tr>
    <tr>
      <td>/api/v1/exercises/*</td>
      <td>July 1, 2020</td>
    </tr>
  </tbody>
</table>

<p>This will definitely break projects like Collingridge’s <a href="https://whatbadgenext.appspot.com/">What Badge Next?</a>, which make use of these endpoints. But what is particularly concerning is that KA has not provided another official API or documentation for an alternative—there’s no way to fix this.</p>

<p>Pamela <a href="https://github.com/Khan/live-editor/pull/720">updated</a> the live-editor to remove one place where a sample program accessed the KA API to get scratchpad data. This feature is relatively unimportant (the KA Extension used it in one place), especially because it’s easy to re-add or use an older version of the live-editor if you need this functionality. However, the API endpoint used here is not a <code class="language-plaintext highlighter-rouge">/api/v1/*</code> endpoint, but rather an Internal API endpoint (<code class="language-plaintext highlighter-rouge">/api/internal/...</code>). KA doesn’t mention these endpoints being deprecated, but they also never officially supported them either. KA is in the process of making a transition towards a GraphQL API backend, and this is likely a part of that transition. However, to my knowledge, there is no way to get program data with GraphQL, and so KA can’t remove the older program endpoints without breaking the functionality of their own website. I think Pamela is being overly aggressive here by removing this internal endpoint from the live-editor.</p>

<p>Given the amount of energy KA has spent on updating the programming section historically, I don’t think they will move the programming section of the website to GraphQL before Jan 6th. I don’t think the internal API will be shut down soon. The best case scenario going forward is that all of these systems continue to work. Projects that interact with KA would then have to choose between the unofficial internal API, the deprecated v1 API, or the undocumented and unofficial GraphQL API.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Yesterday, KA updated the Github repository holding documentation for their publicly available API to contain a deprecation notice. It contains a timeline including when various endpoints will be deprecated, which I have included below. These deprecations begin in just 2 months from today, although KA giving some notice is better than none.]]></summary></entry><entry><title type="html">Profile UI update</title><link href="http://ka-hearth.learnerpages.com/posts/complete-profile-ui-update" rel="alternate" type="text/html" title="Profile UI update" /><published>2019-07-23T00:00:00+00:00</published><updated>2019-07-23T00:00:00+00:00</updated><id>http://ka-hearth.learnerpages.com/posts/complete-profile-ui-update</id><content type="html" xml:base="http://ka-hearth.learnerpages.com/posts/complete-profile-ui-update"><![CDATA[<p>My <a href="profile-ui-update">last post</a> had the URI <code class="language-plaintext highlighter-rouge">profile-ui-update</code>. That post of course described the changes to the top part of the <a href="https://www.khanacademy.org/profile/me">user profile page</a>, and I imagined that was as extreme of an update as we would see from KA for a while. On the contaray, that was just the beginning of a much larger profile re-work KA unvieled earlier today (noticed first by Elijah in Discord).</p>

<p>Notable changes include:</p>
<ul>
  <li>Moving the tabs for different profile sub-pages to the left side of the page, instead of along the top.</li>
  <li>Removing the “Badges” and “Projects” pages from that list.</li>
  <li>Renaming “Profile” to “Learner Home” under the user-name dropdown in the upper right.</li>
</ul>

<p>The area under MY STUFF is personalized. It’s unclear how much flexibilty it has, but it appears that other tabs appear there, in addition to courses, based on your activity.</p>

<p><img src="/assets/images/complete-new-profile.png" alt="" /></p>

<p>Personally, I think that this is a good aesthetic change, it looks cleaner and still includes most of the same content. By far, the concern that has been the most vocalized is that the browse projects page is no longer one-click away from all pages on your profile. It is still possible to get to your projects (or badges) page by clicking “View All” on the widget on the main profile page. I have said that the KA Extension should be able to replace those missing sidebar links.</p>

<p>There also appears to be a bug where the badges display case isn’t editable if you directly navigate to the profile page; only if you cause it load dynamically (e.g. switching to Projects and then back to profile). It’s also worth noting that KA appears to have added a second check for duplicate badges in your display case, patching the KA Extension’s hack. It remains to be seen if it is possible to fix.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[My last post had the URI profile-ui-update. That post of course described the changes to the top part of the user profile page, and I imagined that was as extreme of an update as we would see from KA for a while. On the contaray, that was just the beginning of a much larger profile re-work KA unvieled earlier today (noticed first by Elijah in Discord).]]></summary></entry></feed>