<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>python on S Anand</title>
    <link>https://www.s-anand.net/blog/tag/python/</link>
    <description>Recent content in python on S Anand</description>
    <generator>Hugo -- 0.156.0</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 22 Jun 2026 20:15:22 +0800</lastBuildDate>
    <atom:link href="https://www.s-anand.net/blog/tag/python/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Proving Code Works with Z3</title>
      <link>https://www.s-anand.net/blog/proving-code-works-with-z3/</link>
      <pubDate>Mon, 22 Jun 2026 20:15:22 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/proving-code-works-with-z3/</guid>
      <description>&lt;p&gt;At the &lt;a href=&#34;https://pycon.sg/edusummit.html&#34;&gt;PyCon SG Education Summit&lt;/a&gt; today, &lt;a href=&#34;https://www.linkedin.com/in/melvinzhang/&#34;&gt;Melvin&lt;/a&gt;&amp;rsquo;s lighting talk on &amp;ldquo;Writing Proofs in Python&amp;rdquo; began with a subtle bug in this mid-point calculation (often used in binary search or sort) in languages like Java, C/C++, Go, etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;low&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;high&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;mid&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;low&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;high&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since the integers are fixed-width, this triggers an overflow when &lt;code&gt;low + high&lt;/code&gt; exceeds the maximum integer value.&lt;/p&gt;
&lt;p&gt;Even popular libraries like Pandas &lt;a href=&#34;https://github.com/pandas-dev/pandas/issues/25485&#34;&gt;had this bug until 2019&lt;/a&gt;. In fact, even Python&amp;rsquo;s native &lt;code&gt;list.sort()&lt;/code&gt; had &lt;a href=&#34;https://github.com/python/cpython/issues/67703&#34;&gt;this sort of bug until 2015&lt;/a&gt;! &lt;a href=&#34;https://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/&#34;&gt;Read the details&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;z3-can-find-counterexamples&#34;&gt;Z3 can find counterexamples&lt;/h3&gt;
&lt;p&gt;Melvin showed how to use &lt;a href=&#34;https://github.com/z3prover/z3&#34;&gt;Z3&lt;/a&gt; - a popular theorem prover library - to prove or find errors in code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;z3&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;low&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BitVecs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;low high&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Solver&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;high&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;high&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;mid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;low&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;high&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;# signed 32-bit arithmetic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Find a case where the &amp;#34;obvious&amp;#34; midpoint is wrong&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;low&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Prints something like [high = 2142306236, low = 47120451]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output has found a case where the midpoint is less than &lt;code&gt;low&lt;/code&gt;, which is clearly wrong.&lt;/p&gt;
&lt;!-- https://chatgpt.com/c/6a391927-68a0-83ee-8f8c-b7a8c54a1709 | https://chatgpt.com/share/6a391a41-4d78-83ee-af42-0dac8d8227bc --&gt;
&lt;h3 id=&#34;chatgpt-can-run-z3-to-find-issues&#34;&gt;ChatGPT can run Z3 to find issues&lt;/h3&gt;
&lt;p&gt;I had a &lt;a href=&#34;https://chatgpt.com/share/6a391ae5-1930-83e8-b357-cbef241de71c&#34;&gt;conversation with ChatGPT&lt;/a&gt; that ran like this: &lt;!-- https://chatgpt.com/c/6a38c544-f850-83ee-b6f1-4a7ccfb9ba00 --&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: Prove something with Z3 and teach me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: OK. Here&amp;rsquo;s how you find the midpoint overflow error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: How can Z3 help me?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: Find edge cases, counter-examples, refactor safely, validate rules, write tests, model workflows, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: Any alternatives to Z3?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: Z3 is best, but consider &lt;a href=&#34;https://dafny.org/&#34;&gt;Dafny&lt;/a&gt; for production code, &lt;a href=&#34;https://alloytools.org/&#34;&gt;Alloy&lt;/a&gt; for data, &lt;a href=&#34;https://lamport.azurewebsites.net/tla/tla.html&#34;&gt;TLA+&lt;/a&gt; for workflows, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: Any popular Python tutorials have Z3-detectable bugs?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: Several! GeeksforGeeks&amp;rsquo; Interpolation search hits a ZeroDivisionError; in Programiz&amp;rsquo; Bucket sort, the bucket index can exceed the number of buckets, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: Find production Python code with Z3-detectable bugs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: Sure! There are plenty of &lt;code&gt;ZeroDivisionError&lt;/code&gt;s in networkx, rich, seaborn, xarray, plotly, matplotlib, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: Find real errors - not nitpicky ones!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: OK, xarray, branca, mizani, shap, matplotlib, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Me&lt;/strong&gt;: If these don&amp;rsquo;t have existing bugs filed, write an issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;: Sure! Here they are.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;some-issues-are-not-bad&#34;&gt;Some issues are not bad&lt;/h3&gt;
&lt;p&gt;One issue was quite relevant. I raised &lt;a href=&#34;https://github.com/python-visualization/branca/issues/222&#34;&gt;#222 on python-visualization/branca&lt;/a&gt; which roughly says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;LinearColormap([&amp;quot;red&amp;quot;, &amp;quot;blue&amp;quot;], vmin=0, vmax=1).to_step(n=1)&lt;/code&gt; fails. But there are times when I just have one bucket/class to display, so shouldn&amp;rsquo;t this work?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another looked pretty relevant, too. I raised &lt;a href=&#34;https://github.com/pydata/xarray/issues/11397&#34;&gt;#11397 on pydata/xarray&lt;/a&gt; which roughly says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;np.linspace(0, 1, num=1)&lt;/code&gt; works. Shouldn&amp;rsquo;t &lt;code&gt;RangeIndex.linspace(0, 1, num=1, dim=&amp;quot;x&amp;quot;)&lt;/code&gt; do the same?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;but-not-all-issues-are-worth-reporting&#34;&gt;But not all issues are worth reporting&lt;/h3&gt;
&lt;p&gt;Maybe not. The &lt;a href=&#34;https://github.com/python-visualization/branca/issues/222&#34;&gt;branca LinearColorMap&lt;/a&gt; issue feels more real to me than the &lt;a href=&#34;https://github.com/pydata/xarray/issues/11397&#34;&gt;xarray RangeIndex.linspace&lt;/a&gt; one - maybe because I&amp;rsquo;ve faced it.&lt;/p&gt;
&lt;p&gt;Maybe we could do this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When &lt;strong&gt;you&lt;/strong&gt; find a bug, use Gen AI to report it. It&amp;rsquo;s a real need.&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;Gen AI&lt;/strong&gt; finds a bug, report it only if you&amp;rsquo;ll really need it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;still-z3--chatgpt-is-quite-effective&#34;&gt;Still, Z3 + ChatGPT is quite effective&lt;/h3&gt;
&lt;p&gt;When testing your own code, the ability to prove it correct or find counterexamples is very powerful.&lt;/p&gt;
&lt;p&gt;Since you don&amp;rsquo;t need to know how to use these tools (AI does it for you), the cost of using these is very low.&lt;/p&gt;
&lt;p&gt;This adds a useful layer of defense against vibe coded technical debt.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;UPDATE: 25 Jun 2026&lt;/strong&gt;: The &lt;a href=&#34;https://github.com/pydata/xarray/pull/11401&#34;&gt;pull request&lt;/a&gt; I submitted to fix it was merged. But this led to a fascinating rabbit hole involving the &lt;a href=&#34;https://www.s-anand.net/blog/bounty-hunting-agent-ecosystem/&#34;&gt;Bounty-Hunting Agent Ecosystem&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Sambar Styles</title>
      <link>https://www.s-anand.net/blog/sambar-styles/</link>
      <pubDate>Sun, 26 Apr 2026 20:21:51 -0400</pubDate>
      <guid>https://www.s-anand.net/blog/sambar-styles/</guid>
      <description>&lt;p&gt;My wife&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/Sambar_(dish)&#34;&gt;sambar&lt;/a&gt; tastes different from my mother&amp;rsquo;s. And mine, too. When I cooked as a bachelor, my neighbour would pop by, taste the sambar, and exclaim, &amp;ldquo;&lt;a href=&#34;https://en.wikipedia.org/wiki/Rasam_(dish)&#34;&gt;Rasam&lt;/a&gt; super!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/posts/surbhi-bhatia_looked-at-43-sambar-recipes-across-five-south-share-7452601712604811264-b_6o/&#34;&gt;Surbhi&amp;rsquo;s Day 5 of the 30-day challenge was about Sambar&lt;/a&gt; which inspired me to take &lt;a href=&#34;https://docs.google.com/spreadsheets/d/1l7Xu3j4tPHMiouh_BcT6pWu4OMhFWM5eKsKT_dntGRs/edit?gid=710450701#gid=710450701&#34;&gt;her dataset&lt;/a&gt; and create a decision tree for which state a sambar recipe is from based on its ingredients.&lt;/p&gt;
&lt;!-- https://chatgpt.com/c/69ee8bca-cca8-83ea-bf04-600d49e49ba4 --&gt;
&lt;p&gt;&lt;a href=&#34;https://chatgpt.com/share/69eeac30-d330-83ea-8632-1e37e0a4191a&#34;&gt;ChatGPT&lt;/a&gt; started with 68 recipes and built a tree at &lt;strong&gt;41% accuracy&lt;/strong&gt;. As we added more recipes:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Recipes&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Accuracy&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;68&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;41%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;293&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;42%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;361&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;55%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;406&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;54%&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;hellip; the accuracy wasn&amp;rsquo;t improving all that much.&lt;/p&gt;
&lt;p&gt;Here is the classifier script: &lt;a href=&#34;https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_fftree.py&#34;&gt;&lt;code&gt;sambar_fftree.py&lt;/code&gt;&lt;/a&gt;. You can run it via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_fftree.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But a ingredients are &lt;strong&gt;snipers&lt;/strong&gt;: rare, precise, devastating.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kokum or goda masala -&amp;gt; Maharashtra.&lt;/strong&gt; 32 for 32 in one run. Perfect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sesame/gingelly oil -&amp;gt; Tamil Nadu.&lt;/strong&gt; 28 for 32. Strong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coconut oil + shallots -&amp;gt; Kerala.&lt;/strong&gt; 22 for 29.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Moong dal + no mustard seeds -&amp;gt; Andhra.&lt;/strong&gt; 31 for 36. Better than garlic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Byadagi chillies -&amp;gt; Karnataka.&lt;/strong&gt; 6 for 7. Tiny sample, but clean.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But without some of these strong signals, the sambar could be from &lt;em&gt;anywhere&lt;/em&gt;. Better to abstain when unsure.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-04-26-sambar-styles.avif&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here is the classifier that allows abstentions: &lt;a href=&#34;https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_fftree_abstension.py&#34;&gt;&lt;code&gt;sambar_fftree_abstain.py&lt;/code&gt;&lt;/a&gt; and the &lt;a href=&#34;https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_recipe_dataset.csv&#34;&gt;dataset I used&lt;/a&gt;. You can run it via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Download the files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_recipe_dataset.csv &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_fftree.py &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     https://files.s-anand.net/blog/2026-04-26-sambar-styles/sambar_fftree_abstension.py
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Run the script with the data I used&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run sambar_fftree_abstension.py --no-download
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only about a third of recipes have a clear signal.&lt;/p&gt;
&lt;p&gt;Incidentally, &lt;strong&gt;Coconut&lt;/strong&gt; alone is not a Kerala signal. It&amp;rsquo;s more &amp;ldquo;west coast&amp;rdquo;.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;State&lt;/th&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Uses grated coconut&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Karnataka&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;60%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Kerala&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;58%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Maharashtra&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;32%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Tamil Nadu&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;24%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Andhra&lt;/td&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;14%&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Garlic&lt;/strong&gt; is not Andhra either. In one run, &lt;code&gt;garlic + no coconut&lt;/code&gt; was a 50-50 split between Andhra and Maharashtra.&lt;/p&gt;
&lt;p&gt;Rather than states, it&amp;rsquo;s better to think of styles.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Style&lt;/th&gt;
          &lt;th&gt;Ingredients&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Amti&lt;/td&gt;
          &lt;td&gt;kokum, goda masala&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Tamil tiffin-sambar&lt;/td&gt;
          &lt;td&gt;sesame oil, sambar powder, tamarind&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Kerala coconut-tempering&lt;/td&gt;
          &lt;td&gt;coconut oil, shallots&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Andhra pappu/charu&lt;/td&gt;
          &lt;td&gt;moong dal, less mustard&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Karnataka sweet-roasted&lt;/td&gt;
          &lt;td&gt;byadagi, jaggery, coconut&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Maharashtra is easy to identify if it&amp;rsquo;s &lt;em&gt;amti&lt;/em&gt; style. Without kokum or goda masala, it&amp;rsquo;s generic sambar.&lt;/p&gt;
&lt;p&gt;Tamil Nadu sambar has two distinctive styles: sesame/gingelly oil; or sambar powder + tamarind.&lt;/p&gt;
&lt;p&gt;With all of this, we could identify the state only about one-third of the time based on ~2,000 recipes. But we &lt;em&gt;can&lt;/em&gt; identify the distinctive styles from their ingredients, when it&amp;rsquo;s present.&lt;/p&gt;
&lt;p&gt;Like my bachelor-days sambar, which was missing dal. (No one told me sambar needs dal.) And my neighbour could identify it instantly. As rasam.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 18 Jan 2026</title>
      <link>https://www.s-anand.net/blog/things-i-learned-18-jan-2026/</link>
      <pubDate>Sun, 18 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-18-jan-2026/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pypi.org/project/vulture&#34;&gt;Vulture&lt;/a&gt; is a neat library that funds unused Python code. &lt;code&gt;uvx vulture script.py&lt;/code&gt; works fairly well, out-of-box. This helps when cleaning up AI-edited scripts that often have left-over code or imports.&lt;/li&gt;
&lt;li&gt;One of the lightest alternatives to Google Analytics is &lt;a href=&#34;https://goatcounter.com/&#34;&gt;GoatCounter&lt;/a&gt;. If you just want page views, referrers, browsers, OSes, countries, and devices, it&amp;rsquo;s great. It&amp;rsquo;s privacy-friendly (no cookies), open source, easy to self-host, free for small sites, and the data is exportable.&lt;/li&gt;
&lt;li&gt;The number of countries that allow visa-free entries to Indian passports is gently growing in Asia (Kazakhstan, Thailand, Sri Lanka, Malaysia, Iran, and Philippines).&lt;/li&gt;
&lt;li&gt;Lessons from performance books. &lt;a href=&#34;https://claude.ai/public/artifacts/cd4074fd-f227-4b77-8366-cdc1c2a6199b&#34;&gt;Claude&lt;/a&gt; &lt;a href=&#34;https://claude.ai/chat/ee0c099e-ed4c-46d1-9dcd-111010334375&#34;&gt;#&lt;/a&gt; &lt;a href=&#34;https://gemini.google.com/u/2/app/f6756cca3a258d92&#34;&gt;#&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Summary: In early days, explore, sample. Then narrow based on interest &amp;amp; fit. Practice hard and persist.&lt;/li&gt;
&lt;li&gt;⭐⭐⭐⭐ Range (David Epstein): In changing environments (rules shift, feedback is noisy/late), sample broadly, i.e. generalize. &lt;a href=&#34;https://chatgpt.com/share/68902bbf-bf58-800c-b6b5-9ae787fa9c26&#34;&gt;Specialization vs generalization&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Nobel laureates have more hobbies. Olympic athletes have less. Shift nurses have same hobbies as non-shift workers. &lt;a href=&#34;https://chatgpt.com/share/6894691e-f530-800c-b594-824814559dd2&#34;&gt;Hobbies help expertise in some areas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rewarding ONLY what succeeds locks behavior, halts exploration. Vary / delay incentives. Reward AFTER figuring out what works. &lt;a href=&#34;https://chatgpt.com/share/68946330-d714-800c-b845-ca86df7729b6&#34;&gt;Reinforcement and rewards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Maybe &amp;ldquo;orderly&amp;rdquo; people specialize and creative people generalize? So pick what aligns with personality?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;⭐⭐⭐ Peak (Anders Ericsson &amp;amp; Robert Pool): Compounded practice at the edge of competence, with good immediate feedback, helps 14-26%.
&lt;ul&gt;
&lt;li&gt;But talent (genetics, upbringing, brainpower) differentiates more the expert level.&lt;/li&gt;
&lt;li&gt;Slow, effortful practice (spaced recall, interleaving topics, self-testing) builds lasting knowledge - but looks inefficient and doesn&amp;rsquo;t help with exams. &lt;a href=&#34;https://chatgpt.com/share/689180c7-03a0-800c-a5d4-5a455429e97f&#34;&gt;Learning and long-term retention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Easy&amp;rdquo; 10K hours don&amp;rsquo;t help.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;⭐⭐ Grit (Angela Duckworth): predicts roughly the same as conscientiousness (18%). It predicts success in stable paths moderately (but brainpower, etc. matter too).
&lt;ul&gt;
&lt;li&gt;But premature grit hurts. Quit if it helps.&lt;/li&gt;
&lt;li&gt;But environment can defeat grit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lessons from attention economy books. &lt;a href=&#34;https://claude.ai/public/artifacts/ce1ce275-1d79-443b-bfd6-9a6f2a3ddfbe&#34;&gt;Claude&lt;/a&gt; &lt;a href=&#34;https://claude.ai/chat/1fdda7c7-9d70-47d9-9a4c-7e54c16091da&#34;&gt;#&lt;/a&gt; &lt;a href=&#34;https://gemini.google.com/u/2/app/6cbffbe94a9a4e2c&#34;&gt;#&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;The attention economy is real. It is &lt;em&gt;designed&lt;/em&gt; to capture our mind, and it is winning.&lt;/li&gt;
&lt;li&gt;Distractions hurt &lt;em&gt;MUCH&lt;/em&gt; more than we think. Batching, focus time helps.&lt;/li&gt;
&lt;li&gt;Privilege helps. The rich have more control over these than the poor do.&lt;/li&gt;
&lt;li&gt;⭐⭐⭐⭐ Deep Work (Cal Newport, 2016) and ⭐⭐⭐ Digital Minimalism (Cal Newport, 2019): control the tools. &lt;strong&gt;Focus time, digital detox, embrace boredom&lt;/strong&gt;. This helps - when you can afford to.&lt;/li&gt;
&lt;li&gt;⭐⭐⭐ Indistractable (Nir Eyal): control yourself. The problem is internal (also true), so &lt;strong&gt;build habits&lt;/strong&gt;, since willpower depletes (hm&amp;hellip; not really).&lt;/li&gt;
&lt;li&gt;⭐⭐⭐ How to Do Nothing (Jenny Odell, 2019): reject. &lt;strong&gt;Embrace boredom&lt;/strong&gt; as resistance. This helps - when you can afford to.&lt;/li&gt;
&lt;li&gt;⭐⭐ Stolen Focus (Johann Hari, 2022): regulate &amp;amp; rebel. The problem is systemic and external (also true). &lt;strong&gt;Reclaim your interface&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;BTW: Goldfish have &lt;em&gt;excellent&lt;/em&gt; attention spans and memory :-)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lessons from trauma books. &lt;a href=&#34;https://claude.ai/public/artifacts/b3e2120b-d65f-4beb-94d0-7e8a710bafb9&#34;&gt;Claude&lt;/a&gt; &lt;a href=&#34;https://claude.ai/chat/d33b75b9-a4ed-4972-8f31-c1e34b00b194&#34;&gt;#&lt;/a&gt; &lt;a href=&#34;https://gemini.google.com/u/2/app/ca92bd9b7c2c2549&#34;&gt;#&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;⭐⭐⭐ The Body Keeps the Score (Bessel van der Kolk, 2014): trauma recall shuts down the speech area. Eye movement desensitization (EMDR) helps. So does CBT, despite what the book says. But does yoga (only a little) or neurofeedback (too little data)?&lt;/li&gt;
&lt;li&gt;⭐⭐⭐ What Happened to You? (Bruce Perry &amp;amp; Oprah Winfrey, 2021): calming people down before talking. Strong connections help more than a therapist.&lt;/li&gt;
&lt;li&gt;⭐⭐ The Myth of Normal (Gabor Maté, 2022): trauma causes cancer (no), autoimmunity (partly), ALS (?), etc.&lt;/li&gt;
&lt;li&gt;⭐ It Didn’t Start with You (Mark Wolynn, 2016): maybe anxiety is epigenetic and heriditary? Unproven. &lt;a href=&#34;https://en.wikipedia.org/wiki/Family_Constellations&#34;&gt;Family Constellation Therapy&lt;/a&gt; is wrong&lt;/li&gt;
&lt;li&gt;⭐⭐ My Grandmother’s Hands (Resmaa Menakem, 2017): maybe racism is a somatic (body) response to generational (epigenetic) trauma? Too little data&lt;/li&gt;
&lt;li&gt;⭐⭐ No Bad Parts (Richard Schwartz): maybe we&amp;rsquo;re not one person but a collection of parts, and interviewing family systems (IFS) helps? Unclear&lt;/li&gt;
&lt;li&gt;⭐⭐⭐ Maybe You Should Talk to Someone (Lori Gottlieb): our memory is unreliable and therapy is messy. Connection &amp;amp; compassion help&lt;/li&gt;
&lt;li&gt;Most of these are based on the contested Polyvagal Theory: the nervous system scans for danger before the mind can process it. But the specific claims of the theory are wrong and it makes no other falsifiable claims.
&lt;ul&gt;
&lt;li&gt;The nervous system has hierarchical responses to threat. 🟢 Not unique to PVT&lt;/li&gt;
&lt;li&gt;Social connection regulates physiology. 🟢 Not unique to PVT&lt;/li&gt;
&lt;li&gt;Unconscious threat detection (neuroception). 🟡 Weak evidence&lt;/li&gt;
&lt;li&gt;Mamellian brain (ventral vagal system) is uniquely mammalian. 🔴 Lungfish have it&lt;/li&gt;
&lt;li&gt;Reptilian brain (dorsal vagal) &amp;ldquo;shutdown&amp;rdquo; causes dissociation. 🔴 No evidence&lt;/li&gt;
&lt;li&gt;RSA directly measures vagal tone. 🔴 Contested&lt;/li&gt;
&lt;li&gt;Reptiles are &amp;ldquo;asocial&amp;rdquo;. 🔴 Wrong&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trauma causes &lt;em&gt;body&lt;/em&gt; changes too. It&amp;rsquo;s not just the mind.&lt;/li&gt;
&lt;li&gt;Childhood trauma persists.&lt;/li&gt;
&lt;li&gt;Relationships (connection &amp;amp; compassion) help more than therapy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What constitutes tax residency in India? For an Indian citizen, as I understand it (after 2 hours of research):
&lt;ul&gt;
&lt;li&gt;If you were in India &amp;gt;= 182 days: Resident*&lt;/li&gt;
&lt;li&gt;Else, if you left India &lt;em&gt;this year&lt;/em&gt; for employment: NRI.&lt;/li&gt;
&lt;li&gt;Else, if you are an Indian Citizen living abroad (visiting or not):
&lt;ul&gt;
&lt;li&gt;If Indian Income &amp;lt;= ₹15 Lakhs: NRI.&lt;/li&gt;
&lt;li&gt;Else if you were in India &amp;gt;= 120 days AND &amp;gt;= 365 days in the last 4 years: RNOR.&lt;/li&gt;
&lt;li&gt;Else if you are not liable to tax in any other country: RNOR.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Else, if you left India for non-employment (students, tourism) and were in India &amp;gt;= 60 days AND &amp;gt;= 365 days in the last 4 years: Resident*&lt;/li&gt;
&lt;li&gt;Else: NRI.&lt;/li&gt;
&lt;li&gt;If you ended up as a Resident*
&lt;ul&gt;
&lt;li&gt;If you were NRI in 9 of the last 10 years OR in India &amp;lt;= 729 days in the last 7 years: RNOR&lt;/li&gt;
&lt;li&gt;Else: ROR (Resident &amp;amp; Ordinarily Resident).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For all practical purposes, RNOR is like an NRI. You pay tax only on Indian income, not global income. It&amp;rsquo;s like a transition status for returning NRIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ctrl.blog/entry/webp-avif-comparison.html&#34;&gt;AVIF compresses better than WebP&lt;/a&gt; and &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types#avif_image&#34;&gt;may be the &amp;ldquo;next big thing&amp;rdquo;&lt;/a&gt;. I will be switching for all future images. &lt;a href=&#34;https://squoosh.app/&#34;&gt;Squoosh&lt;/a&gt; remains my choice of compressor and Ezgif&amp;rsquo;s &lt;a href=&#34;https://ezgif.com/avif-maker&#34;&gt;AVIF maker&lt;/a&gt; and &lt;a href=&#34;https://ezgif.com/gif-to-avif&#34;&gt;GIF to AVIF&lt;/a&gt; are handy.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Finding open source bugs with Ty</title>
      <link>https://www.s-anand.net/blog/finding-open-source-bugs-with-ty/</link>
      <pubDate>Sun, 11 Jan 2026 11:55:19 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/finding-open-source-bugs-with-ty/</guid>
      <description>&lt;p&gt;Astral released &lt;a href=&#34;https://astral.sh/blog/ty&#34;&gt;Ty (Beta)&lt;/a&gt; last month.&lt;/p&gt;
&lt;p&gt;As a prototyper, I don&amp;rsquo;t type check much - it slows me down. But the few apps I shipped to production had bugs type checking could have caught. Plus, LLMs don&amp;rsquo;t get slowed by type checking.&lt;/p&gt;
&lt;p&gt;So I decided to check if Ty can spot &lt;em&gt;real&lt;/em&gt; bugs in &lt;em&gt;real&lt;/em&gt; code.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://chatgpt.com/share/69631ff0-c14c-8003-bee2-13f016240cbd&#34;&gt;I asked ChatGPT&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Run &lt;code&gt;ty&lt;/code&gt; (Astral&amp;rsquo;s new type checker) on a few popular Python packages&amp;rsquo; source code, list the errors Ty reports (most of which may be false positives), and identify at least a few that are genuine bugs, not false positives. Write sample code or test case to demonstrate the bug.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t fool yourself into inventing false or borderline bugs. Find genuine bugs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After 25 minutes, ChatGPT reported:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;tqdm.rich&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tqdm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;bar&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tqdm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;total&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# This crashes inside tqdm&amp;#39;s rich integration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;total&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; produces this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TypeError: Progress.reset() missing 1 required positional argument: &amp;#39;task_id&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I verified this locally:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with tqdm python -c &lt;span class=&#34;s1&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;from tqdm.rich import tqdm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;bar = tqdm(total=3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;bar.update(1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;bar.reset(total=3)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-01-11-tqdm-rich-ty-bug.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Yes! Same error.&lt;/p&gt;
&lt;p&gt;But is it really a bug?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.s-anand.net/blog/notes/gemini-tqdm-rich-task-id-bug/&#34;&gt;I asked Gemini&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is this a real tqdm bug?
&lt;ul&gt;
&lt;li&gt;Yes, it is.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Could I submit a pull request? Is tqdm active and reviewing/accepting pull requests - especially for the rich integration?
&lt;ul&gt;
&lt;li&gt;Yes, you should.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Find existing PRs with overlapping functionality. List the closest ones
&lt;ul&gt;
&lt;li&gt;Issue &lt;a href=&#34;https://github.com/tqdm/tqdm/issues/1306&#34;&gt;#1306&lt;/a&gt; and PRs &lt;a href=&#34;https://github.com/tqdm/tqdm/pull/1395&#34;&gt;#1395&lt;/a&gt;, &lt;a href=&#34;https://github.com/tqdm/tqdm/pull/1438&#34;&gt;#1438&lt;/a&gt; are close, but different.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(I checked manually.) &lt;a href=&#34;https://github.com/tqdm/tqdm/issues/1674&#34;&gt;#1674&lt;/a&gt; looks very similar&amp;hellip; is it?
&lt;ul&gt;
&lt;li&gt;No, that&amp;rsquo;s a different bug&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(I wanted to be sure.) What about this issue: &lt;a href=&#34;https://github.com/tqdm/tqdm/issues/1378&#34;&gt;#1378&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Yes, that&amp;rsquo;s an exact duplicate, waiting since 2022. (Stupid LLM!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is the minimal fix?
&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;self._task_id&lt;/code&gt; as the first argument to &lt;code&gt;self._prog.reset(total=total)&lt;/code&gt; in &lt;code&gt;tqdm/rich.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This PR seems to do that: &lt;a href=&#34;https://github.com/tqdm/tqdm/pull/1379&#34;&gt;#1379&lt;/a&gt; doesn&amp;rsquo;t it? Why is it not merged yet?
&lt;ul&gt;
&lt;li&gt;Yes, it was even approved, but not merged. Bump up. Else, submit your own PR.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I &lt;a href=&#34;https://github.com/tqdm/tqdm/pull/1379#issuecomment-3733928734&#34;&gt;bumped it up&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This entire process of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finding a bug&lt;/li&gt;
&lt;li&gt;In a new codebase&lt;/li&gt;
&lt;li&gt;Verifying the bug&lt;/li&gt;
&lt;li&gt;Finding an existing PR&lt;/li&gt;
&lt;li&gt;Bumping it up&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; took 30 min of my time and 30 min of computer time.&lt;/p&gt;
&lt;p&gt;The hardest problem in computer science isn&amp;rsquo;t P-vs-NP or cache invalidation. It&amp;rsquo;s understanding why a human will click a green &amp;lsquo;Merge&amp;rsquo; button.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Get this blog via email on Google Groups</title>
      <link>https://www.s-anand.net/blog/get-this-blog-via-email-on-google-groups/</link>
      <pubDate>Mon, 05 Jan 2026 17:50:35 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/get-this-blog-via-email-on-google-groups/</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: &lt;a href=&#34;https://groups.google.com/g/s-anand&#34;&gt;Join this Google Group&lt;/a&gt; to get my blog updates via email.&lt;/p&gt;
&lt;p&gt;My blog is over 25 years old. At first, people had to visit it to read it. Then I added an RSS feeds. Then email subscriptions. Then via social media, cross-posting on &lt;a href=&#34;https://x.com/sanand0&#34;&gt;Twitter&lt;/a&gt;, now &lt;a href=&#34;https://www.linkedin.com/in/sanand0/&#34;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.s-anand.net/blog/index.xml&#34;&gt;RSS feed&lt;/a&gt; remains. But I feel it&amp;rsquo;s time to bring back email subscriptions. It&amp;rsquo;s the oldest of the technologies, the most robust, and the one I believe will last the longest.&lt;/p&gt;
&lt;p&gt;My blog might last another 25 years. I&amp;rsquo;m willing to bet email will outlast RSS and certainly the social media platforms.&lt;/p&gt;
&lt;p&gt;So, I&amp;rsquo;ve created a &lt;a href=&#34;https://groups.google.com/g/s-anand&#34;&gt;Google Group: &lt;code&gt;s-anand@googlegroups.com&lt;/code&gt;&lt;/a&gt; where I will post new blog entries. You can join the group to get email updates whenever I post something new.&lt;/p&gt;
&lt;p&gt;For now, I will post updates manually. After a few weeks of testing, I&amp;rsquo;ll automate the process.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;PS: I use a &lt;a href=&#34;https://github.com/sanand0/blog/blob/3f9632c742eaec0416b469beb820fcd9c94e8cb3/scripts/htmlemail.py&#34;&gt;&lt;code&gt;htmlemail.py&lt;/code&gt;&lt;/a&gt; script to send blog posts as HTML emails via the GMail API. It was vibe-coded by Claude and taught me a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&#34;https://pypi.org/project/python-frontmatter/&#34;&gt;&lt;code&gt;frontmatter&lt;/code&gt;&lt;/a&gt; package is a clean way to parse YAML frontmatter from markdown files.&lt;/li&gt;
&lt;li&gt;LLMs aren&amp;rsquo;t familiar enough with the &lt;a href=&#34;https://pypi.org/project/markdown2/&#34;&gt;&lt;code&gt;markdown2&lt;/code&gt;&lt;/a&gt; package, which is the new standard for processing Markdown. They prefer &lt;a href=&#34;https://pypi.org/project/Markdown/&#34;&gt;&lt;code&gt;markdown&lt;/code&gt;&lt;/a&gt; instead.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pypi.org/project/premailer/&#34;&gt;&lt;code&gt;premailer&lt;/code&gt;&lt;/a&gt; is a well-maintained package to inline CSS for HTML emails.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pypi.org/project/Pygments/&#34;&gt;&lt;code&gt;pygments&lt;/code&gt;&lt;/a&gt; is the de facto standard to generate CSS for syntax highlighting code blocks.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title></title>
      <link>https://www.s-anand.net/blog/most-repeated-letters/</link>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/most-repeated-letters/</guid>
      <description>&lt;p&gt;While meditating, I realized 75% of &amp;ldquo;LULL&amp;rdquo; is the letter &amp;ldquo;L&amp;rdquo;. (This sort of thing happens a lot when I meditate.)&lt;/p&gt;
&lt;p&gt;MUMMY (60% M) and DADDY (60% D) have lower percentage, but are longer, so maybe get a bonus?&lt;/p&gt;
&lt;p&gt;I asked Claude Code what would top such a list. It picked a dictionary, generated the 333 words with 4+ letters and &amp;gt;50% concentration.&lt;/p&gt;
&lt;p&gt;What did I like best? &amp;ldquo;ASSESSES&amp;rdquo;. 5/8 letters are &amp;ldquo;S&amp;rdquo;. That&amp;rsquo;s nearly two-thirds.&lt;/p&gt;
&lt;p&gt;Then &lt;strong&gt;it wrote an xkcd-style story&lt;/strong&gt;! Here are snippets:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I wrote a Python script to analyze 370,105 English words. Then I questioned my life choices.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;*Does &amp;ldquo;mmmm&amp;rdquo; count? Look, I didn&amp;rsquo;t make the dictionary. I just downloaded it from the internet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Notice something? After length 6, it&amp;rsquo;s just S-words and E-words all the way down. (It&amp;rsquo;s the grammatical duct tape of English)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I didn&amp;rsquo;t analyze Welsh, but I&amp;rsquo;m guessing their L&amp;rsquo;s would be extremely competitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The story &lt;em&gt;way more fun&lt;/em&gt; than the analysis!&lt;/p&gt;
&lt;p&gt;Check it out: &lt;a href=&#34;https://github.com/sanand0/research/tree/main/repeated-letter-words&#34;&gt;https://github.com/sanand0/research/tree/main/repeated-letter-words&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Learning: &lt;strong&gt;Find good styles to copy from&lt;/strong&gt;.
Here&amp;rsquo;s my style catalog: &lt;a href=&#34;https://github.com/sanand0/prompts/blob/main/styles.md&#34;&gt;https://github.com/sanand0/prompts/blob/main/styles.md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2025-11-20-most-repeated-letters-linkedin.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/posts/sanand0_while-meditating-i-realized-75-of-lull-activity-7397862297077125120-cBkG&#34;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 29 Jun 2025</title>
      <link>https://www.s-anand.net/blog/things-i-learned-29-jun-2025/</link>
      <pubDate>Sun, 29 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-29-jun-2025/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;People are great at feedback on what you are doing wrong. They are not so good at telling you how to fix it. They don&amp;rsquo;t know you that well.&amp;rdquo; &lt;a href=&#34;https://amitkaps.com/&#34;&gt;Amit Kapoor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/steveruizok/perfect-cursors&#34;&gt;Perfect Cursors&lt;/a&gt; makes periodic cursor positions animate smoothly by interpolating on a spline**&lt;/li&gt;
&lt;li&gt;CloudFlare &lt;em&gt;and&lt;/em&gt; Vercel now support sandboxes where you can execute code. The price is not so low that we can execute for free in bulk but works well infrequent or batched code execution. &lt;a href=&#34;https://simonwillison.net/2025/Jun/26/sandboxes/&#34;&gt;Simon Willison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Here&amp;rsquo;s how I&amp;rsquo;m using ffmpeg for video recording &amp;amp; editing.
&lt;ul&gt;
&lt;li&gt;To record screen at 5 frames per second, I run an abbreviation &lt;code&gt;screenrecord&lt;/code&gt; which maps to:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Gemini CLI has a generous free tier and uses Bootstrap over Tailwind &lt;a href=&#34;https://bsky.app/profile/simonwillison.net/post/3lsh6mtrw2k2u&#34;&gt;Ref&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;Cloudflare has a native agents SDK that looks good, especially for CloudFlare users. &lt;a href=&#34;https://blog.cloudflare.com/building-agents-with-openai-and-cloudflares-agents-sdk/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;There are several &lt;a href=&#34;https://chatgpt.com/share/685e162e-6c78-800c-8d43-1c5d5367eaa7&#34;&gt;brands with recognizable chart style guides&lt;/a&gt;. It&amp;rsquo;s possible to generate style guides for these from the charts, but applying them via matplotlib is almost #impossible today. &lt;a href=&#34;https://chatgpt.com/share/685e1648-c9fc-800c-b35d-2dd6ed61c934&#34;&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sharkdp/hyperfine&#34;&gt;Hyperfine&lt;/a&gt; is like %timeit for the shell. Written in Rust&lt;/li&gt;
&lt;li&gt;⭐ Vertical AI is a moat against AGI. Specialization reduces hallucinations. Custom workflows and regulations are sticky and defensible. We need to start selling to users, not IT, though. &lt;a href=&#34;https://mtrajan.substack.com/p/vertical-ai-just-got-more-urgent&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When AI automates a task, the bottleneck shifts. AI process re-design is about reworking the process around the new bottleneck, and iterating quickly.
&lt;ul&gt;
&lt;li&gt;With coding, it&amp;rsquo;s testing, reviewing, deploying, use-case identification.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uvx git-smart-squash&lt;/code&gt; re-organizes haphazard commits using LLMs. &lt;a href=&#34;https://github.com/edverma/git-smart-squash&#34;&gt;git-smart-squash&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;GitHub offers a &lt;a href=&#34;https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry&#34;&gt;free Docker container registry&lt;/a&gt;. &lt;a href=&#34;https://til.simonwillison.net/github/container-registry&#34;&gt;Simon Willison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;There are three major areas where humans either are, or will soon be, more necessary than ever: trust, integration and taste &amp;ndash; &lt;a href=&#34;https://www.nytimes.com/2025/06/17/magazine/ai-new-jobs.html&#34;&gt;NYT&lt;/a&gt;. &lt;a href=&#34;https://mvark.blogspot.com/2025/06/this-week-i-learned-week-25-2025.html&#34;&gt;Anil&lt;/a&gt;. To deal with this:
&lt;ul&gt;
&lt;li&gt;Learn things that might grow in importance, like:
&lt;ul&gt;
&lt;li&gt;Data modeling&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Code reviews&lt;/li&gt;
&lt;li&gt;Drawing and 3D modeling&lt;/li&gt;
&lt;li&gt;Narrative storytelling&lt;/li&gt;
&lt;li&gt;Design&lt;/li&gt;
&lt;li&gt;Movie making&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Sceptical fact checking&lt;/li&gt;
&lt;li&gt;Continuous AI auditing e.g. &lt;a href=&#34;https://github.com/githubnext/awesome-continuous-ai&#34;&gt;awesome-continous-ai&lt;/a&gt; or &lt;a href=&#34;https://github.com/anthropic-experimental/automated-auditing&#34;&gt;automated-auditing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Zero knowledge proofs&lt;/li&gt;
&lt;li&gt;Homomorphic encryption&lt;/li&gt;
&lt;li&gt;Privacy-preserving computation&lt;/li&gt;
&lt;li&gt;Fingerprinting and watermarking&lt;/li&gt;
&lt;li&gt;Governance frameworks&lt;/li&gt;
&lt;li&gt;Ethics and AI dilemmas&lt;/li&gt;
&lt;li&gt;Negotiation&lt;/li&gt;
&lt;li&gt;Change management&lt;/li&gt;
&lt;li&gt;Remote working, management, hiring&lt;/li&gt;
&lt;li&gt;Creating attention scarcity&lt;/li&gt;
&lt;li&gt;Local cultures&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Work with people of growing importance
&lt;ul&gt;
&lt;li&gt;People designing products in regulated industries&lt;/li&gt;
&lt;li&gt;Cross domain experts&lt;/li&gt;
&lt;li&gt;Art developers, game makers, designers&lt;/li&gt;
&lt;li&gt;System thinkers. Economists, ecologists, system planners. People who look for second order effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Live in cities that might play a bigger role in the future
&lt;ul&gt;
&lt;li&gt;Cities like Singapore and learn how it builds civics trust, creates digital IDs.&lt;/li&gt;
&lt;li&gt;Cities like Bangalore and Hyderabad and learn how they grow tech talent&lt;/li&gt;
&lt;li&gt;Creative cities like Paris, Seoul, Mexico City, Berlin, etc. on sabbaticals to taste hubs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Try to:
&lt;ul&gt;
&lt;li&gt;Build auditing credentials and IP&lt;/li&gt;
&lt;li&gt;Audit your calendar for what AI can do. Have it interview you&lt;/li&gt;
&lt;li&gt;Practice sceptical fact checking and audit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A clever way to test a library&amp;rsquo;s quality is to have LLMs write code from docs and test it. Failing libraries have flawed code/docs. Improve. &lt;a href=&#34;https://lucumr.pocoo.org/2025/6/17/measuring/&#34;&gt;Ref&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/r-three/common-pile/&#34;&gt;Common Pile&lt;/a&gt; is an 8TB open dataset for LLM training that includes ArXiv, PubMed, StackExchange, GitHub, IRC, Regulations.gov, Patents, UK parliament, books. Easier than scraping.&lt;/li&gt;
&lt;li&gt;A useful way to have reasoning models do deep-research-like work is to have them &amp;ldquo;First, create a plan to solve the problem, clearly listing the objective, approach, and output. Then follow the plan.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://arxiv.org/pdf/2402.09910&#34;&gt;DE-COP&lt;/a&gt; is a method to check if LLMs were trained on private content. GPT-4o was trained on O&amp;rsquo;Reilly books, based on this method. &lt;a href=&#34;https://www.deeplearning.ai/the-batch/issue-303/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LLMs are more persuasive than humans. But repeated exposure reduces the effect. &lt;a href=&#34;https://jack-clark.net/2025/05/26/import-ai-414-superpersuasion-openai-models-avoid-shutdown-weather-prediction-and-ai/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://phoenix.new/&#34;&gt;Phoenix.new&lt;/a&gt; uses live views to publish apps as it codes. The testing framework looks at the screen while it codes and fixes errors. It commits every change&lt;/li&gt;
&lt;li&gt;Anthropic system prompt asking Claude to pursue its goals led to self preservation behavior. &lt;a href=&#34;https://x.com/lefthanddraft/status/1937673283614441685?t=uPejOWJdiL3XR9KSNfJPYQ&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The hungrier I am the better the food tastes. A good reason to eat less quantity and frequency&lt;/li&gt;
&lt;li&gt;You can &lt;a href=&#34;https://www.jsdelivr.com/tools/purge&#34;&gt;purge the jsDelivr cache&lt;/a&gt; manually. Helps if you released a new version of a package and way to purge an alias (e.g. &lt;code&gt;https://cdn.jsdelivr.net/npm/your-package@1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.xconvert.com/compress-webm&#34;&gt;XConvert&lt;/a&gt; is a convenient online app to compress .webm videos. Not great design but fairly good compression.&lt;/li&gt;
&lt;li&gt;You can draw a treemap of import times via &lt;code&gt;python -X importtime app.py &amp;gt; timing.txt&lt;/code&gt; and then paste them at &lt;a href=&#34;https://kmichel.github.io/python-importtime-graph/&#34;&gt;https://kmichel.github.io/python-importtime-graph/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/eoda-dev/py-openlayers&#34;&gt;PyOpenLayers&lt;/a&gt; adds interactive mapping via OpenLayers to Marimo and Jupyter.&lt;/li&gt;
&lt;li&gt;In a &lt;a href=&#34;https://techcrunch.com/podcast/inside-anthropics-ai-ambitions-with-jared-kaplan/&#34;&gt;TechCrunch interview with Jared Kaplan&lt;/a&gt; has was asked if Anthropic is becoming less safety conscious because they released Opus 4 which blackmails. Kaplan replied that they have stronger testing and higher transparency, so they&amp;rsquo;re &lt;em&gt;more&lt;/em&gt; likely to share AI dangers early. Great positioning! Conversations are about perspective change and this nailed it.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://github.com/anthropic-experimental/agentic-misalignment/blob/main/templates/system_prompt_templates.py&#34;&gt;system prompts&lt;/a&gt; for Anthropic misalignment evals are a fascinating read.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/aavetis/ai-pr-watcher&#34;&gt;AI PR Watcher&lt;/a&gt; tracks GitHub pull requests from Codex and other LLMs. Codex is &lt;em&gt;way&lt;/em&gt; ahead of anything else on volume &lt;em&gt;and&lt;/em&gt; success rate. Devin is next on volume, Cursor is next on success rate.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 27 Apr 2025</title>
      <link>https://www.s-anand.net/blog/things-i-learned-27-apr-2025/</link>
      <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-27-apr-2025/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAI&amp;rsquo;s reasoning models are much ahead of other models when multiplying two numbers in their heads. &lt;a href=&#34;https://sanand0.github.io/llmmath/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;⭐ &lt;a href=&#34;https://promptfoo.dev/&#34;&gt;Promptfoo&lt;/a&gt; may be the most mature open source LLM evals tool. &lt;a href=&#34;https://simonwillison.net/2025/Apr/24/exploring-promptfoo/&#34;&gt;Simon Willison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Dyson_sphere&#34;&gt;Dyson Sphere&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lemonslice.com/live&#34;&gt;LemonSlice&lt;/a&gt; showcases real-time audio-video models (avatars) that are close enough to real.&lt;/li&gt;
&lt;li&gt;Notes from &lt;a href=&#34;https://iclr.cc/&#34;&gt;Latent Space ICLR 2025, Singapore&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Daniel: &lt;a href=&#34;https://github.com/menloresearch/ReZero&#34;&gt;Menlo&amp;rsquo;s ReZero&lt;/a&gt;. A model that &lt;em&gt;keeps&lt;/em&gt; searching till it finds the answer.
&lt;ul&gt;
&lt;li&gt;There are multiple search techniques: Multi-step retreival, Iterative retrieval, Query rewriting. Also, reasoning.&lt;/li&gt;
&lt;li&gt;The LLM token generation sequence is normally: &lt;code&gt;&amp;lt;think&amp;gt;, &amp;lt;search&amp;gt;, &amp;lt;answer&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Insight: &amp;ldquo;If we explicitly reward LLMs for retrying after a failed search, they out-perform one-attempt systems.&amp;rdquo; So &lt;code&gt;&amp;lt;think&amp;gt;, &amp;lt;search&amp;gt;, &amp;lt;think&amp;gt;, &amp;lt;search&amp;gt;, &amp;lt;think&amp;gt;, &amp;lt;search&amp;gt;, &amp;lt;answer&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;⭐ Prompt reasoning models, e.g. &amp;ldquo;Keep searching till you find the best answer.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Roger, Nous Research
&lt;ul&gt;
&lt;li&gt;Supervised learning is limited because accuracy is piece-wise linear, i.e. it&amp;rsquo;s broken up. Continuous optimization is meaningless.&lt;/li&gt;
&lt;li&gt;Reinforcement learning works better because rewards can be discrete. (But it converts things back into differentiable loss functions behind the scenes.)
&lt;ul&gt;
&lt;li&gt;Rewards can be good/bad. Single or multi-step. Whatever.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;re in the &amp;ldquo;Era of experience&amp;rdquo;, i.e. models gain experience from the environment themselves.&lt;/li&gt;
&lt;li&gt;⭐ So, we need environments models can learn in. This is the next thing after training data. That needs a standard for environments.&lt;/li&gt;
&lt;li&gt;We&amp;rsquo;d need a model, a trainer, and the environment.&lt;/li&gt;
&lt;li&gt;The environments whatever capabilities. Run code. Browser. A game. &amp;hellip; With an exposed interface&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Eugene Cheah (Featherless.ai)
&lt;ul&gt;
&lt;li&gt;Transformer architectures need n-square GPUs as # of tokens grow. Featherless is exploring an RWKV architecture that scales linearly. THere are other such architectures. Performer, Linformer, Reformer, Hyena.&lt;/li&gt;
&lt;li&gt;Mistral-Nemo-12b-ic is one of the most popular fine-tuned model. It&amp;rsquo;s small enough to run on a server.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Justus Mattern (Prime Intellect)
&lt;ul&gt;
&lt;li&gt;Intellect-2 is a continously learning (RL) model that uses decentralized training on peer-to-peer GPUs.&lt;/li&gt;
&lt;li&gt;Solving problems on bandwidth, verifiable contributions, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ChatGPT Deep Research now also has an O4-Mini version to serve smaller reports. Free users get 0 original + 5 lightweight 5 tasks / month. $20 version gets 10 + 15. $200 version gets 100 + 150. The month begins on first use of Deep Research and runs on a 30 day &amp;ldquo;window&amp;rdquo;. &lt;a href=&#34;https://help.openai.com/en/articles/10500283-deep-research-faq&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;O4-Mini-High is great at going through an under-documented repo and finding things. For example, &lt;a href=&#34;https://chatgpt.com/share/680b3d21-0188-800c-a0bf-8b44a1edd919&#34;&gt;here&amp;rsquo;s how I configured &lt;code&gt;cmdg&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;ChatGPT is my new Jupyter Notebook :-)&lt;/li&gt;
&lt;li&gt;Google announced new AI capabilities at Google Next APAC 2025. &lt;a href=&#34;https://workspace.google.com/blog/product-announcements/new-AI-drives-business-results&#34;&gt;Blog&lt;/a&gt;. Interesting ones are:
&lt;ul&gt;
&lt;li&gt;@Gemini in chat&lt;/li&gt;
&lt;li&gt;Google Meet support for &amp;ldquo;Catch me up&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Google Vids: Create short video clips&lt;/li&gt;
&lt;li&gt;Google Sheets: does better analysis&lt;/li&gt;
&lt;li&gt;Google Slides: image generation&lt;/li&gt;
&lt;li&gt;Google Docs: Create Audio Clips (like NotebookLM in Google Docs)&lt;/li&gt;
&lt;li&gt;Google Docs: &amp;ldquo;Help me refine&amp;rdquo; is better than before&lt;/li&gt;
&lt;li&gt;Google Workspace Flows&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/insanum/gcalcli&#34;&gt;gcalcli&lt;/a&gt; is a convenient way to export Google Calendar. Example: &lt;code&gt;uvx gcalcli agenda --tsv 2025-01-01 2025-01-05&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ThomasHabets/cmdg&#34;&gt;cmdg&lt;/a&gt; is a command line GMail client that I&amp;rsquo;ve now switched to for quick email checks. 80% of my email is spam and this is good enough to scan and delete those. It also avoids running a 200-500 MB tab in the browser that constantly shows me how many unread emails I have.&lt;/li&gt;
&lt;li&gt;From &lt;a href=&#34;https://shows.acast.com/worklife-with-adam-grant/episodes/cancelling-cancel-culture-with-loretta-ross&#34;&gt;Worklife with Adam Grant: Cancelling cancel culture with Loretta Ross&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Lighten up! Fighting Nazis should be fun. It&amp;rsquo;s being a Nazi that sucks. If you&amp;rsquo;re not having fun fighting for hope and joy and human rights, maybe you&amp;rsquo;re doing the fight wrong. We are the ones who should be having fun.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;You can say what you mean. But you don&amp;rsquo;t have to say it mean.&amp;rdquo; There is always a way to put it across better. Refusing to say mean things is about to discover these approaches.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The true mark of a lifelong learner is knowing that you can learn something from every single person you meet.&amp;rdquo; If you remember that, you can&amp;rsquo;t be a know it all.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pypi.org/project/semantic-text-splitter/&#34;&gt;semantic-text-splitter&lt;/a&gt; could be the go-to text splitter. It&amp;rsquo;s Rust-based, supports MarkdownSplitter, and multiple tokenizers. Alternatives like &lt;a href=&#34;https://pypi.org/project/semchunk/&#34;&gt;semchunk&lt;/a&gt;, &lt;a href=&#34;https://pypi.org/project/advanced-chunker/&#34;&gt;advanced-chunker&lt;/a&gt;, &lt;a href=&#34;https://github.com/chonkie-inc/chonkie&#34;&gt;chonkie&lt;/a&gt;, etc. seem clunkier.&lt;/li&gt;
&lt;li&gt;ULID is like UUID but time-sortable. That&amp;rsquo;s an improvement over timestamp IDs (definitely) and potentially even UUIDs. They can be generated by clients as a globally unique ID. Try &lt;a href=&#34;https://github.com/mdomke/python-ulid&#34;&gt;&lt;code&gt;pip install python-ulid&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://github.com/ulid/javascript&#34;&gt;&lt;code&gt;npm install ulid&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://www.cpsc.gov/Data&#34;&gt;Consumer Product Safety Commission Data&lt;/a&gt; has thousands of reports of product safety over time&lt;/li&gt;
&lt;li&gt;You can run &lt;code&gt;xclip -sel clip -o | pandoc -f markdown -t html --no-highlight | xclip -sel clip -t text/html -i&lt;/code&gt; to convert Markdown in the clipboard to rich text. But &lt;code&gt;xclip&lt;/code&gt; doesn&amp;rsquo;t support multiple selections, so the text is lost. &lt;a href=&#34;https://chatgpt.com/share/68071421-07a4-800c-a286-0d8b624c27e4&#34;&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://duckdb.org/2025/03/12/duckdb-ui.html&#34;&gt;DuckDB UI &amp;amp; Notebooks&lt;/a&gt; will potentially be a good alternative to Datasette, DBeaver, etc. But for now, there are still glitches. It crashes with a &lt;code&gt;SIGSEGV (Address boundary error)&lt;/code&gt; when connecting to SQLite databases.&lt;/li&gt;
&lt;li&gt;Ollama limits MAX_TOKENS to 2K by default.&lt;/li&gt;
&lt;li&gt;AI assisted search helps wherever I would have used Google, e.g.
&lt;ul&gt;
&lt;li&gt;Debugging. &amp;ldquo;Fix CUDA initialization: CUDA unknown error&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Tool search. &amp;ldquo;Find an online word counter tool.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Library search. &amp;ldquo;Find a JS micro library to render Markdown.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI API capabilites lag ChatGPT features. For example:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;o4-mini&lt;/code&gt; via the API does &lt;em&gt;not&lt;/em&gt; search the web natively as part of its reasoning.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;o4-mini&lt;/code&gt;, &lt;code&gt;o3&lt;/code&gt;, &lt;code&gt;o3-mini&lt;/code&gt;, &lt;code&gt;o1&lt;/code&gt;, &lt;code&gt;gpt-4.1-nano&lt;/code&gt; don&amp;rsquo;t yet support the &lt;code&gt;web_search_preview&lt;/code&gt; tool. Only &lt;code&gt;gpt-4.1&lt;/code&gt; and &lt;code&gt;gpt-4.1-mini&lt;/code&gt; do. &lt;a href=&#34;https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses#limitations&#34;&gt;Limitations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Search results are NOT visible via the API. They&amp;rsquo;re fed directly to the model. The number of searches or results is unknown. Each search costs 0.25-0.5 cents. &lt;a href=&#34;https://openai.com/api/pricing/&#34;&gt;Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For reasoning traces (e.g. &lt;code&gt;.reasoning.summary: &amp;quot;medium&amp;quot;&lt;/code&gt;) you need to verify your organization via &lt;a href=&#34;https://withpersona.com/&#34;&gt;withpersona.com&lt;/a&gt; which failed with my Indian passport AND Singapore work permit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The ChatGPT Plus plan ($20) gives you 50 O4 mini messages a day, which I exceeded!
It&amp;rsquo;s supposed to reset at midnight UTC &lt;a href=&#34;https://community.openai.com/t/limitations-on-the-openai-o-series-reasoning-models-on-chatgpt/1230183/2&#34;&gt;Ref&lt;/a&gt;
but might operate on a rolling window &lt;a href=&#34;https://chatgpt.com/share/68070ba9-04c0-800c-901e-c3c6e8048f9d&#34;&gt;ChatGPT&lt;/a&gt;.
&amp;ldquo;Currently, there is no way to check how many messages you have used in your usage budget.&amp;rdquo;
&lt;a href=&#34;https://help.openai.com/en/articles/9824962-openai-o3-and-o4-mini-usage-limits-on-chatgpt-and-the-api&#34;&gt;OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.signalbloom.ai/&#34;&gt;SignalBloom&lt;/a&gt; reads SEC filings and writes analyst reports on it using LLMs&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Evaluation in the loop&amp;rdquo; or &amp;ldquo;Evals-in-the-loop&amp;rdquo; is a new term I learnt. &lt;a href=&#34;https://www.signalbloom.ai/hallucination-benchmark&#34;&gt;SignalBloom&amp;rsquo;s Hallucination Bechmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If AI interacts with the world and generates data from its own experience and learns from that, we have a new scaling mechanism. &lt;a href=&#34;https://youtu.be/zzXyPGEtseI&#34;&gt;DeepMind podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI&amp;rsquo;s search API is fairly expensive at $30+/1K calls. Typically, to read interesting HN articles, I will make 30 calls which is about 75c. Instead I should use the app and summarise HM news across different days manually based on my interests!&lt;/li&gt;
&lt;li&gt;Finally! &lt;a href=&#34;https://davepeck.org/2025/04/11/pythons-new-t-strings/&#34;&gt;t-strings&lt;/a&gt; land in Python. They&amp;rsquo;re like JavaScript template literals.&lt;/li&gt;
&lt;li&gt;DuckDB&amp;rsquo;s CSV parser might be one of the most forgiving parsers. Even better than Pandas or SQLite3. &lt;a href=&#34;https://duckdb.org/2025/04/16/duckdb-csv-pollock-benchmark&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Good managers will probably make good AI managers. AI agents can probably substitute humans in business experiments. &lt;a href=&#34;https://bsky.app/profile/emollick.bsky.social/post/3lmhuceiyfk2a&#34;&gt;Ethan Mollick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If Windsurf stops working, reload the extension. &lt;a href=&#34;https://github.com/Exafunction/codeium/issues/59#issuecomment-2690290023&#34;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;TLS certificates will start expiring in 47 days from 15 Mar 2029, forcing automated domain renewals. &lt;a href=&#34;https://www.digicert.com/blog/tls-certificate-lifetimes-will-officially-reduce-to-47-days&#34;&gt;Digicert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wiki.nixos.org/wiki/Flakes&#34;&gt;Nix flakes&lt;/a&gt; are a reliable alternative to &lt;a href=&#34;https://containers.dev/&#34;&gt;DevContainers&lt;/a&gt; that don&amp;rsquo;t need Docker - but don&amp;rsquo;t work on Windows.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/vadimdemedes/ink&#34;&gt;Ink&lt;/a&gt; is like React for the CLI.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://filiph.github.io/unsure/&#34;&gt;Unsure Calculator&lt;/a&gt; is a great tool to calculate formulas with &lt;em&gt;multiple&lt;/em&gt; uncertainties, like:
&lt;ul&gt;
&lt;li&gt;My office is 9-11 km away and it takes me 45-55 min to reach. So I cycle at &lt;code&gt;9~11 / 45~55 * 60&lt;/code&gt; ~ 10-14 kmph (12 most likely).&lt;/li&gt;
&lt;li&gt;I spend $6-15 on lunch and eat out 80-120 days a year. So I spend &lt;code&gt;6~15 * 80~120&lt;/code&gt; ~ $600~1550 ($1000 most likely) eating out yearly.&lt;/li&gt;
&lt;li&gt;I take 30-120 min to prepare a quiz question. Each exam has 6-12 questions. So I need &lt;code&gt;30~120 * 6~12 / 60&lt;/code&gt; = 4~20 hours (11 most likely)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Using Kiran&amp;rsquo;s &lt;a href=&#34;https://jackerhack.ing/notes/202412051824-macos-setup-for-dev&#34;&gt;macOS setup for dev&lt;/a&gt; I &lt;a href=&#34;https://github.com/sanand0/scripts/commit/ae95013019374a3b542ef5a93ea2f4295d0d86c4&#34;&gt;enabled&lt;/a&gt; colorized less and mouse options for tmux.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time fish -i -c exit&lt;/code&gt; prints the time taken for fish startup. &lt;code&gt;fish --profile-startup ~/fish.profile -i -c exit&lt;/code&gt; prints the time taken by each command on fish startup to &lt;code&gt;~/fish.profile&lt;/code&gt;. I used this to &lt;a href=&#34;https://github.com/sanand0/scripts/commit/90d34b7239197d69c3502d1e847b79dd503c1b72&#34;&gt;speed up my fish startup&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The 8 top features of the &lt;a href=&#34;https://platform.openai.com/docs/api-reference/responses&#34;&gt;OpenAI Responses API&lt;/a&gt; that are an improvement over the Completions API (IMHO) are:
&lt;ul&gt;
&lt;li&gt;Link to previous response rather than sending history&lt;/li&gt;
&lt;li&gt;Uploading files directly&lt;/li&gt;
&lt;li&gt;Swappable system instructions while retaining the chat history&lt;/li&gt;
&lt;li&gt;Customisable reasoning effort AND reasoning summary detail&lt;/li&gt;
&lt;li&gt;Truncation in the middle option&lt;/li&gt;
&lt;li&gt;Web search context size option&lt;/li&gt;
&lt;li&gt;File search filters by file attributes&lt;/li&gt;
&lt;li&gt;Flex service tier for lower cost&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI doesn&amp;rsquo;t charge for file storage but &lt;em&gt;does&lt;/em&gt; charge 10 cents / GB-day for vector storage beyond 1 GB. The first 1GB is free&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.augmentcode.com/&#34;&gt;Augment Code&lt;/a&gt; is an AI code editor that&amp;rsquo;s growing popular on Reddit. #ai-coding&lt;/li&gt;
&lt;li&gt;The GPT 4.1 models have a 75% discounted prompt caching (instead of the usual 50%), making them particularly suited for repetitive tasks. &lt;a href=&#34;https://openai.com/index/gpt-4-1/&#34;&gt;OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chatgpt.com/&#34;&gt;chatgpt.com&lt;/a&gt; shortcut keys are revealed via &lt;code&gt;Ctrl + /&lt;/code&gt;. Here&amp;rsquo;s my ranking on usefulness:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + C&lt;/code&gt;: Copy last response as Markdown!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + ;&lt;/code&gt;: Copy last code block&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + S&lt;/code&gt;: Sidebar toggle&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + O&lt;/code&gt;: Open new chat&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Shift + Esc&lt;/code&gt;: Focus chat input&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + I&lt;/code&gt;: Ccustom instructions&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + Shift + X&lt;/code&gt;: Delete chat&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 02 Mar 2025</title>
      <link>https://www.s-anand.net/blog/things-i-learned-02-mar-2025/</link>
      <pubDate>Sun, 02 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-02-mar-2025/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.proxmox.com/en/products/proxmox-virtual-environment/overview&#34;&gt;Proxmox Virtual Environment&lt;/a&gt; is an open-source alternative to VMWare, Hyper-V, Citrix XenServer, etc. (There&amp;rsquo;s nothing there that prompts me to explore it further.)&lt;/li&gt;
&lt;li&gt;With Podman on Windows (a Docker equivalent), many Docker-enabled tasks become easier. For example, running PostgreSQL is as easy as:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman run -d --name postgres -e &lt;span class=&#34;nv&#34;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;postgres -p 5432:5432 postgres:latest
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;podman &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; -it postgres psql -U postgres -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;CREATE DATABASE mydb;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Bad deep research prompts are: vague/broad, under-specified or ambiguous. In short, the more you know what you want, the better. Iterate until then.&lt;/li&gt;
&lt;li&gt;What kind of reports do clients are research companies to produce? I was curious to see if Deep Research can replace these. Here are a bunch of ideas. &lt;a href=&#34;https://chatgpt.com/share/67bf7946-c80c-800c-8132-6f4018455a68&#34;&gt;ChatGPT&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Strategy &amp;amp; Management Consulting Research (McKinsey &amp;amp; Company, Boston Consulting Group, Bain &amp;amp; Company, Strategy&amp;amp;, Accenture Strategy)
&lt;ul&gt;
&lt;li&gt;Produce a comprehensive strategic transformation report for a Fortune 500 consumer goods company. Analyze global market trends, competitor strategies, and actionable growth recommendations, including case studies and source citations.&lt;/li&gt;
&lt;li&gt;Generate an in‐depth study on corporate restructuring trends in emerging markets. Focus on successful turnaround strategies, CEO leadership factors, and strategic pivots, with a comparative analysis of key players.&lt;/li&gt;
&lt;li&gt;Create a report on M&amp;amp;A trends in the technology sector over the past five years. Detail deal drivers, integration best practices, and forecast future acquisition opportunities, citing relevant data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IT &amp;amp; Technology Research Analysts (Gartner, Forrester Research, IDC, 451 Research, Ovum)
&lt;ul&gt;
&lt;li&gt;Produce a market assessment report on emerging cloud computing platforms. Include vendor evaluations, adoption forecasts, and key technology drivers with supporting data and charts.&lt;/li&gt;
&lt;li&gt;Generate an in‐depth cybersecurity trends report for enterprise IT. Analyze recent threat vectors, defense strategies, and best practices for risk mitigation, providing actionable recommendations.&lt;/li&gt;
&lt;li&gt;Create a comprehensive study on the impact of artificial intelligence in enterprise software. Include competitive benchmarking, technology adoption rates, and forecasted market changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Marketing &amp;amp; Consumer Research (Nielsen, Kantar Group, Ipsos, GfK, Euromonitor International)
&lt;ul&gt;
&lt;li&gt;Produce a consumer behavior analysis report for a leading retail brand. Identify key demographic shifts, purchasing trends, and brand loyalty factors, and provide actionable insights with data visualizations.&lt;/li&gt;
&lt;li&gt;Generate a detailed report on digital media consumption trends among millennials, incorporating survey results, social media analytics, and case studies of successful campaigns.&lt;/li&gt;
&lt;li&gt;Create a market segmentation report for a new consumer electronics launch. Identify key consumer segments, behavioral drivers, and media usage patterns with clear recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Financial Investment Research (Goldman Sachs, JPMorgan Chase, Morgan Stanley, Morningstar, Keefe Bruyette &amp;amp; Woods)
&lt;ul&gt;
&lt;li&gt;Produce an equity research report on mid-cap technology stocks. Include detailed financial modeling, valuation analysis, and buy/sell/hold recommendations with supporting data and charts.&lt;/li&gt;
&lt;li&gt;Generate a fixed income analysis report for corporate bonds in the industrial sector. Assess credit risk, yield forecasts, and macroeconomic influences, citing key data sources.&lt;/li&gt;
&lt;li&gt;Create a comprehensive report on global market trends impacting investment banking. Analyze regulatory changes, market sentiment, and performance metrics of leading financial institutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Healthcare Research (IQVIA, Frost &amp;amp; Sullivan, Evaluate Ltd, Deloitte Healthcare, IMS Health)
&lt;ul&gt;
&lt;li&gt;Produce a market analysis report on emerging biotechnologies in oncology. Include competitive landscape, regulatory challenges, and growth forecasts with relevant case studies.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive report on patient satisfaction and telemedicine adoption trends. Analyze survey data from leading healthcare providers and benchmark best practices.&lt;/li&gt;
&lt;li&gt;Create a detailed study on pharmaceutical market dynamics in emerging economies. Focus on pipeline developments, regulatory environments, and market potential with actionable insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Legal Research Providers (LexisNexis, Westlaw, Bloomberg Law, Fastcase)
&lt;ul&gt;
&lt;li&gt;Produce a legal risk assessment report on the impact of recent data privacy regulations for multinational corporations. Include case studies, trend analysis (2019–2024), and strategic recommendations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive report summarizing key federal and Supreme Court rulings on intellectual property rights over the past five years, highlighting trends and divergent interpretations.&lt;/li&gt;
&lt;li&gt;Create a detailed report on the evolution of securities law and its effect on investment research practices, incorporating analysis of recent litigation and regulatory updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Media &amp;amp; News Research (Factiva, Kantar Media, Comscore, Cision)
&lt;ul&gt;
&lt;li&gt;Produce a media consumption trends report that analyzes audience behavior shifts across digital, TV, and print platforms. Include data visualizations, key drivers, and forecasted trends.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive report on the impact of social media on traditional news reporting, with case studies and a comparative analysis of engagement metrics.&lt;/li&gt;
&lt;li&gt;Create a detailed study on the effectiveness of multimedia advertising campaigns, evaluating ROI, consumer engagement, and best practices with actionable insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Economic &amp;amp; Industry-Specific Research (Economist Intelligence Unit, BMI Research, IHS Markit, Consensus Economics)
&lt;ul&gt;
&lt;li&gt;Produce a macroeconomic outlook report for emerging markets, including GDP, inflation, and employment forecasts, with detailed data analysis and visualizations.&lt;/li&gt;
&lt;li&gt;Generate an industry analysis report on the automotive sector, covering technological innovations, competitive dynamics, and consolidation trends.&lt;/li&gt;
&lt;li&gt;Create a comprehensive country risk assessment report for a target region, detailing political, economic, and regulatory factors with recommendations for investors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Human Resources &amp;amp; Employee Engagement Research (Gallup, Great Place to Work, Mercer)
&lt;ul&gt;
&lt;li&gt;Produce an employee engagement report for a multinational firm based on recent survey data. Identify key drivers of satisfaction, retention challenges, and improvement recommendations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the impact of remote and hybrid work models on employee productivity across industries, including best practices and benchmark data.&lt;/li&gt;
&lt;li&gt;Create a detailed report on workplace culture transformation, analyzing organizational behavior trends, employee feedback, and actionable strategies to boost engagement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Environmental, Social &amp;amp; Governance (ESG) Research (MSCI ESG Research, Sustainalytics, ISS ESG, Bloomberg ESG)
&lt;ul&gt;
&lt;li&gt;Produce an ESG performance report for a portfolio of global companies. Include sustainability scores, risk assessments, and recommendations for improvement with data visualizations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the impact of climate change regulations on the energy sector, including policy analysis, market forecasts, and strategic implications.&lt;/li&gt;
&lt;li&gt;Create a detailed report on corporate social responsibility trends in the consumer goods industry, incorporating qualitative and quantitative analyses with actionable recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Education &amp;amp; Academic Research (RAND Corporation, National Center for Education Statistics, HolonIQ)
&lt;ul&gt;
&lt;li&gt;Produce an analysis report on the future of online education, examining technological adoption, market growth projections, and student outcome trends with supporting data.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the effects of educational policy reforms on public school performance in the U.S., including trend analysis and actionable recommendations.&lt;/li&gt;
&lt;li&gt;Create a detailed international higher education trends report, covering tuition dynamics, international student mobility, and emerging academic programs with comparative data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Real Estate &amp;amp; Property Research (CBRE, JLL, CoStar Group, Cushman &amp;amp; Wakefield)
&lt;ul&gt;
&lt;li&gt;Produce a commercial real estate market analysis report for major urban centers, including occupancy trends, rental rate forecasts, and investment opportunity assessments.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on residential housing market dynamics in emerging economies, focusing on affordability, supply-demand gaps, and policy impacts.&lt;/li&gt;
&lt;li&gt;Create a detailed report on the impact of urban redevelopment projects on local real estate values, including case studies, forecasts, and strategic recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Energy &amp;amp; Natural Resources Research (Wood Mackenzie, Rystad Energy, Bloomberg New Energy Finance)
&lt;ul&gt;
&lt;li&gt;Produce an analysis report on global renewable energy trends, covering technology adoption, market forecasts, and key policy drivers, with detailed data and visuals.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive commodity price forecasting report for oil, natural gas, and key metals, incorporating historical trends, risk assessments, and predictive modeling.&lt;/li&gt;
&lt;li&gt;Create a detailed report on energy transition strategies for traditional energy companies, focusing on clean technology investments and market adaptation strategies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Supply Chain &amp;amp; Logistics Research (ARC Advisory Group, Gartner Supply Chain Research, Supply Chain Insights)
&lt;ul&gt;
&lt;li&gt;Produce a report on supply chain resilience for global manufacturers. Analyze risk factors, digital transformation impacts, and best practices for operational efficiency with supporting data.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the impact of technology on logistics networks, including case studies on digital optimization and cost reduction strategies.&lt;/li&gt;
&lt;li&gt;Create a detailed report on emerging last-mile delivery solutions, assessing innovations, consumer expectations, and scalability with actionable insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cybersecurity &amp;amp; Information Security Research (KuppingerCole, Forrester Security, IDC Cybersecurity, Cybersecurity Ventures)
&lt;ul&gt;
&lt;li&gt;Produce an in-depth report on emerging cybersecurity threats for large enterprises, including detailed analysis of recent incidents, risk vectors, and defense strategies.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive cybersecurity market landscape report, evaluating vendor performance, technology forecasts, and best practices for mitigating risks.&lt;/li&gt;
&lt;li&gt;Create a detailed report on regulatory compliance trends in information security within the financial services industry, with case studies and strategic recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Social Media, Digital &amp;amp; Online Research (Comscore, SimilarWeb, Brandwatch)
&lt;ul&gt;
&lt;li&gt;Produce a digital audience behavior report for a global brand, focusing on social media trends, engagement metrics, and platform performance with detailed data analysis.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive analysis of influencer marketing effectiveness across digital channels, including ROI metrics, case studies, and best practices.&lt;/li&gt;
&lt;li&gt;Create a detailed report on online brand sentiment analysis, incorporating social listening data, trend forecasts, and actionable recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Public Opinion &amp;amp; Political Research (Pew Research Center, Gallup, YouGov)
&lt;ul&gt;
&lt;li&gt;Produce a public opinion polling report on voter sentiment ahead of a major election. Include demographic breakdowns, key issue analysis, and trend visualizations for the past five years.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on political risk in emerging markets, analyzing historical data, current trends, and future projections, with policy recommendations.&lt;/li&gt;
&lt;li&gt;Create a detailed report on the influence of media on public policy, using survey data, social media analysis, and comparative case studies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sports, Entertainment &amp;amp; Media Research (Nielsen Sports, Sportcal, Kantar Media Sports)
&lt;ul&gt;
&lt;li&gt;Produce a market analysis report on sports sponsorship trends, detailing viewership metrics, brand engagement, and investment ROI with industry case studies.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive report on audience behavior in the streaming media industry, including demographic insights, consumption trends, and competitive benchmarks.&lt;/li&gt;
&lt;li&gt;Create a detailed analysis of digital advertising effectiveness in the entertainment sector, including segmentation data, ROI analysis, and strategic recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Innovation, R&amp;amp;D &amp;amp; Technology Trends Research (Innosight, Frost &amp;amp; Sullivan Innovation, CB Insights)
&lt;ul&gt;
&lt;li&gt;Produce a global R&amp;amp;D investment trends report, analyzing technology spending, innovation indices, and the impact on market growth across key industries.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on disruptive technologies in manufacturing, including competitive analysis, market potential forecasts, and adoption trends.&lt;/li&gt;
&lt;li&gt;Create a detailed report on emerging innovation hubs worldwide, focusing on startup ecosystems, funding trends, and collaborative opportunities in technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agriculture &amp;amp; Agribusiness Research (Rabobank Agribusiness Research, USDA Economic Research Service, AgFunder)
&lt;ul&gt;
&lt;li&gt;Produce an analysis report on global agricultural market trends, including crop yield forecasts, trade dynamics, and policy impacts, with data visualizations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on agritech innovations such as precision farming and sustainable practices, including case studies and market forecasts.&lt;/li&gt;
&lt;li&gt;Create a detailed report on the impact of climate change on food production and supply chain stability in agribusiness, with risk assessments and strategic recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Environmental &amp;amp; Climate Change Research (Carbon Trust, IHS Markit Energy Transition, Bloomberg New Energy Finance)
&lt;ul&gt;
&lt;li&gt;Produce a report on the economic and social impacts of climate change on urban infrastructure, including forecasting models and policy recommendations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on national climate policies and their effects on industrial competitiveness, with detailed trend analysis and source citations.&lt;/li&gt;
&lt;li&gt;Create a detailed report on corporate sustainability initiatives, assessing environmental risk management practices and providing actionable recommendations for improvement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Customer Experience (CX) &amp;amp; User Experience (UX) Research (Forrester CX Research, Gartner CX Research, Qualtrics, Nielsen Norman Group)
&lt;ul&gt;
&lt;li&gt;Produce a report on customer journey mapping for a leading retail brand, identifying key touchpoints, pain points, and actionable improvement strategies with data visualizations.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on digital user experience trends for e-commerce platforms, including usability testing insights, design best practices, and conversion optimization recommendations.&lt;/li&gt;
&lt;li&gt;Create a detailed report on customer satisfaction and loyalty metrics across multiple industries, integrating survey data and actionable recommendations to enhance overall CX.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Blockchain, Cryptocurrency &amp;amp; Fintech Research (Chainalysis, CoinDesk Research, Deloitte Fintech Research, CB Insights)
&lt;ul&gt;
&lt;li&gt;Produce an analysis report on emerging blockchain technologies and their applications in financial services, including market trends, adoption forecasts, and case studies.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on cryptocurrency market dynamics, analyzing regulatory developments, investor sentiment, and competitive landscapes with source citations.&lt;/li&gt;
&lt;li&gt;Create a detailed report on fintech disruption in traditional banking, with case studies on leading startups, technology adoption, and future market forecasts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Venture Capital, Startup &amp;amp; Private Equity Research (PitchBook, CB Insights, Crunchbase, Preqin)
&lt;ul&gt;
&lt;li&gt;Produce a global venture capital investment trends report, including performance analysis of high-growth startups, sector benchmarks, and emerging market opportunities.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on private equity market dynamics, covering deal flow analysis, exit strategies, and forecasted trends with supporting data.&lt;/li&gt;
&lt;li&gt;Create a detailed report on emerging startup ecosystems in key regions, highlighting funding trends, investor activity, and growth potential with actionable insights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Operations Research &amp;amp; Management Science Consulting (The Brattle Group, NERA Economic Consulting, CRA International)
&lt;ul&gt;
&lt;li&gt;Produce a report on optimization techniques for operational efficiency in large-scale manufacturing, including quantitative analysis, simulation models, and case studies.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the application of predictive analytics in supply chain management, focusing on data modeling, process improvements, and actionable insights.&lt;/li&gt;
&lt;li&gt;Create a detailed report on advanced quantitative modeling approaches to solve complex business problems in logistics and operations, including scenario analysis and recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cultural &amp;amp; Social Research (Ethnographic/Sociocultural Studies) (Ipsos MORI, Kantar TNS, YouGov)
&lt;ul&gt;
&lt;li&gt;Produce a qualitative ethnographic study on urban consumer lifestyle trends, incorporating field observations, interviews, and cultural analysis with actionable insights.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on how cultural shifts influence global brand perception, including comparative case studies and trend analysis.&lt;/li&gt;
&lt;li&gt;Create a detailed report on sociocultural dynamics and consumer behavior in emerging economies, integrating in-depth field research and actionable recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Economic &amp;amp; Demographic Research Firms (Oxford Economics, The Conference Board, CEIC Data)
&lt;ul&gt;
&lt;li&gt;Produce a macroeconomic forecasting report for a specific region, including GDP, inflation, and employment trends with detailed data visualizations and source citations.&lt;/li&gt;
&lt;li&gt;Generate a detailed demographic analysis report for a target market, highlighting age distribution, income levels, and consumption patterns with actionable insights.&lt;/li&gt;
&lt;li&gt;Create a comprehensive report on the economic impact of demographic shifts on consumer markets, with policy recommendations and trend analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Academic &amp;amp; Think Tank Research Organizations (Brookings Institution, RAND Corporation, Carnegie Endowment for International Peace)
&lt;ul&gt;
&lt;li&gt;Produce a policy research report on global governance challenges and their implications for economic development, including case studies, literature reviews, and expert interviews.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on social inequality and its effects on public health and education outcomes, supported by empirical research and trend analysis.&lt;/li&gt;
&lt;li&gt;Create a detailed report on emerging trends in international relations and their impact on global trade and security, integrating academic research and data analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Market Research Technology &amp;amp; Software Providers (Qualtrics, SurveyMonkey, Confirmit)
&lt;ul&gt;
&lt;li&gt;Produce a report on the latest innovations in survey technology and data analytics software for market research, including product comparisons, user case studies, and future trend forecasts.&lt;/li&gt;
&lt;li&gt;Generate a comprehensive study on the integration of AI and machine learning in consumer insights platforms, highlighting case studies, performance metrics, and industry benchmarks.&lt;/li&gt;
&lt;li&gt;Create a detailed report on digital transformation trends in market research technology, featuring analysis of leading software solutions, market share data, and recommendations for technology adoption.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;When evaluating inputs, models tend to prefer the first response, prefer their own response, and prefer longer responses. &lt;a href=&#34;https://sub.thursdai.news/p/thursdai-feb-20-live-from-ai-eng&#34;&gt;ThursdAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Real-time speech-to-text options for transcription:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://deepgram.com/learn/live-transcription-mic-browser&#34;&gt;Deepgram&lt;/a&gt; has a MediaRecorder API, which is perfect.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/QuentinFuxa/whisper_streaming_web&#34;&gt;Whisper Streaming Web&lt;/a&gt; is a web app that can transcribe audio real-time from the browser. A good approach, but I wouldn&amp;rsquo;t use it for meeting transcription on my mid-end laptop. Streaming takes up the bulk of my GPU, leaving little for transcription.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/collabora/WhisperLive&#34;&gt;whisper-live&lt;/a&gt; runs as a Python console app and does something similar.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://huggingface.co/spaces/Xenova/realtime-whisper-webgpu&#34;&gt;Whisper WebGPU&lt;/a&gt; runs on the browser (only 200MB). Cool! But slow and still takes up GPU.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gpt-omni/mini-omni/&#34;&gt;Mini-omni&lt;/a&gt; is an open-source Qwen-based LLM that can hear and talk while thinking in real-time. An interesting experiment, but not for prototyping.&lt;/li&gt;
&lt;li&gt;OpenAI shares an insights report with clients that has insights on what different professions search for. What doctors search for is:
&lt;ol&gt;
&lt;li&gt;Is my diagnosis right?&lt;/li&gt;
&lt;li&gt;How do I read this report?&lt;/li&gt;
&lt;li&gt;Is my prescription correct?&lt;/li&gt;
&lt;li&gt;Is there a cheaper medicine?&lt;/li&gt;
&lt;li&gt;What&amp;rsquo;s the life expectancy given these symptoms?&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Dataclasses in Python have a slight overhead over named tuples. The 2 main uses I see for them are: providing defaults and offering type hints.&lt;/li&gt;
&lt;li&gt;UVB 76 is a radio channel has been broadcasting static (with occasional Russian conversation) since 1976. No one knows why. It&amp;rsquo;s live at &lt;a href=&#34;https://m.youtube.com/watch?v=8h_D2P0iqMk&#34;&gt;https://m.youtube.com/watch?v=8h_D2P0iqMk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Romans washed clothes in urine. The government taxed the purchase of urine for commercial purposes! That&amp;rsquo;s the origin of the phrase &amp;ldquo;Pecunia non olet&amp;rdquo; which means &amp;ldquo;money doesn&amp;rsquo;t stink&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nixos.org/&#34;&gt;Nix&lt;/a&gt; is a package manager that creates container-like environments. Like a cross between Docker and &lt;code&gt;apt&lt;/code&gt; / &lt;code&gt;venv&lt;/code&gt;. It has an immutable file system. &lt;a href=&#34;https://www.jetify.com/devbox&#34;&gt;DevBox&lt;/a&gt; is a higher-level tool built on top of Nix that streamlines developer workflows, e.g. common project environment setup.&lt;/li&gt;
&lt;li&gt;VS Code can be used to develop inside a Docker container via Podman, too. Set &lt;code&gt;dev.containers.dockerPath&amp;quot;: &amp;quot;podman&amp;quot;&lt;/code&gt; &lt;a href=&#34;https://geekingoutpodcast.substack.com/p/running-dev-containers-locally-with&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.rilldata.com/&#34;&gt;Rill Data&lt;/a&gt; is an interesting BI tool based on DuckDB. It auto-generates a dashboard given a dataset.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s possible to assign &amp;ldquo;variables&amp;rdquo; in SQL (notably in DuckDB). Here&amp;rsquo;s an example:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;WITH&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sessions&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;events&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;DISTINCT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;session_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pages&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;events&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sessions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pages&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sessions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pages_per_session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;DuckDB has a &lt;code&gt;GROUP BY *&lt;/code&gt; that groups by all categorical columns. &lt;code&gt;SELECT x, y, COUNT(*) FROM t GROUP BY *&lt;/code&gt; is equivalent to &lt;code&gt;SELECT x, y, COUNT(*) FROM t GROUP BY x, y&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;VS Code can be used as a code executor by adding &lt;code&gt;{&amp;quot;key&amp;quot;: &amp;quot;shift+enter&amp;quot;, &amp;quot;command&amp;quot;: &amp;quot;workbench.action.terminal.runSelectedText&amp;quot;, &amp;quot;when&amp;quot;: &amp;quot;editorFocus&amp;quot;}&lt;/code&gt; to the &lt;code&gt;keybindings.json&lt;/code&gt; file. Press Shift-Enter to run the selection on the terminal. Useful for DuckDB, SQLite, etc. &lt;a href=&#34;https://motherduck.com/blog/duckdb-tutorial-for-beginners/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LLMs are excellent at database migration. They can convert schemas and queries across SQL dialects (e.g. BigQuery to DuckDB, etc.) at 90%+ accuracy. This is useful when clients want to migrate cloud providers, go from on-prem to cloud, or reduce cost by switching databases.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Perl, 1994-2011</title>
      <link>https://www.s-anand.net/blog/perl-1994-2011/</link>
      <pubDate>Sat, 28 Sep 2024 16:51:14 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/perl-1994-2011/</guid>
      <description>&lt;p&gt;In 1994, I learnt &lt;a href=&#34;https://www.perl.org/&#34;&gt;Perl&lt;/a&gt;. It was fantastic. I used it to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1995: Build CCChat - the unofficial IITM &lt;a href=&#34;https://www.s-anand.net/blog/bets-and-pranks/lee-in-the-cc/&#34;&gt;email system&lt;/a&gt; and software repository&lt;/li&gt;
&lt;li&gt;1999: Build &lt;a href=&#34;https://s-anand.net/&#34;&gt;my entire blog&lt;/a&gt; from scratch&lt;/li&gt;
&lt;li&gt;2000: Author my 2nd year thesis on the &lt;a href=&#34;https://archive.org/download/final-report_20240928/Final_Report.doc&#34;&gt;&lt;strong&gt;Behavioural Aspects of Financial Analysts&lt;/strong&gt;&lt;/a&gt; by analyzing 600MB of IBES data&lt;/li&gt;
&lt;li&gt;2002: Analyze where to place the &lt;a href=&#34;https://www.s-anand.net/blog/visualisation-locating-hubs/&#34;&gt;central processing hubs&lt;/a&gt; for a bank&lt;/li&gt;
&lt;li&gt;2004: Analyze the interest durations of public sector banks&lt;/li&gt;
&lt;li&gt;2005: Creating &lt;a href=&#34;https://www.s-anand.net/blog/matching-misspelt-tamil-movie-names/&#34;&gt;music quizzes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2006: Create my own &lt;a href=&#34;https://www.s-anand.net/blog/hindi-songs-online/&#34;&gt;music search engine&lt;/a&gt; (which earned me about $100 a month in Google Ad revenue for a while)&lt;/li&gt;
&lt;li&gt;2006: Automated &lt;a href=&#34;https://www.s-anand.net/blog/automated-resume-filtering/&#34;&gt;resume filtering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2007: Create custom search engines&lt;/li&gt;
&lt;li&gt;2008: &lt;a href=&#34;https://www.s-anand.net/blog/launching-applications/&#34;&gt;Build application launchers&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In 2006, I was convinced &lt;a href=&#34;https://www.s-anand.net/blog/python-vs-perl/&#34;&gt;I should stick to Perl&lt;/a&gt; over Python.&lt;/p&gt;
&lt;p&gt;In 2008, Google launched AppEngine and it provided free hosting (which was a &lt;strong&gt;big deal&lt;/strong&gt;!) but had only 2 runtimes: Java and Python. The choice was clear. I&amp;rsquo;d rather learn Python than code in Java.&lt;/p&gt;
&lt;p&gt;By 2011, I &lt;a href=&#34;https://www.s-anand.net/blog/software-for-my-new-laptop-2/&#34;&gt;stopped installing Perl&lt;/a&gt; on my laptop.&lt;/p&gt;
&lt;p&gt;Though most people know me mainly as a Python developer, I&amp;rsquo;ve programmed in Perl for about as long as I have in Python. I have fond memories of it. But I can&amp;rsquo;t read any of my code, nor write in it anymore.&lt;/p&gt;
&lt;p&gt;When I watched The Perl Conference (now called The Perl and Raku Conference &amp;ndash; Perl 6 is called Raku), I was surprised to hear how much the language had declined.&lt;/p&gt;
&lt;div class=&#34;video-embed&#34;&gt;&lt;iframe src=&#34;https://www.youtube.com/embed/BgjV8A10peI&#34; title=&#34;YouTube video&#34; loading=&#34;lazy&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=BgjV8A10peI&amp;amp;t=533s&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/perl-conference-attendees.webp&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There were fewer than 100 attendees - and for 2025, they&amp;rsquo;ve &lt;a href=&#34;https://blogs.perl.org/users/makoto_nozaki/2024/09/things-ive-learned-serving-on-the-board-of-the-perl-foundation.html&#34;&gt;decided to go smaller&lt;/a&gt; and book a tiny hotel, so as to break-even even if only 20 people show up.&lt;/p&gt;
&lt;p&gt;Few languages have had as much of an impact on my life and thinking. My knowledge of modern programming comes from &lt;a href=&#34;https://en.wikipedia.org/wiki/Programming_Perl&#34;&gt;The Camel Book&lt;/a&gt;, functional programming from &lt;a href=&#34;https://hop.perl.plover.com/&#34;&gt;Higher Order Perl&lt;/a&gt;, Windows programming from &lt;a href=&#34;https://www.goodreads.com/book/show/86631.Learning_Perl_on_Win32_Systems&#34;&gt;Learning Perl on Win32 Systems&lt;/a&gt;, and so on. Even my philosophy of coding was shaped by Larry Wall&amp;rsquo;s the &lt;a href=&#34;https://thethreevirtues.com/&#34;&gt;three great virtues of a programmer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is my homage to the language that shaped me. Bless you, Perl!&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 09 Jun 2024</title>
      <link>https://www.s-anand.net/blog/things-i-learned-09-jun-2024/</link>
      <pubDate>Sun, 09 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-09-jun-2024/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;httpretty can mock ALL Python HTTP libraries&lt;/li&gt;
&lt;li&gt;Japanese pray to dead parents instead of gods. The dead are preserved in plates by priests. Japanese are generally non religious&lt;/li&gt;
&lt;li&gt;Looks like GPT-4o is using CNNs to create vector embeddings of images, with images gridded into a 1x1, 2x2, etc. PLUS OCR. &lt;a href=&#34;https://www.oranlooney.com/post/gpt-cnn/&#34;&gt;Ref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The sum of a sinusoidal series is like a spirogram. Spinning circle linked to another and so on &lt;a href=&#34;https://www.andreinc.net/2024/04/24/from-the-circle-to-epicycles&#34;&gt;https://www.andreinc.net/2024/04/24/from-the-circle-to-epicycles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 18 Feb 2024</title>
      <link>https://www.s-anand.net/blog/things-i-learned-18-feb-2024/</link>
      <pubDate>Sun, 18 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-18-feb-2024/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fine tuning makes economic sense only if the input tokens SAVED is twice the output token size on each call.&lt;/li&gt;
&lt;li&gt;Docker container memory usage on WSL2 &lt;code&gt;docker stats&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;frolvlad/alpine-glibc:alpine-3.17: 540KB&lt;/li&gt;
&lt;li&gt;ubuntu: 1MB (python3: +5MB)&lt;/li&gt;
&lt;li&gt;nikolaik/python-nodejs:python3.10-nodejs18-bullseye: 1.4MB (python3: +5MB)&lt;/li&gt;
&lt;li&gt;python:3-alpine: 612KB (python3: +7.5MB)&lt;/li&gt;
&lt;li&gt;python:3: 500KB (python3: +11.2MB)&lt;/li&gt;
&lt;li&gt;continuumio/miniconda3: 7.6MB (+6.5MB)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discussion with Vinu Yamunan
&lt;ul&gt;
&lt;li&gt;Databuck by FirstEigen. Autolysis plus monitoring&lt;/li&gt;
&lt;li&gt;Quality council has the data steward (maintainer of each dataset) coming together with the uses on a weekly basis to understand what quality problems to users are facing. Data owners jaundice at a lower frequency to get an understanding&lt;/li&gt;
&lt;li&gt;#TODO Automate rules for data quality in our projects and intranet&lt;/li&gt;
&lt;li&gt;Convert a config rule into business language. Explain SQL. These are good use cases for llm&amp;rsquo;s&lt;/li&gt;
&lt;li&gt;Graph DBs are powerful for flexible data structures, but query generation needs AI or expertise. Check the Neo4J language cypher&lt;/li&gt;
&lt;li&gt;Explore storing SAME data in relational DBs AND in graph DBs / document DBs for different use cases&lt;/li&gt;
&lt;li&gt;Dallas rocketry challenge. Build a rocket that can take an egg to 800 feet exactly and land without breaking it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discussion with Karthik A
&lt;ul&gt;
&lt;li&gt;#TODO Ask IIT students to do internship tasks. Use advent of code is a qualifying criterion&lt;/li&gt;
&lt;li&gt;Tata motors unionized DB admins for longevity. No one can take their jobs. Hires people who LIKE their jobs&lt;/li&gt;
&lt;li&gt;Rust gives me typing. It&amp;rsquo;s very efficient. Pola.rs is interesting but Pandas as good enough.&lt;/li&gt;
&lt;li&gt;Explore alerts from CCTV feeds. Karthik sends email alerts with pictures for:
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Is the machine on or off&amp;rdquo;? for productivity&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Are people not wearing helmets?&amp;rdquo; for safety at Cummins&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;#TODO Integrate with WhatsApp. Use LLMs with function calling for responses&lt;/li&gt;
&lt;li&gt;Use expiring links (to pictures or content). It increases engagement&lt;/li&gt;
&lt;li&gt;Check Deno licensing. Is there a commercial clause? #ANS No - it&amp;rsquo;s MIT license&lt;/li&gt;
&lt;li&gt;Centre or excellence for zero emission tech at IIT. Karthik is part of it&lt;/li&gt;
&lt;li&gt;Explore auth0. 7000 users are free&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toml&lt;/code&gt; is part of the Python 3.11 standard library!&lt;/li&gt;
&lt;li&gt;If copilot writes code we don&amp;rsquo;t understand we are screwed. Hence expertise matters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discussion with Vikas Kedia
&lt;ul&gt;
&lt;li&gt;#TODO Plan an AMA&lt;/li&gt;
&lt;li&gt;The mind becomes lazy with financial success. Vikas is treating his podcast as a startup&lt;/li&gt;
&lt;li&gt;Hire a professional videographer for your content&lt;/li&gt;
&lt;li&gt;Financial RoI in financial markets is the highest. Programming is high too but FS is even better&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Performative power&amp;rdquo; &amp;ndash; when you&amp;rsquo;re forced to perform, you get better ideas&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://observablehq.com/blog/observable-2-0&#34;&gt;Observable 2.0 is an open source static site generator for data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.python.org/3/library/dataclasses.html&#34;&gt;Python dataclasses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://openai.com/sora&#34;&gt;SORA&lt;/a&gt; is OpenAI&amp;rsquo;s video generation model, and is stunning!&lt;/li&gt;
&lt;li&gt;If Appa comes to Singapore even for a week, he will feel better and can boast to his friends. At over 90, it may be better to move Appa to where I am since many of his friends would be no more and shops, doctors, etc can be managed and getting an independent house nearby is not hard.&lt;/li&gt;
&lt;li&gt;There is an SEZ in Gujarat where Indians can invest like in Mauritius without forex restraint&lt;/li&gt;
&lt;li&gt;Shubha: Media sites are moving away from Vickrey auctions to first-price auctions for ads. That&amp;rsquo;s because they send the auction price &lt;em&gt;forward&lt;/em&gt; to a search engine and the winning second-price value can lose even though the owner is willing to pay more. Second-price auctions don&amp;rsquo;t work unless ALL bidders are in the SAME auction. Ad networks are a hierarchy of auctions!&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developers.googleblog.com/2024/02/gemini-15-available-for-private-preview-in-google-ai-studio.html&#34;&gt;Gemini 1.5 launched&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fly.io/blog/gpu-ga/&#34;&gt;Fly.io offers GPU hosting&lt;/a&gt; and auto stop when they have nothing to do.&lt;/li&gt;
&lt;li&gt;Embeddings in random forest are very effective at classification &amp;ndash; much better than dot product.&lt;/li&gt;
&lt;li&gt;To deploy apps with OAuth + templating support in a small Docker container, use Caddy&lt;/li&gt;
&lt;li&gt;Deno has native TypeScript, browser APIs, and compiles to multiple OSs&lt;/li&gt;
&lt;li&gt;Ruff is a MUCH faster flake8&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://minimaxir.com/2023/12/chatgpt-structured-data/#two-pass-generation&#34;&gt;Two pass generation&lt;/a&gt; is a clever technique to get multiple SEQUENTIAL answers in a single API request. For example the schema &lt;code&gt;{&#39;code&#39;, &#39;optimized_code&#39;}&lt;/code&gt; will generate &lt;code&gt;code&lt;/code&gt; and then optimize it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://minimaxir.com/2023/12/chatgpt-reestructured-data/#unions-and-chain-of-thoughts&#34;&gt;Unions in function calling&lt;/a&gt; allows flexible multi-step prompts in a single API.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 14 Jan 2024</title>
      <link>https://www.s-anand.net/blog/things-i-learned-14-jan-2024/</link>
      <pubDate>Sun, 14 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-14-jan-2024/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transparent LED screens will be useful in windshieds to display maps as we drive.&lt;/li&gt;
&lt;li&gt;Marimo is a reactive alternative to Jupyter notebooks that saves files as pure Python.&lt;/li&gt;
&lt;li&gt;To run an org-specific chatbot on your own LLM: (via &lt;a href=&#34;https://github.com/sindresorhus/awesome-chatgpt&#34;&gt;awesome-chatgpt&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/langchain-ai/opengpts&#34;&gt;opengpts&lt;/a&gt; - but it doesn&amp;rsquo;t support auth&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mckaywrigley/chatbot-ui&#34;&gt;chatbot-ui&lt;/a&gt; - but Supabase is hard to install&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/anse-app/anse&#34;&gt;anse&lt;/a&gt; - but it doesn&amp;rsquo;t support auth&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web&#34;&gt;ChatGPT-Next-Web&lt;/a&gt; - but it doesn&amp;rsquo;t support auth&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tonybaloney.github.io/posts/python-gets-a-jit.html&#34;&gt;Python 3.13 gets a store and copy JIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If an npm package adds another package as a dependency with version &amp;ldquo;*&amp;rdquo;, target package cannot unpublish &lt;strong&gt;ANY&lt;/strong&gt; version! So this is a way of freezing EVERY repo and preventing unpublishing of EVERY version &amp;ndash; an unintentional flaw in the npm design. &lt;a href=&#34;https://youtu.be/xnPNKRs5TVo&#34;&gt;via&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ggerganov/llama.cpp/pull/1684&#34;&gt;Quantization is better than fewer parameters&lt;/a&gt;. So prefer high parameters (e.g. 70b) and quantize to 4-bit.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://antonz.org/in-browser-code-playgrounds/&#34;&gt;In-browser playgrounds&lt;/a&gt; has compiled WASM versions of Python, PHP, SQLite.&lt;/li&gt;
&lt;li&gt;Happiness Lab podcast. Happiness lessons of the ancients
&lt;ul&gt;
&lt;li&gt;Talking to strangers makes us happy&lt;/li&gt;
&lt;li&gt;Giving money makes us happy&lt;/li&gt;
&lt;li&gt;Free time makes us happier than working hard&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tangi
&lt;ul&gt;
&lt;li&gt;Domain-specific models being beaten by general purpose models is a phase. It will reverse towards domain.
&lt;ul&gt;
&lt;li&gt;AI will potentially help build and understand domain-specific models&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Models are evolving so rapidly that humans cannot interpret models. We need a process to interpret models!&lt;/li&gt;
&lt;li&gt;xAI, Responsible AI, Physics-guided or Knowledge-guided models (called grey box models) are therefore a trend&lt;/li&gt;
&lt;li&gt;CS papers
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t review other papers, certainly not other fields.&lt;/li&gt;
&lt;li&gt;Disregard measurement errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When CS papers get applied to climate, manufacturing or biology, we&amp;rsquo;ll worry about
&lt;ul&gt;
&lt;li&gt;Interpretability&lt;/li&gt;
&lt;li&gt;Domain-specific mechanics. (Introduce that into the training as a constraint.)
&lt;ul&gt;
&lt;li&gt;Many domain experts are using AI to UNDERSTAND their process. Need to explore&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Uncertainty&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IB adds context to make learning applicable. But that distracts from the core learning, and if there&amp;rsquo;s a gap it widens&lt;/li&gt;
&lt;li&gt;Most data science courses teach &amp;ldquo;Python science&amp;rdquo;, not data science. They teach a bunch of models. They don&amp;rsquo;t teach how even one kind of model e.g. LSTM works.&lt;/li&gt;
&lt;li&gt;Most coaching programs today teach FAMILIARITY with problems, not critical thinking&lt;/li&gt;
&lt;li&gt;Most of current education will become redundant thanks to LLMs. For students AND teachers
&lt;ul&gt;
&lt;li&gt;Coding will become irrelevant&lt;/li&gt;
&lt;li&gt;Cognitive thinking, reasoning, human relations, systems thinking will become more relevant&lt;/li&gt;
&lt;li&gt;Troubleshooting will become more important. AI is not self-diagnosing. I would hire someone who can figure out something is going wrong, diagnose what&amp;rsquo;s going wrong, and fix it&lt;/li&gt;
&lt;li&gt;#TODO Hire for troubleshooting ability. Give a Q, an A, and ask them to figure out if it&amp;rsquo;s wrong, why, and fix it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;All my exams and quizzes are open book, open ChatGPT. Onus is on me to give a problem that forces you to think.
&lt;ul&gt;
&lt;li&gt;#TODO Write a question paper that is ChatGPT proof.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Exploring AI could be a ToK subject. &amp;ldquo;How to interact with an AI?&amp;rdquo;
&lt;ul&gt;
&lt;li&gt;We need a manual on how to use AI. Like Simon Willison says&lt;/li&gt;
&lt;li&gt;Content doesn&amp;rsquo;t suffice. You need pedegogy. What to serve you at what time, how, how to assess. Lots of businesses are filling this gap&lt;/li&gt;
&lt;li&gt;Students get great confidence when a teacher points to online content and says, I&amp;quot;ll tell you WHAT to see&amp;quot; and COMPLEMENTS that in their class&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;The map is not the territory.&amp;rdquo; Most people confuse sample mean for the actual.&lt;/li&gt;
&lt;li&gt;#ASK Parameter estimation -&amp;gt; Signal estimation -&amp;gt; State estimation&lt;/li&gt;
&lt;li&gt;Stats vs DL differ in that
&lt;ul&gt;
&lt;li&gt;There is no notion of a defined &amp;ldquo;truth&amp;rdquo;. Hence reliability is not measurable&lt;/li&gt;
&lt;li&gt;Parameters have no value. Hence interpretability is ignored.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;#TODO Read 2020 National Education Policy. It&amp;rsquo;s quite modern.
&lt;ul&gt;
&lt;li&gt;We need a manual on self-learning too&lt;/li&gt;
&lt;li&gt;Listening is not learning. You know only if you implement.&lt;/li&gt;
&lt;li&gt;Levels for students:
&lt;ul&gt;
&lt;li&gt;I can solve it.&lt;/li&gt;
&lt;li&gt;I can explain why it works.&lt;/li&gt;
&lt;li&gt;I can find alternatives.&lt;/li&gt;
&lt;li&gt;I can apply it to a new area, reformulating (requires imagination.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For teachers, you also need:
&lt;ul&gt;
&lt;li&gt;Responsible learning (extra careful about what to teach and how to teach, to exceite them, to teach at THEIR level).&lt;/li&gt;
&lt;li&gt;Show the universality and connecting to other concepts. E.g. noise reduction with FT is like using water to remove dirt. Transform to water domain, remove dirt, transform back to air domain. It&amp;rsquo;s better than dusting clothes to remove clothes. Washing machine programs are just different models of removing noise in the water domain.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Teach people who WANT to learn &lt;strong&gt;AND&lt;/strong&gt; who will APPLY it long-term. That&amp;rsquo;s what maximizes impact
&lt;ul&gt;
&lt;li&gt;Grad students are more satisfying that way.&lt;/li&gt;
&lt;li&gt;Else, it is WASTED effort. (Not that it&amp;rsquo;s a bad thing for the student, but the effort &lt;em&gt;IS&lt;/em&gt; wasted for the teacher)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Therefore, I believe students should have general engineering first, and let students pick specialization later. Some universitie are doing that.&lt;/li&gt;
&lt;li&gt;#THINK Students remember my philosophy more than my content. We impart character, not just knowledge.&lt;/li&gt;
&lt;li&gt;Astrology and horoscopes serve a different function. They provide explainability, not predictive ability. As the world becomes less explainable, the need for astrology will grow.
&lt;ul&gt;
&lt;li&gt;Explainability is about creating STORIES that fits data plausibly. It has nothing to do with data or truth.&lt;/li&gt;
&lt;li&gt;Explainability and predictive ability and reproducibility are all different. Maybe, Science is about the latter two, less about explainability.&lt;/li&gt;
&lt;li&gt;Astrology is a model. The map is not the territory. It&amp;rsquo;s an explanatory, not a predictive model.&lt;/li&gt;
&lt;li&gt;#THINK Therefore, my lessons are just explanations. Stats about experiments are STILL explanations. They are NOT reproducible or predictive. Hence not yet science&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The meaning of our life is the transformation we undergo in our lives
&lt;ul&gt;
&lt;li&gt;#TODO Read &amp;ldquo;The Journey of Souls&amp;rdquo; by Michael Newton. A hypnotherapist&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;#TODO Try regression therapy / hypnosis. Record it and listen to it. Just for fun!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rohini Deshpande
&lt;ul&gt;
&lt;li&gt;Slam book was the Facebook of the 1900s&lt;/li&gt;
&lt;li&gt;Prepared mind is an extremely powerful tool for learning. Practice prepared mind&lt;/li&gt;
&lt;li&gt;When women drop out of education or career, that is also a waste from the teacher and system perspective&lt;/li&gt;
&lt;li&gt;The time for career growth is the same as child bearing time for women. That&amp;rsquo;s not true for men. But child rearing can be done by either. That&amp;rsquo;s not recognised. It&amp;rsquo;s 0K for a man to raise the child and make the home and 0K to treat that as the default&lt;/li&gt;
&lt;li&gt;Since men are more senior, it&amp;rsquo;s usually logical for them to stay in their jobs. That&amp;rsquo;s a systematic bias. When seniors advise women to step back. they respect it. That widens the barrier. Why not eliminate that situation?&lt;/li&gt;
&lt;li&gt;Be proud of the working women in the family&lt;/li&gt;
&lt;li&gt;Stats are just a symptom. They don&amp;rsquo;t explain the cause. (Map is not the territory.) Explanations are what really helps us fix the cause. Hence stories are important.&lt;/li&gt;
&lt;li&gt;Read Tinker Tailor Soldier Spy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RV Athimber health tips:
&lt;ul&gt;
&lt;li&gt;Eat foods with low glycemic index&lt;/li&gt;
&lt;li&gt;Eliminate free salt completely&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.voyageai.com/docs/embeddings&#34;&gt;Voyage AI Embeddings&lt;/a&gt; have a &lt;a href=&#34;https://blog.voyageai.com/2025/01/07/voyage-3-large/&#34;&gt;higher quality, similar price&lt;/a&gt; compared to OpenAI embeddings. There&amp;rsquo;s a clear benefit to replacing &lt;code&gt;text-embedding-3-large&lt;/code&gt; with &lt;code&gt;voyage-3-lite&lt;/code&gt;. There&amp;rsquo;s a 200 MTok free tier currently.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dvmazur/mixtral-offloading&#34;&gt;mixtral-offloading&lt;/a&gt; cleverly loads only the model layer required at any point, letting you run Mixtral 8x7b on Colab Free and on 16GB GPUs. &lt;a href=&#34;https://colab.research.google.com/gist/chigkim/5521120118fd7533a224b36a3167972f/mixtral.ipynb&#34;&gt;This notebook&lt;/a&gt; runs on Colab Free too.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.codegpt.co/&#34;&gt;CodeGPT&lt;/a&gt; is an alternative to Github Copilot that can use any LLM.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>LLMs can teach experts</title>
      <link>https://www.s-anand.net/blog/llms-can-teach-experts/</link>
      <pubDate>Thu, 02 Nov 2023 05:03:33 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/llms-can-teach-experts/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;LLMs can teach experts&#34; loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2023-11-02-computer-with-crt-monitor.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;I am a fairly good programmer. So, when I see a problem, my natural tendency is to code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m trying to break that pattern. Instead, I ask ChatGPT.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://chat.openai.com/share/1f0858cd-4768-466a-a494-c570e9debb7d&#34;&gt;For example, I asked&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write a compact 1-line Python expression that checks if &lt;code&gt;user.id&lt;/code&gt; ends with @gramener.com or @straive.com&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endswith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@gramener.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;@straive.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After 15 years of using Python, I learnt that &lt;code&gt;.endswith()&lt;/code&gt; supports tuple suffixes. This has been around since Python 2.5 (released in 2006 &amp;ndash; before I knew Python.) The documentation has a &lt;strong&gt;tiny&lt;/strong&gt; sentence in the middle saying &amp;ldquo;suffix can also be a tuple of suffixes to look for.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I checked with a few colleagues, including &lt;a href=&#34;https://www.linkedin.com/in/jaidevd/&#34;&gt;Jaidev&lt;/a&gt;. They didn&amp;rsquo;t know it either.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s small little things like this that made me conclude.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to code anymore. ChatGPT will, instead.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Maps, Delimitation, and Gerrymandering</title>
      <link>https://www.s-anand.net/blog/maps-delimitation-and-gerrymandering/</link>
      <pubDate>Sun, 15 Aug 2021 06:04:36 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/maps-delimitation-and-gerrymandering/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Maps, Delimitation, and Gerrymandering&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-56.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;https://www.youtube.com/watch?v=ql3Kz8ZjhRg&#34;&gt;delivered a talk&lt;/a&gt; at &lt;a href=&#34;https://in.pycon.org/2019/&#34;&gt;PyCon India 2019&lt;/a&gt;. My &lt;a href=&#34;https://github.com/gramener/pycon2019&#34;&gt;slides are on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a transcript of that talk.&lt;/p&gt;
&lt;div class=&#34;video-embed&#34;&gt;&lt;iframe src=&#34;https://www.youtube.com/embed/ql3Kz8ZjhRg&#34; title=&#34;YouTube video&#34; loading=&#34;lazy&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;What I&amp;rsquo;m going to be talking about is how you can get insights by joining two maps but before we go there, just some basic bookkeeping things.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-29.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;In case you&amp;rsquo;re tweeting, these are the hashtags, you probably want to be using the #PyconIndia, my hashtag my IDs, #SANAND0, you don&amp;rsquo;t need to worry about the slides, they are online. I&amp;rsquo;ve already posted on Twitter, the link to the slide deck, the slide deck that you&amp;rsquo;re using but if you desperately do want to take notes, then one small suggestion. Research has shown that taking notes on pen and paper is much better than taking notes on laptops if you want to remember stuff or on mobile phones. So this was a discovery for me. In fact, it was my discovery of the year and I&amp;rsquo;m following it diligently. Do give it a shot if you want to take notes. Let&amp;rsquo;s dive in.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-30.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;The story begins at the Karnataka elections in 2018. Say about one-eighth of the voters are Muslim, and both the Congress as well as the JD(S), were trying to get their support while on the other hand, BJP was taking potshots saying both of them are just trying to appease the community. The Hindu newspaper wanted to write a piece about how large a factor this is, and where all the Muslim vote is strong. You see, here we have a problem.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-31.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;The thing is that the proportion of the population by religion is available only at the district level or the village level, depending on where you get the data from and this is from the census. Unfortunately, elections are not conducted by the district, elections are conducted by constituency and these are two very different maps. So, I have data in one map, which shows me how many Muslims exists in a particular region and I want to see how many Muslims live in a different region on another map and even though they overlap, there really is no direct way of getting the data from one layer on to the other. So, we literally don&amp;rsquo;t know how many Muslims live in a constituency.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-32.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;So, how do we solve this problem? Well, the logical way is you could take one district and a constituency or a set of constituencies, and let’s say the district has a population of 100, out of which we know that 13% are Muslims and we want to split it evenly across a bunch of constituencies.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-33.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;We could just overlay them. So one district could cover multiple constituencies, one constituency could cover multiple districts, and there is a many to many mapping between these there is sometimes full coverage, sometimes partial coverage.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-34.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;So this district, for instance, covers at least one constituency fully and maybe this takes up about 1/3 of the total area. So I can say approximately 1/3 of the district&amp;rsquo;s population, which is that red area lives in this constituency.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-35.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Or let&amp;rsquo;s take another constituency that overlaps with this district. So, now only a portion of this constituency overlaps with this district. So in this area, which takes up maybe about 1/5, or about 20% of that district population, I can say that population lives here. In other words, we are simply making an assumption that within a district, which is the lowest level of data that you have, or if you have village data that&amp;rsquo;s far more granular, the population is uniformly distributed. That&amp;rsquo;s the basic assumption.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-36.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, what we can do is fragment each of these districts and constituencies by overlaying them and creating an intersection out of those, and reassembling those and this is a process that I call reshaping the map.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-37.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;How much of this can we do in Python? There is a library called reshaper that we put together. The reshaper Library is something that&amp;rsquo;s very work in progress by the way. You can find it &lt;a href=&#34;https://github.com/gramener/reshaper&#34;&gt;github.com/gramener/reshaper&lt;/a&gt;. It does exactly what I&amp;rsquo;m about to show you right now.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-38.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s give it a shot. I&amp;rsquo;m going to open up the &lt;a href=&#34;https://github.com/gramener/pycon2019/blob/master/ka/merge.ipynb&#34;&gt;IPython notebook&lt;/a&gt;. The library that we are going to be using for this primarily, the core library is &lt;a href=&#34;https://geopandas.org/&#34;&gt;Geopandas&lt;/a&gt;. For those of you who have been working with data, Pandas is pretty much the de-facto library to use for any kind of data processing. Geopandas is becoming that kind of a standard for any shapefile. So if you have any shapefile and you want to do any kind of geospatial processing, an easy way of doing it is Geopandas and an easy way of installing it is through Conda using Anaconda. Rather than trying to do a pip install by yourself. It&amp;rsquo;s a little more efficient on most machines. So let&amp;rsquo;s import Geopandas. Now I have a shapefile that has the Karnataka census data which will eventually appear. I&amp;rsquo;m going to load it once it appears on the screen. (Just taking a long time. Okay, there we are back again.)&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-39.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;So GPD, which is the abbreviation for Geopandas, has a &lt;code&gt;from_file&lt;/code&gt; function that lets you load any shapefile. Now, the other question you&amp;rsquo;ll have is where am I going to get these shapefiles from? We&amp;rsquo;ll come to that in a bit. It&amp;rsquo;s not as difficult as you might think. Let&amp;rsquo;s say you&amp;rsquo;ve downloaded the shapefiles. This particularly is the Karnataka census shapefile and what does this look like? Geopandas has a plotting function, which lets you see what the map looks like. So if you look at these districts, this is a pretty large district, this is Bangalore.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-40.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s take the area for these. Geopandas offers an attribute called &lt;code&gt;.geometry&lt;/code&gt;, which has an attribute called .area, which gets you the overall area of each of these regions, and if you want to look at what that data frame looks like, each of these regions corresponds to one row. So the Bagalkot district is one row, Bangalore rural district is one row and so on. All of the data in the shapefile also comes in here, you have a column called geometry, which has the additional geometry details, this is a pretty large column, which you probably won&amp;rsquo;t be going into the details of it. We&amp;rsquo;ve just now added one column called area, and this has the area of each of these regions and at the very least, you can figure out which are the larger regions, which are the smaller regions.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-44.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s do the same for the constituencies data set. So here we have the constituencies that are more, these are parliamentary constituencies, by the way, not assembly constituencies. The difference being if you&amp;rsquo;re electing someone for the parliament, it&amp;rsquo;s or an MP, then it&amp;rsquo;s a parliamentary constituency. If you&amp;rsquo;re electing them for the assembly, which is an MLA, then it&amp;rsquo;s the assembly constituency. Parliamentary constituencies are bigger. So you&amp;rsquo;ll notice that out here, there are multiple parliamentary constituencies that sit in the same region that this district sits in, but it&amp;rsquo;s not a perfect match. Again, let&amp;rsquo;s take the area and see what this looks like. We have a bunch of these parliamentary constituencies like Gulbarga, Bijapur, etc, and their respective areas.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-45.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, Geopandas has a function called &lt;code&gt;sjoin&lt;/code&gt;, which lets you take two shapefiles and create all the intersections around those shapefiles the fragments that I just showed you out here. So yeah, creating all these fragments is what the &lt;code&gt;sjoin&lt;/code&gt; function does. So, if we do that, then what it&amp;rsquo;s now done is created a new data frame called merged and that has all these shapes. Let&amp;rsquo;s validate that. So there are 30 districts and 28 constituencies, but when you overlay them, it turns out that there are 147 fragments, each of which represents an intersection of a district and a constituency. Now, given this, it should be possible to just take any metric, like the percentage of Muslim voters or the number of Muslims, the size of the Muslim population, from the district data into the data that you have on the constituencies.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-46.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;But it turns out that it&amp;rsquo;s a little trickier than that. So, you have to do a little more calculation and that&amp;rsquo;s what&amp;rsquo;s available in the reshaper library, you can take a look at the code, what it does is moves the metrics from one layer to another in a way that is seamless.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-47.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Once we have this, the result is an Excel sheet that kind of looks like this. It has all the attributes from both layers.&lt;/p&gt;
&lt;p&gt;So, it says, for instance, that this particular assembly constituency is broken up into three regions, each of which maps to different districts. So some of it overlaps with more and some of it with shift saagar some of it with data and in fact, these are across different states and what is the area of each of these, along with a variety of other metrics that you can calculate and the proportion of area that is overlapping. Once you have this kind of data set, what can we do with it? So let&amp;rsquo;s revert back to our story.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-48.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;What actually happened to the Muslim vote?&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-49.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Well, this is the constituency-wise Muslim voter population in Karnataka.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-50.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;This was used by the Hindu to publish an article around where exactly the bulk of the voters are concentrated. So, there is a chunk here, there&amp;rsquo;s a chunk here, there&amp;rsquo;s a chunk here.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-51.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, what was happening at this particular point was there was a fight for an alliance. The AIMIM, which is a Muslim party whose name is very long, and I can&amp;rsquo;t even say it fully. But they had won a number of seats in Telangana, and were looking to also participate in the Karnataka elections. They plan to contest in 60 seats. Now, to make sure that they get the Muslim vote, both JD(S) and the Congress were vying for an alliance with the party and in April 2018, AMIM decided that they will not be directly contesting in the elections, but instead would be supporting JD(S). Now, we have the results of the elections by constituency, we know the voter population by constituency. Let us see what happened to JD(S).&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-52.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Turns out that where there were more Muslim populations, JD(S) actually got lower votes. So you can see the net result of this election and the alliance.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-53.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Congress, on the other hand, had a mildly higher vote share and where there was a significantly larger voter population.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-54.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;It turns out that BJP was the one that gained the most.&lt;/p&gt;
&lt;p&gt;Now while I&amp;rsquo;m moderately okay, at Python, I&amp;rsquo;m terrible at electoral analysis. So I have no idea what this means. Okay, I&amp;rsquo;ll let you figure it out. The elections in Maharashtra and Haryana are also coming up and it turns out that Congress is aligned with AIMIM and, well, let&amp;rsquo;s just leave it at that.&lt;/p&gt;
&lt;p&gt;So, what can we do with this? What kinds of datasets exist and what is the potential of being able to join data sets across two spaces? That&amp;rsquo;s something that I&amp;rsquo;m pretty keen on.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-55.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;It turns out that in India, there are broadly three kinds of geographic hierarchies. There is a political boundary hierarchy, a postal boundary hierarchy and an administrative boundary hierarchy.&lt;/p&gt;
&lt;p&gt;By political boundary, I mean, the state parliamentary constituency, assembly constituency, going all the way down to polling booth. This has all of the results of the elections and one of the important aspects of this is that policies get made to a good extent at this level because the MPs and the MLS are focused on their respective constituencies.&lt;/p&gt;
&lt;p&gt;The second is a postal code boundary. There is a zone within which there is a sorting district within which there is a post office and there is a PIN code, there are about 110,000 of these in total.&lt;/p&gt;
&lt;p&gt;The third is the administrative boundary hierarchy. So there is a state there is a district, there&amp;rsquo;s also something called a division, but we&amp;rsquo;ll leave that aside, then there could be a sub district block or village, if it&amp;rsquo;s a rural area, or it could be municipality zone and ward if it&amp;rsquo;s a township.&lt;/p&gt;
&lt;p&gt;Now, this apart, there is one other way we can create our own hierarchies. But before that, in case you&amp;rsquo;re looking for shapefiles, for many of these, the easiest way to get the shapefile for India is to search for “Datameet maps”. Datameet is a group that it&amp;rsquo;s a discussion forum and there is a lot of active discussion on various kinds of maps, pretty much any kind of map, there&amp;rsquo;s a decent chance that you&amp;rsquo;ll find it on Datameet and if it&amp;rsquo;s not there on Datameet, ask the people, they might be able to post something, and if not, it probably just doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-56.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;But you can also create your own boundaries. If you have a single location, you can look at the area that is closest to this particular location than any other location. So for example, if this were a network of, let&amp;rsquo;s say, schools, then what is that vision that is closest to a particular school than any other school.&lt;/p&gt;
&lt;p&gt;So if I take this particular point as a school, then this red region represents all of those points which are closer to this school than any other school.&lt;/p&gt;
&lt;p&gt;This particular process is called Voronoi tessellation and is something that comes out of box with QGIS, it&amp;rsquo;s something that you can create with the command line prompt again using the reshape or library, but what that means is that now you can take literally any point and convert that into a region and the potential for that is quite high.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-57.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;So if I look at the kinds of data sets that you can create with location boundaries, right, so there&amp;rsquo;s… take all the hospitals, take all the schools, take all the bank branches, take all the petrol pumps take all the locations where crimes have been reported, take any address or take all the telephone towers, take all the locations where there are stores of a particular brand.&lt;/p&gt;
&lt;p&gt;All of these are datasets for which you can get an address and an address can be geocoded into a point. If it can be geocoded into a point, you can convert that into a region and for each of these, you naturally have some kind of data for schools, you know how many teachers or how many students that are for telecom towers, you know, which is the organization that runs that tower, potentially the telecom organization will know how many calls are flowing through it, if it&amp;rsquo;s healthcare data, you know, how many facilities that hospital has, how many patients, how many doctors, all of these are data sets that can be added to that particular cell in your respective region.&lt;/p&gt;
&lt;p&gt;But what this means, therefore, is that if we take any of these data sets that which you can create from location boundaries, or that often already exist by administrative boundaries &amp;ndash; and this is a pretty powerful set as well. Census gives us demographic data, asset ownership, who owns laptops, internet connections, TV, cars, fridges, social and religious data, economic indicators, well, income, household indicators, is the house made of a mud roof brick roof, do you have a toilet in the house not have a toilet in the house, practically every government scheme is tracked this way. So how many people have benefited from the National Rural Employment Guarantee act? Banking data is reported this way health data is reported this way.&lt;/p&gt;
&lt;p&gt;So effectively, anything that the government runs is reported by administrative boundaries. Anything that the corporate sector runs, by and large, is reported by locations. So between these two, there is enormous potential. But there&amp;rsquo;s also the fact of how decision making happens. Ultimately, political boundaries are owned, in some sense by an MP or an MLA. And, of course, there is also the associated IAS equivalents, who usually run it by administrative boundaries. So if I wanted somebody on the political side to make decisions, then I could take any of this data and put it on to the constituency boundaries. If I wanted an administrative official to make a decision, then I could take any of this data and put it on to a district. If I wanted a manager or a principal of a school, or the CEO of a hospital to make a decision, I could take all of that data and put it onto their geographic boundary.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-58.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;For example, one of the things that the Hindu again did was found that the Congress is doing much better in the agrarian areas and they did that by taking the census data, which had the percentage of farmers and mapping that on to the voter constituency regions.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-59.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;If we took, for example, census demographic data and school data, we can answer a question, where should we open new schools so that students don&amp;rsquo;t have to travel far or where there is a reasonably equal distribution of students across schools?&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-60.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;If we took economic indicators how well the country is growing versus bank branch data? Then we can answer questions like are the bank branches distributed? Based on population? That is, does every person roughly have equal access to the bank or based on wealth? Does every rupee have roughly equal access to the bank or if it&amp;rsquo;s in between? How close is it from one to the other?&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-61.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;We could find out whether increasing the district&amp;rsquo;s wealth leads to more theft. So that means people get richer. So does that mean that it does that lead to increase in crime? Or does it lead to less theft? Because the people are richer, and they don&amp;rsquo;t need to steal therefore? And these are data sets that are available and can be joined.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-62.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Similarly, with health data, does poor health lead to an increase in the number of pharmacies that are set up in that region because the pharmacies can sell more. Vice versa, if you actually set up more pharmacies? And does that have a positive impact on the people&amp;rsquo;s health in that particular region?&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-63.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Now, the reason these questions are trivial to ask, but nearly impossible to solve today is because merging the data across different kinds of layers of maps is non-trivial. But both conceptually and technologically is quite an easy exercise.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-64.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;What can we do to solve problems like this? Well, me personally, I&amp;rsquo;d love to see more of these hidden insights come out but there are a few things that you can do, literally right now.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-65.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;First, if you have an idea, take a look at these data sets, any of the data sets that you know and raise an issue on this particular repository and I’d invite all of you to share this with people. It&amp;rsquo;ll be great to see what kinds of ideas can be solved using these problems and I’d like to crowd source this to a number of people on the administrative side, on the NGO side, and on the corporate side, to create a repository that says here are things that we can do.&lt;/p&gt;
&lt;p&gt;If you want to try solving one of these and discovering your own insight, to build your own portfolio to share some useful knowledge. Then start by finding a map. Like I said, Datameet is a good place where you can find them up. You can find the reshaper library on &lt;a href=&#34;https://github.com/gramener/reshaper&#34;&gt;https://github.com/gramener/reshaper&lt;/a&gt;. The links are again, on &lt;a href=&#34;https://github.com/gramener/pycon2019&#34;&gt;https://github.com/gramener/pycon2019&lt;/a&gt;. This is the one link that you need to remember and if you find something, do share it on Twitter. Please tag me @sanand0, I&amp;rsquo;d love to share it at least with the media and get some people to understand the power of geospatial joins.&lt;/p&gt;
&lt;p&gt;If you want to contribute to the library right now it&amp;rsquo;s in a terrible state. Or if you want to learn more, I&amp;rsquo;m planning to organize a series of workshops on geospatial joins, do drop me an email. My email ID is &lt;a href=&#34;mailto:s.anand@gramener.com&#34;&gt;s.anand@gramener.com&lt;/a&gt; and I&amp;rsquo;ll mail you the workshops.&lt;br&gt;
If nothing else, if you just enjoyed the talk and you&amp;rsquo;ve learned something about it, then tweet about it. The tags are #PyconIndia2019, my ID, @sanand0. More than anything else, I&amp;rsquo;d love to see some insights come out by joining data.&lt;/p&gt;
&lt;p&gt;Happy mapping!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: So my question is, basically, I&amp;rsquo;m belonging to northeast part of India. So I&amp;rsquo;m from Assam. So what happened in terms of the documentation for this geographic data and so those are always kept in a sort of, you know, register. We call registers or something, so how we use that image processing and all like, to enable those things into a more of a like a public space?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: Okay. There are broadly three ways in which you can get this kind of data out. The first is beg, borrow, steal. Somebody in the government may have this data. So for example, if you go to the Survey of India, they sell these shape files. Of course, I&amp;rsquo;ve been trying to buy one of these shape files for the last six years now and have failed and I’ve tried it through the Prime Minister&amp;rsquo;s office and I still failed. But it&amp;rsquo;s actually easier to just walk over to the Survey of India office and give them a USB stick, and they&amp;rsquo;ll give it. So, depending on how you approach it, it may prove relatively straightforward.&lt;/p&gt;
&lt;p&gt;On the other hand, sometimes the maps don&amp;rsquo;t exist. So for example, most interesting anecdote was the former head of the postal College of Mysore was trying to create a postal map, the region of all of the PIN codes. It turns out that nobody knows what the region is that a PIN code covers. So he created that he uploaded that ISRO’s Bhuvan, and then after about a year and a half realize that people have permission to upload into ISRO but download from Bhuvan. So after one and a half years of putting all the data, the data is locked, it&amp;rsquo;s not even there. So today, what is the best source of getting PIN code data? It turns out that what people did was took various locations, geocoded them, they said, this location is at that this particular PIN code, this location is at that this particular PIN code, let&amp;rsquo;s draw a region around it using the concept of Voronoi polygons, and publish it. So the second possibility is to create such maps.&lt;/p&gt;
&lt;p&gt;The third possibility that you talked about, which is can we use image processing to detect it? Some features can be detected that way. So, for example, if you want to detect urban regions are constructed regions, that&amp;rsquo;s possible using satellite photography, if you want to locate water bodies, and whether they are growing or shrinking, so for example, in Chennai, the Chembarambakkam lake actually drying up, that&amp;rsquo;s something that you can draw a boundary around using image processing and that’s a straightforward method. But the thing is, I don&amp;rsquo;t think a single method will work for a wide variety of data sets, which is why we have many of these.&lt;/p&gt;
&lt;p&gt;But the biggest lesson that I&amp;rsquo;ve learned is that 90% of the things that we want, somebody else has usually wanted, and has managed to get their inputs. So, I find that the most efficient ways to ask and Datameet is a pretty good place to ask if somebody already has his data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: Anand, thank you very much for your talk. I&amp;rsquo;ve got a question regarding shape files. I had the requirement of using the map of India a few times and I suddenly realized that our external boundaries in a lot of places are in dispute and the kind of shape files that we get are not matching with what politically we want our file boundaries to be. So is there any official place from where we can get these shape files because the only shape file which are available are those distorted shape files, and I finally had to change the shape files myself to use it. I couldn&amp;rsquo;t find any official place from where to get the shape file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: So, the official place is the Survey of India, which claims to sell these maps like I said, for the last five, six years now I&amp;rsquo;ve been trying to buy these maps it&amp;rsquo;s actually not possible. But there are people who have succeeded and stock is being recorded, right? Okay. Let&amp;rsquo;s just say that if you go to Datameet maps, you will get unofficial but correct maps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: So, since you are in the field, shouldn&amp;rsquo;t we have a system of getting correct official maps? Isn’t there a process being put in place or something?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: I tried talking to a couple of people at the Prime Minister&amp;rsquo;s office and suggested this. They put me on the phone with the Inspector General of Surveys or some such high ranking official who said yes, absolutely, connected me to some person, who connected me to some person, who connected me to some person, who is exactly the same person I talked to in the first place. So, I don&amp;rsquo;t know. I&amp;rsquo;m sure there is a process. I don&amp;rsquo;t know it well enough.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Programming Minecraft with Websockets</title>
      <link>https://www.s-anand.net/blog/programming-minecraft-with-websockets/</link>
      <pubDate>Wed, 20 Jan 2021 03:40:09 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/programming-minecraft-with-websockets/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Programming Minecraft with Websockets&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/minecraft-incomplete-pyramid.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Minecraft lets you connect to a websocket server when you&amp;rsquo;re in a game. The server can receive and send any commands. This lets you build a bot that you can &amp;hellip; (well, I don&amp;rsquo;t know what it can do, let&amp;rsquo;s explore.)&lt;/p&gt;
&lt;p&gt;Minecraft has &lt;a href=&#34;https://minecraft.gamepedia.com/Commands&#34;&gt;commands&lt;/a&gt; you can type on a chat window. For example, type &lt;code&gt;/&lt;/code&gt; to start a command and type &lt;code&gt;setblock ~1 ~0 ~0 grass&lt;/code&gt; changes the block 1 north of you into grass. (&lt;code&gt;~&lt;/code&gt; means relative to you. Coordinates are specified as X, Y and Z.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/img/minecraft-grass-block.png&#34;&gt;&lt;img alt=&#34;Minecraft grass block&#34; loading=&#34;lazy&#34; src=&#34;https://github.com/sanand0/minecraft-websocket/raw/dev/tutorial/img/minecraft-grass-block.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note: These instructions were tested on Minecraft Bedrock 1.16. I haven&amp;rsquo;t tested them on the Java Edition.&lt;/p&gt;
&lt;div class=&#34;video-embed&#34;&gt;&lt;iframe src=&#34;https://www.youtube.com/embed/bjanNXXwQbo&#34; title=&#34;YouTube video&#34; loading=&#34;lazy&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h2 id=&#34;connect-to-minecraft&#34;&gt;Connect to Minecraft&lt;/h2&gt;
&lt;p&gt;You can send any command to Minecraft from a websocket server. Let&amp;rsquo;s use JavaScript for this.&lt;/p&gt;
&lt;p&gt;First, run &lt;code&gt;npm install ws uuid&lt;/code&gt;. (We need &lt;a href=&#34;https://npmjs.com/package/ws&#34;&gt;&lt;code&gt;ws&lt;/code&gt;&lt;/a&gt; for websockets and &lt;a href=&#34;https://npmjs.com/package/uuid&#34;&gt;&lt;code&gt;uuid&lt;/code&gt;&lt;/a&gt; to generate unique IDs.)&lt;/p&gt;
&lt;p&gt;Then create this &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver1.js&#34;&gt;&lt;code&gt;mineserver1.js&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ws&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;uuid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// For later use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Create a new websocket server on port 3000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Ready. On MineCraft chat, type /connect localhost:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;wss&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;WebSocket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3000&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// On Minecraft, when you type &amp;#34;/connect localhost:3000&amp;#34; it creates a connection
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;wss&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;connection&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Connected&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Minecraft &amp;gt; Settings &amp;gt; General &amp;gt; Profile, turn &lt;strong&gt;off&lt;/strong&gt; the &amp;ldquo;Require Encrypted Websockets&amp;rdquo; setting.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-18.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;node mineserver1.js&lt;/code&gt;. Then type &lt;code&gt;/connect localhost:3000&lt;/code&gt; in a Minecraft chat window. You&amp;rsquo;ll see 2 things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MineCraft says &amp;ldquo;Connection established to server: ws://localhost:3000&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Node prints &amp;ldquo;Connected&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, our program is connected to Minecraft, and can send/receive messages.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/img/minecraft-chat-connected.png&#34;&gt;&lt;img alt=&#34;Minecraft chat connect&#34; loading=&#34;lazy&#34; src=&#34;https://github.com/sanand0/minecraft-websocket/raw/dev/tutorial/img/minecraft-chat-connected.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Python equivalent is in &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver1.py&#34;&gt;mineserver1.py&lt;/a&gt;. Run &lt;code&gt;python mineserver1.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you get an &lt;code&gt;Uncaught Error: Cannot find module &#39;ws&#39;&lt;/code&gt;, make sure you ran &lt;code&gt;npm install ws uuid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you get an &amp;ldquo;Encrypted Session Required&amp;rdquo; error, make sure you turned off the &amp;ldquo;Require Encrypted Websockets&amp;rdquo; setting mentioned above.&lt;/li&gt;
&lt;li&gt;To disconnect, run &lt;code&gt;/connect off&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;subscribe-to-chat-messages&#34;&gt;Subscribe to chat messages&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s listen to the players&amp;rsquo; chat.&lt;/p&gt;
&lt;p&gt;A connected websocket server can send a &amp;ldquo;subscribe&amp;rdquo; message to Minecraft saying it wants to &amp;ldquo;listen&amp;rdquo; to specific actions. For example, you can subscribe to &amp;ldquo;PlayerMessage&amp;rdquo;. Whenever a player sents a chat message, Minecraft will notify the websocket client.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how to do that. Add this code in the &lt;code&gt;wss.on(&#39;connection&#39;, socket =&amp;gt; { ... })&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Tell Minecraft to send all chat messages. Required once after Minecraft starts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;header&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// We&amp;#39;re using the version 1 message protocol
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;requestId&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;uuid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;v4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// A unique ID for the request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;messageType&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandRequest&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// This is a request ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;messagePurpose&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subscribe&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// ... to subscribe to ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;eventName&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;PlayerMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// ... all player messages.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, every time a player types something in the chat window, the socket will receive it. Add this code below the above code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// When MineCraft sends a message (e.g. on player chat), print it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;packet&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;packet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code parses all the messages it receives and prints them.&lt;/p&gt;
&lt;p&gt;This code in is &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver2.js&#34;&gt;&lt;code&gt;mineserver2.js&lt;/code&gt;&lt;/a&gt;. Run &lt;code&gt;node mineserver2.js&lt;/code&gt;. Then type &lt;code&gt;/connect localhost:3000&lt;/code&gt; in a Minecraft chat window. Then type a message (e.g. &amp;ldquo;alpha&amp;rdquo;) in the chat window. You&amp;rsquo;ll see a message like this in the console.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;messagePurpose&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;event&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// This is an event
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;requestId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;00000000-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;                      &lt;span class=&#34;c1&#34;&gt;// using version 1 message protocol
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;eventName&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;PlayerMessage&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;measurements&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;AccountType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;ActiveSessionID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;e0afde71-9a15-401b-ba38-82c64a94048d&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;AppSessionID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;b2f5dddc-2a2d-4ec1-bf7b-578038967f9a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Biome&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// Plains Biome. https://minecraft.gamepedia.com/Biome
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.16.201&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// That&amp;#39;s my build
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;BuildNum&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;5131175&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;BuildPlat&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Cheevos&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;ClientId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;fcaa9859-0921-348e-bc7c-1c91b72ccec1&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;CurrentNumDevices&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;DeviceSessionId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;b2f5dddc-2a2d-4ec1-bf7b-578038967f9a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Difficulty&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;NORMAL&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// I&amp;#39;m playing on normal difficulty
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Dim&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;GlobalMultiplayerCorrelationId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;91967b8c-01c6-4708-8a31-f111ddaa8174&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;alpha&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;// This is the message I typed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;MessageType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;chat&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;// It&amp;#39;s of type chat
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;NetworkType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Plat&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Win 10.0.19041.1&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;PlayerGameMode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// Creative. https://minecraft.gamepedia.com/Commands/gamemode
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Sender&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Anand&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// That&amp;#39;s me.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;Seq&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;497&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;WorldFeature&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;WorldSessionId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;8c9b4d3b-7118-4324-ba32-c357c709d682&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;editionType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;win10&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;isTrial&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;locale&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;en_IN&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;vrMode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Python equivalent is in &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver2.py&#34;&gt;mineserver2.py&lt;/a&gt;. Run &lt;code&gt;python mineserver2.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The official Minecraft docs say that the &lt;a href=&#34;https://minecraft.gamepedia.com/Commands/wsserver#Uses&#34;&gt;MCWSS protocol is outdated&lt;/a&gt;. But it seems to work.&lt;/li&gt;
&lt;li&gt;The full list of things we can subscribe to is undocumented, but &lt;a href=&#34;https://gist.github.com/jocopa3/&#34;&gt;@jocopa3&lt;/a&gt; has reverse-engineered a &lt;a href=&#34;https://gist.github.com/jocopa3/5f718f4198f1ea91a37e3a9da468675c&#34;&gt;list of messages&lt;/a&gt; we can subscribe to, and they&amp;rsquo;re somewhat meaningful.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Sandertv/mcwss/&#34;&gt;This Go package&lt;/a&gt; has code that explores the &lt;a href=&#34;https://github.com/Sandertv/mcwss/tree/master/protocol&#34;&gt;protocol&lt;/a&gt; further.&lt;/li&gt;
&lt;li&gt;This &lt;a href=&#34;https://www.reddit.com/r/MCPE/comments/5ta719/mcpewin10_global_chat_using_websockets/&#34;&gt;chat&lt;/a&gt; has more details. There&amp;rsquo;s also an &lt;a href=&#34;https://gist.github.com/jocopa3/54b42fb6361952997c4a6e38945e306f&#34;&gt;outdated list of JSON messages&lt;/a&gt; from &lt;a href=&#34;https://gist.github.com/jocopa3/&#34;&gt;@jocopa3&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Here&amp;rsquo;s a sample program that &lt;a href=&#34;https://gist.github.com/pirosuke/1ca2aa4d8920f41dfbabcbc7dc2a669f&#34;&gt;places a block in Minecraft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;build-structures-using-chat&#34;&gt;Build structures using chat&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a pyramid of size &lt;code&gt;10&lt;/code&gt; around us when we type &lt;code&gt;pyramid 10&lt;/code&gt; in the chat window.&lt;/p&gt;
&lt;p&gt;The first step is to check if the player sent a chat message like &lt;code&gt;pyramid 10&lt;/code&gt; (or another number). Add this code below the above code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// When MineCraft sends a message (e.g. on player chat), act on it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;packet&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;packet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// If this is a chat window
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;eventName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;PlayerMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ... and it&amp;#39;s like &amp;#34;pyramid 10&amp;#34; (or some number), draw a pyramid
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;match&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;/^pyramid (\d+)/i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;draw_pyramid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the user types &amp;ldquo;pyramid 3&amp;rdquo; on the chat window, &lt;code&gt;draw_pyramid(3)&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;draw_pyramid()&lt;/code&gt;, let&amp;rsquo;s send commands to build a pyramid. To send a command, we need to create a JSON with the command (e.g. &lt;code&gt;setblock ~1 ~0 ~0 grass&lt;/code&gt;). Add this code below the above code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;header&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;requestId&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;uuid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;v4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Send unique ID each time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;messagePurpose&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandRequest&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;messageType&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandRequest&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// TODO: Needed?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandLine&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Define the command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;origin&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;player&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Message comes from player
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Send the JSON string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s write &lt;code&gt;draw_pyramid()&lt;/code&gt; to create a pyramid using glowstone by adding this code below the above code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Draw a pyramid of size &amp;#34;size&amp;#34; around the player.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;draw_pyramid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// y is the height of the pyramid. Start with y=0, and keep building up
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// At the specified y, place blocks in a rectangle of size &amp;#34;side&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`setblock ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; glowstone`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`setblock ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; glowstone`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`setblock ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; glowstone`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`setblock ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;side&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; ~&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt; glowstone`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code in is &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver3.js&#34;&gt;&lt;code&gt;mineserver3.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node mineserver3.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;/connect localhost:3000&lt;/code&gt; in a Minecraft chat window.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;pyramid 3&lt;/code&gt; in the chat window.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ll be surrounded by a glowstone pyramid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/img/minecraft-glowstone-pyramid.png&#34;&gt;&lt;img alt=&#34;Minecraft glowstone pyramid&#34; loading=&#34;lazy&#34; src=&#34;https://github.com/sanand0/minecraft-websocket/raw/dev/tutorial/img/minecraft-glowstone-pyramid.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Python equivalent is in &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver3.py&#34;&gt;mineserver3.py&lt;/a&gt;. Run &lt;code&gt;python mineserver3.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &amp;ldquo;requestId&amp;rdquo; needs to be a UUID &amp;ndash; at least for block commands. I tried unique &amp;ldquo;requestId&amp;rdquo; values like 1, 2, 3 etc. That didn&amp;rsquo;t work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;understand-minecrafts-responses&#34;&gt;Understand Minecraft&amp;rsquo;s responses&lt;/h2&gt;
&lt;p&gt;For every command you send, Minecraft sends a response. It&amp;rsquo;s &amp;ldquo;header&amp;rdquo; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;header&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;messagePurpose&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandResponse&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;// Response to your command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;requestId&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;97dee9a3-a716-4caa-aef9-ddbd642f2650&amp;#34;&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// ... and your requestId
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the command is successful, the response has &lt;code&gt;body.statusCode == 0&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusCode&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;// No error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Block placed&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// It placed the block you wanted
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;position&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;y&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;z&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// ... at this location
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the command failed, the response has a negative &lt;code&gt;body.statusCode&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusCode&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2147352576&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// This is an error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;The block couldn&amp;#39;t be placed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To print these, add this to &lt;code&gt;socket.on(&#39;message&#39;, ...)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// If we get a command response, print it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messagePurpose&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandResponse&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code in is &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver4.js&#34;&gt;&lt;code&gt;mineserver4.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node mineserver4.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;/connect localhost:3000&lt;/code&gt; in a Minecraft chat window.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;pyramid 3&lt;/code&gt; in the chat window.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ll be surrounded by a glowstone pyramid, and the &lt;strong&gt;console will show every command response&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notes on common error messages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;The block couldn&#39;t be placed&lt;/code&gt; (-2147352576): The same block was already at that location.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Syntax error: Unexpected &amp;quot;xxx&amp;quot;: at &amp;quot;~0 ~9 ~-1 &amp;gt;&amp;gt;xxx&amp;lt;&amp;lt;&amp;quot;&lt;/code&gt; (-2147483648): You gave wrong arguments to the command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Too many commands have been requested, wait for one to be done&lt;/code&gt; (-2147418109): Minecraft only allows 100 commands can be executed without waiting for their response.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CloudburstMC/Language/blob/master/en_GB.lang&#34;&gt;More error messages here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;wait-for-commands-to-be-done&#34;&gt;Wait for commands to be done&lt;/h2&gt;
&lt;p&gt;Typing &amp;ldquo;pyramid 3&amp;rdquo; works just fine. But try &amp;ldquo;pyramid 5&amp;rdquo; and your pyramid is incomplete.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/img/minecraft-incomplete-pyramid.png&#34;&gt;&lt;img alt=&#34;Minecraft incomplete pyramid&#34; loading=&#34;lazy&#34; src=&#34;https://github.com/sanand0/minecraft-websocket/raw/dev/tutorial/img/minecraft-incomplete-pyramid.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s because Minecraft only allows up to 100 messages in its queue. On the 101st message, you get a &lt;code&gt;Too many commands have been requested, wait for one to be done&lt;/code&gt; error.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;header&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;messagePurpose&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;requestId&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a5051664-e9f4-4f9f-96b8-a56b5783117b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s2&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusCode&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2147418109&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;statusMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Too many commands have been requested, wait for one to be done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So let&amp;rsquo;s modify &lt;code&gt;send()&lt;/code&gt; to add to a queue and send in batches. We&amp;rsquo;ll create two queues:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendQueue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Queue of commands to be sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Queue of responses awaited from Minecraft
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;code&gt;wss.on(&#39;connection&#39;, ...)&lt;/code&gt;, when Minecraft completes a command, we&amp;rsquo;ll remove it from the &lt;code&gt;awaitedQueue&lt;/code&gt;. If the command has an error, we&amp;rsquo;ll report it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// If we get a command response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messagePurpose&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;commandResponse&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// ... and it&amp;#39;s for an awaited command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;requestId&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Print errors 5(if any)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;statusCode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;requestId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;commandLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;statusMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ... and delete it from the awaited queue
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;delete&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;requestId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Now, we&amp;#39;ve cleared all completed commands from the awaitedQueue.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we&amp;rsquo;ve processed Minecraft&amp;rsquo;s response, we&amp;rsquo;ll send pending messages from &lt;code&gt;sendQueue&lt;/code&gt;, upto 100 and add them to the &lt;code&gt;awaitedQueue&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// We can send new commands from the sendQueue -- up to a maximum of 100.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Math&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;min&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;keys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Each time, send the first command in sendQueue, and add it to the awaitedQueue
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;awaitedQueue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;requestId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Now we&amp;#39;ve sent as many commands as we can. Wait till the next PlayerMessage/commandResponse
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, in function send(), instead of &lt;code&gt;socket.send(JSON.stringify(msg))&lt;/code&gt;, we use &lt;code&gt;sendQueue.push(msg)&lt;/code&gt; to add the message to the queue.&lt;/p&gt;
&lt;p&gt;This code in is &lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/mineserver5.js&#34;&gt;&lt;code&gt;mineserver5.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;node mineserver5.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;/connect localhost:3000&lt;/code&gt; in a Minecraft chat window.&lt;/li&gt;
&lt;li&gt;Then type &lt;code&gt;pyramid 6&lt;/code&gt; in the chat window.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ll be surrounded by a large glowstone pyramid.&lt;/li&gt;
&lt;li&gt;The console will print messages like &lt;code&gt;setblock ~0 ~6 ~0 glowstone The block couldn&#39;t be placed&lt;/code&gt; because we&amp;rsquo;re trying to place duplicate blocks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/minecraft-websocket/blob/dev/tutorial/img/minecraft-glowstone-pyramid-large.png&#34;&gt;&lt;img alt=&#34;Minecraft glowstone pyramid&#34; loading=&#34;lazy&#34; src=&#34;https://github.com/sanand0/minecraft-websocket/raw/dev/tutorial/img/minecraft-glowstone-pyramid-large.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2 id=&#34;rodland-8-mar-2021-1245-amthanks-for-a-great-tutorialhowever-when-i-try-to-implement-the-chat-listener-server2js-i-get-an-json-error-from-minecraft-in-nodejs-consolekryptert-økt-kreves--needs-secure-connection&#34;&gt;&lt;strong&gt;Rodland&lt;/strong&gt; &lt;em&gt;8 Mar 2021 12:45 am&lt;/em&gt;:Thanks for a great tutorial.However when I try to implement the chat listener (server2.js) i get an JSON error from MineCraft (in node.js console):&amp;ldquo;kryptert økt kreves&amp;rdquo; = &amp;ldquo;Needs secure connection&amp;rdquo;&lt;/h2&gt;
Ready. On MineCraft chat, type /connect localhost:3000
Connected
{
body: { statusCode: -2147418107, statusMessage: &amp;lsquo;Kryptert økt kreves&amp;rsquo; },
header: {
messagePurpose: &amp;rsquo;error&amp;rsquo;,
requestId: &amp;lsquo;3522bb53-5256-4030-b827-4b411ae72a6c&amp;rsquo;,
version: 1
}
}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;8 Mar 2021 4:07 pm&lt;/em&gt;:
Under Settings &amp;gt; General &amp;gt; Profile, please turn off the &amp;ldquo;Require Encrypted Websockets&amp;rdquo; setting. I&amp;rsquo;ve added this to the tutorial. Thanks for flagging this!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;2 Jan 2022 9:48 am&lt;/em&gt;:
That&amp;rsquo;s right. Looks like you resolved it and changed localhost to minecraft-server.warpedwartwars.repl.co 👍&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WarpedWartWars&lt;/strong&gt; &lt;em&gt;21 Jun 2022 6:48 am&lt;/em&gt;:
Got it working on localhost, using the Python mineserver3.py, but the message protocol seems to have changed, to this:
{&amp;lsquo;body&amp;rsquo;: {&amp;lsquo;message&amp;rsquo;: &amp;lsquo;pyramid 32&amp;rsquo;, &amp;lsquo;receiver&amp;rsquo;: &amp;lsquo;&amp;rsquo;, &amp;lsquo;sender&amp;rsquo;: &amp;lsquo;WarpedWartWars&amp;rsquo;, &amp;rsquo;type&amp;rsquo;: &amp;lsquo;chat&amp;rsquo;}, &amp;lsquo;header&amp;rsquo;: {&amp;rsquo;eventName&amp;rsquo;: &amp;lsquo;PlayerMessage&amp;rsquo;, &amp;lsquo;messagePurpose&amp;rsquo;: &amp;rsquo;event&amp;rsquo;, &amp;lsquo;version&amp;rsquo;: 16842752}}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WarpedWartWars&lt;/strong&gt; &lt;em&gt;15 Dec 2021 8:27 am&lt;/em&gt;:
I tried this, as it seemed to be the best guide I could find.
I made a Replit Repl: &lt;a href=&#34;https://replit.com/@WarpedWartWars/minecraft-server?v=1&#34;&gt;https://replit.com/@WarpedWartWars/minecraft-server?v=1&lt;/a&gt;
and I ran it, then tried &amp;ldquo;/connect localhost:3000&amp;rdquo; in Minecraft Bedrock 1.18.2, and I got &amp;ldquo;Could not connect to server: ws://localhost:3000&amp;rdquo;. I imagine I have to change &amp;ldquo;localhost&amp;rdquo; to something else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;someGuy&lt;/strong&gt; &lt;em&gt;23 Feb 2022 8:11 am&lt;/em&gt;:
This will be deleted in couple of days but some of the reasons people are getting issues connecting is because of UWP loopback restrictions source: &lt;a href=&#34;https://stackoverflow.com/questions/34589522/cant-see-localhost-from-uwp-app&#34;&gt;https://stackoverflow.com/questions/34589522/cant-see-localhost-from-uwp-app&lt;/a&gt;
to resolve this problem for windows: &lt;a href=&#34;https://docs.microsoft.com/en-us/minecraft/creator/documents/scriptdevelopertools&#34;&gt;https://docs.microsoft.com/en-us/minecraft/creator/documents/scriptdevelopertools&lt;/a&gt;. run this in system administrator command prompt: CheckNetIsolation.exe LoopbackExempt -a -p=S-1-15-2-1958404141-86561845-1752920682-3514627264-368642714-62675701-733520436&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
    <item>
      <title>How to extend Markdown with custom blocks</title>
      <link>https://www.s-anand.net/blog/how-to-extend-markdown-with-custom-blocks/</link>
      <pubDate>Fri, 08 Jan 2021 09:37:48 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/how-to-extend-markdown-with-custom-blocks/</guid>
      <description>&lt;p&gt;One problem I&amp;rsquo;ve had in Markdown is rendering a content in columns.&lt;/p&gt;
&lt;p&gt;On Bootstrap, the markup would look like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;...&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;...&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;How do we get that into Markdown without writing HTML?&lt;/p&gt;
&lt;p&gt;On Python, the &lt;a href=&#34;https://python-markdown.github.io/extensions/attr_list/&#34;&gt;attribute lists extension&lt;/a&gt; lets you add a class. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is some content
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{: .row}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; renders &lt;code&gt;&amp;lt;p class=&amp;quot;row&amp;quot;&amp;gt;This is some content&amp;lt;/p&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But I can&amp;rsquo;t do that to multiple paragraphs. Nor can I next content, i.e. add a &lt;code&gt;.col&lt;/code&gt; inside the &lt;code&gt;.row&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&#34;https://pypi.org/project/markdown-customblocks/&#34;&gt;markdown-customblocks&lt;/a&gt;. It&amp;rsquo;s a Python module that extends &lt;a href=&#34;https://python-markdown.github.io/&#34;&gt;Python Markdown&lt;/a&gt;. This lets me write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: row
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: row
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This translates to:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;Content in column 1&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;Content in column 2&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Better yet, we can create our own custom HTML block types. For example, this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markdown&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Markdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;customblocks&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CustomBlocksExtension&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;audio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;audio/mp3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;audio src=&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#34; type=&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;    &amp;lt;/audio&amp;gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;md&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Markdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CustomBlocksExtension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generators&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s1&#34;&gt;&amp;#39;audio&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;audio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; lets you convert this piece of Markdown:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;md&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;::: audio src=&amp;#34;mymusic.ogg&amp;#34; type=&amp;#34;audio/ogg&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;    Your browser does not support `audio`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; into this HTML:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;audio src=&amp;#34;mymusic.ogg&amp;#34; type=&amp;#34;audio/ogg&amp;#34;&amp;gt;
  Your browser does not support &amp;lt;code&amp;gt;audio&amp;lt;/code&amp;gt;.
&amp;lt;/audio&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://pypi.org/project/markdown-customblocks/&#34;&gt;markdown-customblocks&lt;/a&gt; is easily the most useful Python module I discovered last quarter.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>lxml is fast enough</title>
      <link>https://www.s-anand.net/blog/lxml-is-fast-enough/</link>
      <pubDate>Fri, 11 Dec 2020 03:12:34 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/lxml-is-fast-enough/</guid>
      <description>&lt;p&gt;Given the blazing speed of &lt;a href=&#34;https://nodejs.org/&#34;&gt;Node.js&lt;/a&gt; these days, I expected HTML parsing to be faster on Node than on Python.&lt;/p&gt;
&lt;p&gt;So I compared &lt;a href=&#34;https://lxml.de/&#34;&gt;lxml&lt;/a&gt; with &lt;a href=&#34;https://github.com/fb55/htmlparser2&#34;&gt;htmlparser2&lt;/a&gt; &amp;ndash; the fastest libraries on Python and JS in parsing the &lt;a href=&#34;https://www.reddit.com/&#34;&gt;reddit&lt;/a&gt; home page (~700KB).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lxml took ~8.6 milliseconds&lt;/li&gt;
&lt;li&gt;htmlparser2 took ~14.5 milliseconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looks like lxml is much faster. I&amp;rsquo;m likely to stick around with Python for pure HTML parsing (without JavaScript) for a while longer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;In&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;lxml.html&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;In&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timeit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tree&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;reddit.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mf&#34;&gt;8.69&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ms&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;±&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;190&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;µs&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;per&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loop&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mean&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;±&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loops&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;each&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Parser&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;htmlparser2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DomHandler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;domhandler&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;fs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;readFileSync&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;reddit.html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;handler&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DomHandler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;dom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Parser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;parser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;parser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If I run the htmlparser2 code 100 times instead of 10, it only takes 7ms per loop. The more the number of loops, the faster it parses. I guess Node.js optimizes repeated loops. But I&amp;rsquo;m only interested in the first iteration, since I&amp;rsquo;ll be parsing files only once.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>The most popular scientific Python modules</title>
      <link>https://www.s-anand.net/blog/the-most-popular-scientific-python-modules/</link>
      <pubDate>Tue, 11 Dec 2012 02:37:52 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/the-most-popular-scientific-python-modules/</guid>
      <description>&lt;p&gt;I just &lt;a href=&#34;https://gist.github.com/4244899&#34;&gt;scraped&lt;/a&gt; the &lt;a href=&#34;http://pypi.python.org/pypi?:action=browse&amp;amp;show=all&amp;amp;c=385&#34;&gt;scientific packages on pypi&lt;/a&gt;. Here are the top 50 by downloads.&lt;/p&gt; &lt;table style=&#34;color: #444; font-size: 80%&#34; class=&#34;lines numbers&#34;&gt; &lt;thead&gt; &lt;tr&gt; &lt;th&gt;Name&lt;/th&gt; &lt;th&gt;Description&lt;/th&gt; &lt;th&gt;Size&lt;/th&gt; &lt;th&gt;Downloads&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/numpy/1.6.2&#34;&gt;numpy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;NumPy: array processing for numbers, strings, records, and objects.&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;133076&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scipy/0.11.0&#34;&gt;scipy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;SciPy: Scientific Library for Python&lt;/td&gt; &lt;td&gt;7000000&lt;/td&gt; &lt;td&gt;33990&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pygraphviz/1.1&#34;&gt;pygraphviz&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python interface to Graphviz&lt;/td&gt; &lt;td&gt;99000&lt;/td&gt; &lt;td&gt;22828&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/geopy/0.94.2&#34;&gt;geopy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python Geocoding Toolbox&lt;/td&gt; &lt;td&gt;32000&lt;/td&gt; &lt;td&gt;18617&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/googlemaps/1.0.2&#34;&gt;googlemaps&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Easy geocoding, reverse geocoding, driving directions, and local search in Python via Google.&lt;/td&gt; &lt;td&gt;69000&lt;/td&gt; &lt;td&gt;15135&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Rtree/0.7.0&#34;&gt;Rtree&lt;/a&gt;&lt;/td&gt; &lt;td&gt;R-Tree spatial index for Python GIS&lt;/td&gt; &lt;td&gt;495000&lt;/td&gt; &lt;td&gt;14370&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/nltk/2.0.4&#34;&gt;nltk&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Natural Language Toolkit&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;12844&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Shapely/1.2.16&#34;&gt;Shapely&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Geometric objects, predicates, and operations&lt;/td&gt; &lt;td&gt;93000&lt;/td&gt; &lt;td&gt;12635&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyutilib.component.doc/1.0.1&#34;&gt;pyutilib.component.doc&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Documentation for the PyUtilib Component Architecture.&lt;/td&gt; &lt;td&gt;372000&lt;/td&gt; &lt;td&gt;10181&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/geojson/1.0.1&#34;&gt;geojson&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Encoder/decoder for simple GIS features&lt;/td&gt; &lt;td&gt;12000&lt;/td&gt; &lt;td&gt;9407&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/GDAL/1.9.1&#34;&gt;GDAL&lt;/a&gt;&lt;/td&gt; &lt;td&gt;GDAL: Geospatial Data Abstraction Library&lt;/td&gt; &lt;td&gt;410000&lt;/td&gt; &lt;td&gt;8957&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.audiolab/0.11.0&#34;&gt;scikits.audiolab&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A python module to make noise from numpy arrays&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;8856&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pupynere/1.0.15&#34;&gt;pupynere&lt;/a&gt;&lt;/td&gt; &lt;td&gt;NetCDF file reader and writer.&lt;/td&gt; &lt;td&gt;16000&lt;/td&gt; &lt;td&gt;8809&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.statsmodels/0.3.1&#34;&gt;scikits.statsmodels&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Statistical computations and models for use with SciPy&lt;/td&gt; &lt;td&gt;3000000&lt;/td&gt; &lt;td&gt;8761&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/munkres/1.0.5.4&#34;&gt;munkres&lt;/a&gt;&lt;/td&gt; &lt;td&gt;munkres algorithm for the Assignment Problem&lt;/td&gt; &lt;td&gt;42000&lt;/td&gt; &lt;td&gt;8409&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikit-learn/0.12.1&#34;&gt;scikit-learn&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A set of python modules for machine learning and data mining&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;7735&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/networkx/1.7&#34;&gt;networkx&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python package for creating and manipulating graphs and networks&lt;/td&gt; &lt;td&gt;1009000&lt;/td&gt; &lt;td&gt;7652&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyephem/3.7.5.1&#34;&gt;pyephem&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Scientific-grade astronomy routines&lt;/td&gt; &lt;td&gt;927000&lt;/td&gt; &lt;td&gt;7644&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/PyBrain/0.3&#34;&gt;PyBrain&lt;/a&gt;&lt;/td&gt; &lt;td&gt;PyBrain is the swiss army knife for neural networking.&lt;/td&gt; &lt;td&gt;255000&lt;/td&gt; &lt;td&gt;7313&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.learn/0.8.1&#34;&gt;scikits.learn&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A set of python modules for machine learning and data mining&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;7088&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.seisan/0.5.1&#34;&gt;obspy.seisan&lt;/a&gt;&lt;/td&gt; &lt;td&gt;SEISAN read support for ObsPy.&lt;/td&gt; &lt;td&gt;3000000&lt;/td&gt; &lt;td&gt;6990&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.wav/0.5.1&#34;&gt;obspy.wav&lt;/a&gt;&lt;/td&gt; &lt;td&gt;WAV(audio) read and write support for ObsPy.&lt;/td&gt; &lt;td&gt;241000&lt;/td&gt; &lt;td&gt;6985&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.seishub/0.5.1&#34;&gt;obspy.seishub&lt;/a&gt;&lt;/td&gt; &lt;td&gt;SeisHub database client for ObsPy.&lt;/td&gt; &lt;td&gt;237000&lt;/td&gt; &lt;td&gt;6941&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.sh/0.5.2&#34;&gt;obspy.sh&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Q and ASC (Seismic Handler) read and write support for ObsPy.&lt;/td&gt; &lt;td&gt;285000&lt;/td&gt; &lt;td&gt;6926&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/crcmod/1.7&#34;&gt;crcmod&lt;/a&gt;&lt;/td&gt; &lt;td&gt;CRC Generator&lt;/td&gt; &lt;td&gt;128000&lt;/td&gt; &lt;td&gt;6714&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.fissures/0.4.7&#34;&gt;obspy.fissures&lt;/a&gt;&lt;/td&gt; &lt;td&gt;DHI/Fissures request client for ObsPy.&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;6339&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/stsci.distutils/0.3.1&#34;&gt;stsci.distutils&lt;/a&gt;&lt;/td&gt; &lt;td&gt;distutils/packaging-related utilities used by some of STScI&#39;s packages&lt;/td&gt; &lt;td&gt;25000&lt;/td&gt; &lt;td&gt;6215&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyopencl/2012.1&#34;&gt;pyopencl&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python wrapper for OpenCL&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;6124&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Kivy/1.4.1&#34;&gt;Kivy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A software library for rapid development of hardware-accelerated multitouch applications.&lt;/td&gt; &lt;td&gt;11000000&lt;/td&gt; &lt;td&gt;5879&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/speech/0.5.2&#34;&gt;speech&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A clean interface to Windows speech recognition and text-to-speech capabilities.&lt;/td&gt; &lt;td&gt;17000&lt;/td&gt; &lt;td&gt;5809&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/patsy/0.1.0&#34;&gt;patsy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A Python package for describing statistical models and for building design matrices.&lt;/td&gt; &lt;td&gt;276000&lt;/td&gt; &lt;td&gt;5517&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/periodictable/1.3.0&#34;&gt;periodictable&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Extensible periodic table of the elements&lt;/td&gt; &lt;td&gt;775000&lt;/td&gt; &lt;td&gt;5498&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pymorphy/0.5.6&#34;&gt;pymorphy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Morphological analyzer (POS tagger + inflection engine) for Russian and English (+perhaps German) languages.&lt;/td&gt; &lt;td&gt;70000&lt;/td&gt; &lt;td&gt;5174&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/imposm.parser/1.0.3&#34;&gt;imposm.parser&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Fast and easy OpenStreetMap XML/PBF parser.&lt;/td&gt; &lt;td&gt;31000&lt;/td&gt; &lt;td&gt;4940&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/hcluster/0.2.0&#34;&gt;hcluster&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A hierarchical clustering package for Scipy.&lt;/td&gt; &lt;td&gt;442000&lt;/td&gt; &lt;td&gt;4761&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.core/0.7.1&#34;&gt;obspy.core&lt;/a&gt;&lt;/td&gt; &lt;td&gt;ObsPy - a Python framework for seismological observatories.&lt;/td&gt; &lt;td&gt;487000&lt;/td&gt; &lt;td&gt;4608&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Pyevolve/0.5&#34;&gt;Pyevolve&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A complete python genetic algorithm framework&lt;/td&gt; &lt;td&gt;99000&lt;/td&gt; &lt;td&gt;4509&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.ann/0.2.dev-r803&#34;&gt;scikits.ann&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Approximate Nearest Neighbor library wrapper for Numpy&lt;/td&gt; &lt;td&gt;82000&lt;/td&gt; &lt;td&gt;4368&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.imaging/0.7.0&#34;&gt;obspy.imaging&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Plotting routines for ObsPy.&lt;/td&gt; &lt;td&gt;324000&lt;/td&gt; &lt;td&gt;4356&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.xseed/0.7.0&#34;&gt;obspy.xseed&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Dataless SEED, RESP and XML-SEED read and write support for ObsPy.&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;4331&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.sac/0.7.0&#34;&gt;obspy.sac&lt;/a&gt;&lt;/td&gt; &lt;td&gt;SAC read and write support for ObsPy.&lt;/td&gt; &lt;td&gt;306000&lt;/td&gt; &lt;td&gt;4319&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.arclink/0.7.1&#34;&gt;obspy.arclink&lt;/a&gt;&lt;/td&gt; &lt;td&gt;ArcLink/WebDC client for ObsPy.&lt;/td&gt; &lt;td&gt;247000&lt;/td&gt; &lt;td&gt;4164&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.iris/0.7.0&#34;&gt;obspy.iris&lt;/a&gt;&lt;/td&gt; &lt;td&gt;IRIS Web service client for ObsPy.&lt;/td&gt; &lt;td&gt;261000&lt;/td&gt; &lt;td&gt;4153&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Orange/2.5a4&#34;&gt;Orange&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Machine learning and interactive data mining toolbox.&lt;/td&gt; &lt;td&gt;14000000&lt;/td&gt; &lt;td&gt;4099&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/obspy.neries/0.7.0&#34;&gt;obspy.neries&lt;/a&gt;&lt;/td&gt; &lt;td&gt;NERIES Web service client for ObsPy.&lt;/td&gt; &lt;td&gt;239000&lt;/td&gt; &lt;td&gt;4066&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pandas/0.9.1&#34;&gt;pandas&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Powerful data structures for data analysis, time series,and statistics&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;4037&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pycuda/2012.1&#34;&gt;pycuda&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python wrapper for Nvidia CUDA&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;4030&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/GeoAlchemy/0.7.1&#34;&gt;GeoAlchemy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Using SQLAlchemy with Spatial Databases&lt;/td&gt; &lt;td&gt;159000&lt;/td&gt; &lt;td&gt;3881&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyfits/3.1&#34;&gt;pyfits&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Reads FITS images and tables into numpy arrays and manipulates FITS headers&lt;/td&gt; &lt;td&gt;748000&lt;/td&gt; &lt;td&gt;3746&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/HTSeq/0.5.3p7&#34;&gt;HTSeq&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A framework to process and analyze data from high-throughput sequencing (HTS) assays&lt;/td&gt; &lt;td&gt;523000&lt;/td&gt; &lt;td&gt;3720&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyopencv/2.1.0.wr1.2.0&#34;&gt;pyopencv&lt;/a&gt;&lt;/td&gt; &lt;td&gt;PyOpenCV - A Python wrapper for OpenCV 2.x using Boost.Python and NumPy&lt;/td&gt; &lt;td&gt;354000&lt;/td&gt; &lt;td&gt;3660&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/thredds/0.1.5&#34;&gt;thredds&lt;/a&gt;&lt;/td&gt; &lt;td&gt;THREDDS catalog generator.&lt;/td&gt; &lt;td&gt;25000&lt;/td&gt; &lt;td&gt;3622&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/hachoir-subfile/0.5.3&#34;&gt;hachoir-subfile&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Find subfile in any binary stream&lt;/td&gt; &lt;td&gt;16000&lt;/td&gt; &lt;td&gt;3540&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/fluid/0.1.7&#34;&gt;fluid&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Procedures to study geophysical fluids on Python.&lt;/td&gt; &lt;td&gt;210000&lt;/td&gt; &lt;td&gt;3520&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pygeocoder/1.1.4&#34;&gt;pygeocoder&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python interface for Google Geocoding API V3. Can be used to easily geocode, reverse geocode, validate and format addresses.&lt;/td&gt; &lt;td&gt;7000&lt;/td&gt; &lt;td&gt;3514&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/csc-pysparse/1.1.1.4&#34;&gt;csc-pysparse&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A fast sparse matrix library for Python (Commonsense Computing version)&lt;/td&gt; &lt;td&gt;111000&lt;/td&gt; &lt;td&gt;3455&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/topex/0.1&#34;&gt;topex&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A very simple library to interpret and load TOPEX/JASON altimetry data&lt;/td&gt; &lt;td&gt;7000&lt;/td&gt; &lt;td&gt;3378&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/arrayterator/1.0.1&#34;&gt;arrayterator&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Buffered iterator for big arrays.&lt;/td&gt; &lt;td&gt;7000&lt;/td&gt; &lt;td&gt;3320&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/python-igraph/0.6&#34;&gt;python-igraph&lt;/a&gt;&lt;/td&gt; &lt;td&gt;High performance graph data structures and algorithms&lt;/td&gt; &lt;td&gt;3000000&lt;/td&gt; &lt;td&gt;3260&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/csvkit/0.5.0&#34;&gt;csvkit&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A library of utilities for working with CSV, the king of tabular file formats.&lt;/td&gt; &lt;td&gt;29000&lt;/td&gt; &lt;td&gt;3236&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/PyVISA/1.3&#34;&gt;PyVISA&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python VISA bindings for GPIB, RS232, and USB instruments&lt;/td&gt; &lt;td&gt;237000&lt;/td&gt; &lt;td&gt;3201&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Quadtree/0.1.2&#34;&gt;Quadtree&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Quadtree spatial index for Python GIS&lt;/td&gt; &lt;td&gt;40000&lt;/td&gt; &lt;td&gt;3000&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/ProxyHTTPServer/0.0.1&#34;&gt;ProxyHTTPServer&lt;/a&gt;&lt;/td&gt; &lt;td&gt;ProxyHTTPServer -- from the creator of PyWebRun&lt;/td&gt; &lt;td&gt;3000&lt;/td&gt; &lt;td&gt;2991&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/mpmath/0.17&#34;&gt;mpmath&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python library for arbitrary-precision floating-point arithmetic&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;2901&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/bigfloat/0.2.1&#34;&gt;bigfloat&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Arbitrary precision correctly-rounded floating point arithmetic, via MPFR.&lt;/td&gt; &lt;td&gt;126000&lt;/td&gt; &lt;td&gt;2879&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/SimPy/2.3.1&#34;&gt;SimPy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Event discrete, process based simulation for Python.&lt;/td&gt; &lt;td&gt;5000000&lt;/td&gt; &lt;td&gt;2871&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Delny/0.4.1&#34;&gt;Delny&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Delaunay triangulation&lt;/td&gt; &lt;td&gt;18000&lt;/td&gt; &lt;td&gt;2790&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pymc/2.2&#34;&gt;pymc&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Markov Chain Monte Carlo sampling toolkit.&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;2727&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/PyBUFR/0.4&#34;&gt;PyBUFR&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Pure Python library to encode and decode BUFR.&lt;/td&gt; &lt;td&gt;10000&lt;/td&gt; &lt;td&gt;2676&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/collective.geo.bundle/0.1&#34;&gt;collective.geo.bundle&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Plone Maps (collective.geo)&lt;/td&gt; &lt;td&gt;11000&lt;/td&gt; &lt;td&gt;2676&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/dap/2.2.6.7&#34;&gt;dap&lt;/a&gt;&lt;/td&gt; &lt;td&gt;DAP (Data Access Protocol) client and server for Python.&lt;/td&gt; &lt;td&gt;125000&lt;/td&gt; &lt;td&gt;2598&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/rq/0.3.2&#34;&gt;rq&lt;/a&gt;&lt;/td&gt; &lt;td&gt;RQ is a simple, lightweight, library for creating background jobs, and processing them.&lt;/td&gt; &lt;td&gt;29000&lt;/td&gt; &lt;td&gt;2590&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyinterval/1.0b21&#34;&gt;pyinterval&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Interval arithmetic in Python&lt;/td&gt; &lt;td&gt;397000&lt;/td&gt; &lt;td&gt;2558&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/StarCluster/0.93.3&#34;&gt;StarCluster&lt;/a&gt;&lt;/td&gt; &lt;td&gt;StarCluster is a utility for creating and managing computing clusters hosted on Amazon&#39;s Elastic Compute Cloud (EC2).&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;2521&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/fisher/0.1.4&#34;&gt;fisher&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Fast Fisher&#39;s Exact Test&lt;/td&gt; &lt;td&gt;43000&lt;/td&gt; &lt;td&gt;2503&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/mathdom/0.8&#34;&gt;mathdom&lt;/a&gt;&lt;/td&gt; &lt;td&gt;MathDOM - Content MathML in Python&lt;/td&gt; &lt;td&gt;169000&lt;/td&gt; &lt;td&gt;2482&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/img2txt/2008.11.20&#34;&gt;img2txt&lt;/a&gt;&lt;/td&gt; &lt;td&gt;superseded by asciiporn, http://pypi.python.org/pypi/asciiporn&lt;/td&gt; &lt;td&gt;443000&lt;/td&gt; &lt;td&gt;2436&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/DendroPy/3.12.0&#34;&gt;DendroPy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A Python library for phylogenetics and phylogenetic computing: reading, writing, simulation, processing and manipulation of phylogenetic trees (phylogenies) and characters.&lt;/td&gt; &lt;td&gt;6000000&lt;/td&gt; &lt;td&gt;2349&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/geolocator/0.1.1&#34;&gt;geolocator&lt;/a&gt;&lt;/td&gt; &lt;td&gt;geolocator library: locate places and calculate distances between them&lt;/td&gt; &lt;td&gt;26000&lt;/td&gt; &lt;td&gt;2342&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/MyProxyClient/1.3.0&#34;&gt;MyProxyClient&lt;/a&gt;&lt;/td&gt; &lt;td&gt;MyProxy Client&lt;/td&gt; &lt;td&gt;67000&lt;/td&gt; &lt;td&gt;2325&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/PyUblas/2011.1&#34;&gt;PyUblas&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Seamless Numpy-UBlas interoperability&lt;/td&gt; &lt;td&gt;51000&lt;/td&gt; &lt;td&gt;2252&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/oroboros/20080712&#34;&gt;oroboros&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Astrology software&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;2228&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/textmining/1.0&#34;&gt;textmining&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python Text Mining Utilities&lt;/td&gt; &lt;td&gt;1000000&lt;/td&gt; &lt;td&gt;2198&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.talkbox/0.2.5&#34;&gt;scikits.talkbox&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Talkbox, a set of python modules for speech/signal processing&lt;/td&gt; &lt;td&gt;147000&lt;/td&gt; &lt;td&gt;2188&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/asciitable/0.8.0&#34;&gt;asciitable&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Extensible ASCII table reader and writer&lt;/td&gt; &lt;td&gt;312000&lt;/td&gt; &lt;td&gt;2160&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/scikits.samplerate/0.3.3&#34;&gt;scikits.samplerate&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A python module for high quality audio resampling&lt;/td&gt; &lt;td&gt;368000&lt;/td&gt; &lt;td&gt;2151&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/tabular/0.0.8&#34;&gt;tabular&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Tabular data container and associated convenience routines in Python&lt;/td&gt; &lt;td&gt;52000&lt;/td&gt; &lt;td&gt;2114&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pywcs/1.10-4.7&#34;&gt;pywcs&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python wrappers to WCSLIB&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;2081&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/DeliciousAPI/1.6.7&#34;&gt;DeliciousAPI&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Unofficial Python API for retrieving data from Delicious.com&lt;/td&gt; &lt;td&gt;19000&lt;/td&gt; &lt;td&gt;2038&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/hachoir-regex/1.0.5&#34;&gt;hachoir-regex&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Manipulation of regular expressions (regex)&lt;/td&gt; &lt;td&gt;31000&lt;/td&gt; &lt;td&gt;2031&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/Kamaelia/0.6.0&#34;&gt;Kamaelia&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Kamaelia - Multimedia &amp;amp; Server Development Kit&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;2007&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/seawater/2.0.1&#34;&gt;seawater&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Seawater Libray for Python&lt;/td&gt; &lt;td&gt;2000000&lt;/td&gt; &lt;td&gt;1985&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/descartes/1.0&#34;&gt;descartes&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Use geometric objects as matplotlib paths and patches&lt;/td&gt; &lt;td&gt;3000&lt;/td&gt; &lt;td&gt;1983&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/vectorformats/0.1&#34;&gt;vectorformats&lt;/a&gt;&lt;/td&gt; &lt;td&gt;geographic data serialization/deserialization library&lt;/td&gt; &lt;td&gt;10000&lt;/td&gt; &lt;td&gt;1949&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/PyMT/0.5.1&#34;&gt;PyMT&lt;/a&gt;&lt;/td&gt; &lt;td&gt;A framework for making accelerated multitouch UI&lt;/td&gt; &lt;td&gt;18000000&lt;/td&gt; &lt;td&gt;1945&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/times/0.6&#34;&gt;times&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Times is a small, minimalistic, Python library for dealing with time conversions between universal time and arbitrary timezones.&lt;/td&gt; &lt;td&gt;4000&lt;/td&gt; &lt;td&gt;1929&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/CocoPy/1.1.0rc&#34;&gt;CocoPy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Python implementation of the famous CoCo/R LL(k) compiler generator.&lt;/td&gt; &lt;td&gt;302000&lt;/td&gt; &lt;td&gt;1913&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/django-shapes/0.2.0&#34;&gt;django-shapes&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Upload and export shapefiles using GeoDjango.&lt;/td&gt; &lt;td&gt;9000&lt;/td&gt; &lt;td&gt;1901&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/sympy/0.7.2&#34;&gt;sympy&lt;/a&gt;&lt;/td&gt; &lt;td&gt;Computer algebra system (CAS) in Python&lt;/td&gt; &lt;td&gt;5000000&lt;/td&gt; &lt;td&gt;1842&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href=&#34;http://pypi.python.org/pypi/pyfasta/0.4.5&#34;&gt;pyfasta&lt;/a&gt;&lt;/td&gt; &lt;td&gt;fast, memory-efficient, pythonic (and command-line) access to fasta sequence files&lt;/td&gt; &lt;td&gt;14000&lt;/td&gt; &lt;td&gt;1836&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ron Z&lt;/strong&gt; &lt;em&gt;25 Jun 2013 10:19 pm&lt;/em&gt;:
Another good one is simpleCV:
&lt;a href=&#34;http://www.simplecv.org/&#34;&gt;http://www.simplecv.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ravindranath M&lt;/strong&gt; &lt;em&gt;8 Apr 2013 7:13 am&lt;/em&gt;:
Nice list Anand. Very useful.
&amp;ndash; This is Ravi from Comviva, who attended your introduction.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
    <item>
      <title>Inspecting code in Python</title>
      <link>https://www.s-anand.net/blog/inspecting-code-in-python/</link>
      <pubDate>Tue, 04 Sep 2012 03:49:08 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/inspecting-code-in-python/</guid>
      <description>&lt;p&gt;Lisp users would laugh, since they have &lt;a href=&#34;http://en.wikipedia.org/wiki/Macro_(computer_science)&#34;&gt;macros&lt;/a&gt;, but Python supports some basic code inspection and modification.&lt;/p&gt;
&lt;p&gt;Consider the following pieces of code:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;margin = lambda v: 1 - v[&amp;#39;cost&amp;#39;] / v[&amp;#39;sales&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What if you wanted another function that lists all the dictionary indices used in the function? That is, you wanted to extract &lt;code&gt;cost&lt;/code&gt; and &lt;code&gt;sales&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;This is a real-life problem I encountered this morning. I have 100 functions, each defining a metric. For example,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;lambda v: v[&#39;X&#39;] + v[&#39;Y&#39;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lambda v: v[&#39;X&#39;] - v[&#39;Z&#39;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lambda v: (v[&#39;X&#39;] + v[&#39;Y&#39;]) / v[&#39;Z&#39;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I had to plot the functions, as well as each of the corresponding elements (&amp;lsquo;X&amp;rsquo;, &amp;lsquo;Y&amp;rsquo; and &amp;lsquo;Z&amp;rsquo;) in the formula.&lt;/p&gt;
&lt;p&gt;Two options. One: along with each formula, maintain a list of the elements used. Two: figure it out automatically.&lt;/p&gt;
&lt;p&gt;Each function has a &lt;code&gt;func_code&lt;/code&gt; attribute. So, when you take&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;margin = lambda v: 1 - v[&amp;#39;cost&amp;#39;] / v[&amp;#39;sales&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;margin.func_code&lt;/code&gt; is a &amp;ldquo;code object&amp;rdquo;. This has a bunch of interesting attributes, one of which is &lt;code&gt;co_consts&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt;&amp;gt;&amp;gt; margin.func_code.co_consts
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;None, 1, &lt;span class=&#34;s1&#34;&gt;&amp;#39;cost&amp;#39;&lt;/span&gt;, &lt;span class=&#34;s1&#34;&gt;&amp;#39;sales&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There &amp;ndash; I just pick the strings out of that list and we&amp;rsquo;re done (for simple functions at least.)&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&#34;http://docs.python.org/reference/datamodel.html&#34;&gt;http://docs.python.org/reference/datamodel.html&lt;/a&gt; and search for &lt;code&gt;func_&lt;/code&gt; &amp;ndash; you&amp;rsquo;ll find a number of interesting things you can do with functions, such as&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Finding and changing the default parameters&lt;/li&gt;
&lt;li&gt;Accessing the global variables of the namespace where the function was defined (!)&lt;/li&gt;
&lt;li&gt;Replacing the function code with new code&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also search for &lt;code&gt;co_&lt;/code&gt; &amp;ndash; you&amp;rsquo;ll find some even more interesting things you can do with the code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find all local variable names&lt;/li&gt;
&lt;li&gt;Find all constants used in the code&lt;/li&gt;
&lt;li&gt;Find the filename and line number where the code was compiled from&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Python also comes with a disassembly module &lt;a href=&#34;http://docs.python.org/library/dis.html&#34;&gt;dis&lt;/a&gt;. A look at its &lt;a href=&#34;http://svn.python.org/projects/python/trunk/Lib/dis.py&#34;&gt;source&lt;/a&gt; is instructive.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kamaal&lt;/strong&gt; &lt;em&gt;4 Sep 2012 7:29 am&lt;/em&gt;:
This is cool. But Python needs to get Multiline Lambdas.
One of the things Higher order Perl programmers miss in Python are muliline lamdas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;4 Sep 2012 11:40 am&lt;/em&gt;:
Yeah &amp;ndash; I miss that too. But I guess it&amp;rsquo;d go too strongly against the Python ethos of readability. I find it interesting that I miss multi-line lambdas ONLY when writing code. Never when reading it. So guess it isn&amp;rsquo;t too bad a thing, given that I&amp;rsquo;m reading (my own, often) code 90% of the time, and writing it less than 10% :-)&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
  </channel>
</rss>
