<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Aniruddha Adhikary]]></title><description><![CDATA[Hi there! Ani here. I am a Polyglot Software Engineer hacking away from the sunny shores of Singapore 🇸🇬.

> Whatever you read here, are my opinions in my per]]></description><link>https://blog.adhikary.net</link><generator>RSS for Node</generator><lastBuildDate>Sat, 16 May 2026 14:57:05 GMT</lastBuildDate><atom:link href="https://blog.adhikary.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Matching HS Codes in 2024: Traversing the Customs Space]]></title><description><![CDATA[HS (Harmonised System) Codes help classify customs authorities and businesses around the world to ensure appropriate import/export control. This system recursively classifies a product into finer granularity of categories.

Figure 1: A simple exercis...]]></description><link>https://blog.adhikary.net/matching-hs-codes-in-2024-traversing-the-customs-space</link><guid isPermaLink="true">https://blog.adhikary.net/matching-hs-codes-in-2024-traversing-the-customs-space</guid><category><![CDATA[llm]]></category><category><![CDATA[openai]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Thu, 29 Feb 2024 01:32:51 GMT</pubDate><content:encoded><![CDATA[<p>HS (Harmonised System) Codes help classify customs authorities and businesses around the world to ensure appropriate import/export control. This system recursively classifies a product into finer granularity of categories.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*2EbKtoAZ4EKdadODMHTdLQ.png" alt /></p>
<p>Figure 1: A simple exercise of coding a RAM module.</p>
<p>Could we do this differently with the linguistic tools like LLMs in 2024? This blog examines different approaches towards classification.</p>
<h3 id="heading-methodology-of-classification">Methodology of Classification</h3>
<p>Assigning a HS Code is done <strong>hierarchically</strong>.</p>
<p>Starting off from Chapters, to Sections to further granularities. If we consider this as a search problem, the search domain keeps shrinking as we continue the “process of selection”. i.e., as soon as we classify a product to be an electrical component, we don’t need to keep Wines in the search space.</p>
<p>A graph could be a great solution to this problem!</p>
<h3 id="heading-resources-at-our-disposal">Resources at our Disposal</h3>
<p>We are focusing on classifying according to the definitions set by Singapore Customs.</p>
<ul>
<li><p><a target="_blank" href="https://file.go.gov.sg/stcced2022.pdf">Singapore Trade Classification, Customs &amp; Excise Duties (STCCED) 2022</a></p>
</li>
<li><p><a target="_blank" href="https://file.go.gov.sg/customs-ruling-database.pdf">Customs Ruling Dataset</a></p>
</li>
<li><p><a target="_blank" href="https://file.go.gov.sg/productguide.pdf">Guide for Classifying Products</a></p>
</li>
</ul>
<h3 id="heading-constructing-a-graph">Constructing a Graph</h3>
<p>STCCED, as the name suggests, contains the hierarchical classification of traded goods. It is a PDF file, and the text is divided into Sections, Chapters and “Subchapters”.</p>
<p><strong>Step 1:</strong> ⬇️ Download the STCCED 2022 PDF, use <code>PyPDF2</code> to extract the text content.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*3IY79gjFKZOtGYePe4v-4Q.png" alt /></p>
<p>Step 1: Raw text content of STCCED</p>
<p><strong>Step 2:</strong> ✂️ Split the text content recursively, into Sections, Chapters and “Subchapters”.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*kQlAvQYX3dnAY_BMsctF0A.png" alt /></p>
<p>Step 2: The recursively split STCCED!</p>
<p><strong>Step 3:</strong> Convert all the subchapters into GraphViz <code>dot</code> files. (Compact representation of parent-child relationships). I used <code>gpt-4</code> to read the sections and construct these subgraphs.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*1E4ydTWJZfNH1GErYwzVvA.png" alt /></p>
<p>Super-interesting prompt that converted chapter text into GraphViz</p>
<p><strong>Step 4:</strong> Merge the subgraphs hierarchically. The result, is a Graph of 13K+ Nodes, neatly organised!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709170706820/7f3c53b5-f680-46e7-ac8a-08f23c16fe9a.gif" alt class="image--center mx-auto" /></p>
<p>Zooming into the STCCED 2022 Graph!</p>
<h3 id="heading-building-a-hierarchical-search">Building a Hierarchical Search</h3>
<p>For each granularity level (Section, Chapter, Subchapter, Dash and Double Dash), I sent requests to <code>gpt-4</code> directly with a list of the child nodes. Perhaps this illustration will be of assistance!</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*X2PCvtjo-SyH1UeAoXRxdA.gif" alt /></p>
<p>Illustration of traversing root -&gt; Section -&gt; Chapter…</p>
<p>Thus, progressive granularity would shrink the total search space down.</p>
<h3 id="heading-giving-it-some-llm-and-streamlit">Giving it some LLM and Streamlit</h3>
<p>For the first build, I used <code>openai</code> directly and got <code>streamlit</code> to create the user-interface.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*iOb6V0ecASnIAQi5mdrj_Q.png" alt /></p>
<p>Try it now on <strong>Streamlit</strong>:</p>
<p>Demo: 🌏 <a target="_blank" href="https://harmony-ai.streamlit.app/">https://harmony-ai.streamlit.app/</a><br />GitHub: 🔗 <a target="_blank" href="https://github.com/aniruddha-adhikary/harmony">https://github.com/aniruddha-adhikary/harmony</a></p>
<h3 id="heading-limitations-and-future-work">Limitations and Future Work</h3>
<ol>
<li><p>The current implementation does not go backwards to course-correct. Thus it continues on with a bad classification in a higher granularity.</p>
</li>
<li><p>More tokens may be saved by combining vector search along-side graphs for nodes with larger number of children.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Jan AI: Using Desktop LLMs with Langchain or llama-index]]></title><description><![CDATA[Jan allows you to deploy and run LLMs on your Windows or macOS computer! 16 Gigabytes of memory and a M1 chip was enough for me to run Mistral locally. Now how do you take Jan and use libraries like Langchain?
https://jan.ai
 
Local API Server
Click ...]]></description><link>https://blog.adhikary.net/jan-ai-using-desktop-llms-with-langchain-or-llama-index</link><guid isPermaLink="true">https://blog.adhikary.net/jan-ai-using-desktop-llms-with-langchain-or-llama-index</guid><category><![CDATA[openai]]></category><category><![CDATA[MistralAI]]></category><category><![CDATA[langchain]]></category><category><![CDATA[LlamaIndex]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sat, 24 Feb 2024 16:02:14 GMT</pubDate><content:encoded><![CDATA[<p><code>Jan</code> allows you to deploy and run LLMs on your Windows or macOS computer! 16 Gigabytes of memory and a M1 chip was enough for me to run Mistral locally. Now how do you take Jan and use libraries like <code>Langchain</code>?</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://jan.ai">https://jan.ai</a></div>
<p> </p>
<h1 id="heading-local-api-server">Local API Server</h1>
<p>Click the <code>[&lt;&gt;]</code> icon to open the API Server pane. Click "<strong>Start Server</strong>".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708789750036/753cb143-ef78-4bb5-9eea-bf3726154d7f.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-openai-environment-variables">OpenAI Environment Variables</h1>
<p>Jan AI exposes an Open-AI compatible <code>/chat/completions</code> endpoint. That means, you can convert your existing LLM applications to run on locally hosted models through configuring the <code>OPENAI_API_BASE</code> environment variable.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> OPENAI_API_BASE=http://127.0.0.1:1337/v1
</code></pre>
<p>Granted, if your library or application relies on the Python/Node.js <code>openai</code> package.</p>
<blockquote>
<p>If you are using Langchain or llama-index, this is enough!</p>
</blockquote>
<p>And for the API key, well you don't need one. It can be any random value.</p>
]]></content:encoded></item><item><title><![CDATA[Hacking with Words: Exploiting Vulnerabilities in LLMs (PyCon Thailand)]]></title><description><![CDATA[My talk at PyCon Thailand 2023 on the security aspects and possible attack vectors of LLM Applications, tailored to both product people and engineers!
https://youtu.be/_fvk_Qa5OsM
 
Thank you PyCon TH team!]]></description><link>https://blog.adhikary.net/hacking-with-words-exploiting-vulnerabilities-in-llms-pycon-thailand</link><guid isPermaLink="true">https://blog.adhikary.net/hacking-with-words-exploiting-vulnerabilities-in-llms-pycon-thailand</guid><category><![CDATA[talks]]></category><category><![CDATA[llm]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Thu, 15 Feb 2024 23:48:58 GMT</pubDate><content:encoded><![CDATA[<p>My talk at PyCon Thailand 2023 on the security aspects and possible attack vectors of LLM Applications, tailored to both product people and engineers!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/_fvk_Qa5OsM">https://youtu.be/_fvk_Qa5OsM</a></div>
<p> </p>
<p>Thank you PyCon TH team!</p>
]]></content:encoded></item><item><title><![CDATA[AI Agent as my property agent?]]></title><description><![CDATA[Finding a flat for rent could be tiring. Ranging from non-responsive agents to landlords with particular demographic preferences, getting a new home always feels like a drag. Unless... We had an AI Agent do the scheduling.

Overview

This post is a t...]]></description><link>https://blog.adhikary.net/ai-agent-as-my-property-agent</link><guid isPermaLink="true">https://blog.adhikary.net/ai-agent-as-my-property-agent</guid><category><![CDATA[llm]]></category><category><![CDATA[#agent]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sun, 11 Feb 2024 17:20:14 GMT</pubDate><content:encoded><![CDATA[<p>Finding a flat for rent could be tiring. Ranging from non-responsive agents to landlords with particular demographic preferences, getting a new home always feels like a drag. Unless... We had an AI Agent do the scheduling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707672129902/3dfb3be0-5507-4cae-ae04-7133fe0d2040.webp" alt class="image--center mx-auto" /></p>
<h1 id="heading-overview">Overview</h1>
<blockquote>
<p>This post is a thought-experiment. I would NEVER violate the WhatsApp Terms of Service by using their Web App as an API to automate stuff.</p>
</blockquote>
<p>Our goal is to provide our tenant profile for as many property listings as possible (from our list of properties we like), then <strong>schedule up viewings</strong>.</p>
<p>For the uninitiated, <strong>this is the tiring part</strong> - constantly providing your profiles, and following up with property agents.</p>
<p><img src="https://mermaid.ink/svg/pako:eNp9UctKw0AU_ZXhQqFCEppJm9eiUHAjtCC6ECSbsbltI81kyEyssfQbii4E3XTjRvADBP_GH7Cf4CR9SDbO6pxzD2cO9y5hnMUIIUxzJmZkeBFxot_gbDBFrtrbzduzJqRmJ7vZ1YwpORBCD58-yKJiTAhzgTfWrdx7Wi0yHI7a368vP5_rCu718zwTmKvykP74vt2sv47y8Z9GC2KaRCKPJUlRSjZFLfSPNZqlKm-OY0zuUGog5mVt3icdghs1_k_rN80RBwNSzFOWxHpry8ofgZphihGEGsY4YcVcRRDxlbayQmWXJR9DqPICDShEzBSeJkzvO4VwwuZSqxgnKstHu0vUBzFAMH6dZX8ezSFcwj2Etmtbbof6gdfzunbgBY4BJYSmTalvOU7Hpnro9ALqrwx4qDOoRQO363qe6wc9x3G67uoXUy-lGQ" alt class="image--center mx-auto" /></p>
<p>The solution is centered around <code>whatsapp-web.js</code> , it provides a Node.js wrapper around WhatsApp Web. We can initiate conversations or get an event when we receive a reply.</p>
<p>The AI Agent should have access to a few tools, namely,</p>
<ul>
<li><p><code>get_availabilities(from_date, to_date)</code></p>
</li>
<li><p><code>is_available(time)</code></p>
</li>
<li><p><code>schedule_appointment(time)</code></p>
</li>
</ul>
<p>This could be possible with some calendar API service, i.e, Google Calendar API with Appointment Slots. (Imagine Calendly)</p>
<p><img src="https://mermaid.ink/svg/pako:eNp9UU1Lw0AQ_SthTgpJaJI2aXIoFL0ICqIHQXKZJtMmmo8lu63G0qNnUcFrL14E_4F_qj_B6UcqoeCe5s17-_bNzhyiMiYIYFKhSLTzq7DQ-AzPhhMq1NFq-fnBQNug4y13k6CSQyGYfPvWHtYIhTAeaGTeyZ3msioFVapuXF6_VsuXn3275XeCGRUxVix7f94jJltRNMPQJDNSy0lKnBA3Bvss7WRrbUURpTOSXIis3oh3To1xK-P_boO2eO1wEC5KKLqXGs4wzXCUZqnavtoMdHABYx6Gf65MC5U3ERo16JBTlWMa827m67shqIRyCiHgMqYxTjMVQlgsWIpTVV7XRQSBqqakw1TEqOg0Rd5qDsEYM8ldilNVVhfbfW_WroPA4rYs_zSMIZjDIwSWa5lux-77Xs_rWr7nOzrUEBiWbfdNx-lYNpNOz7f7Cx2eNh62aftu1_U8t-_3HMfpuotfjkTG1A" alt class="image--center mx-auto" /></p>
<p>A simplified flow would look like:</p>
<p><img src="https://mermaid.ink/svg/pako:eNqFU7GOm0AQ_ZXVFqk46wAbzBYnIZ9OSnHSKS4iRTQTdrBXgV2yLL44lsvUURIp7TXXRMof5KfuE7IYA3ZsKzSwM--9mTfsbGiqOFJGK_xYo0zxVsBCQ5FIYp8StBGpKEEaEr-OF2jfUJGXp-ef9kx2gVPk2yWYKi7LFvr9dx84hT5oVaI26wPpb79enr7-6TOXiswgR8lBt6QfX_pAIlvwvt-rm5uuPCNziyAGZSNQapWJHMkrohvrlSGZ0mQl8FHIRSvREa3GUaOM3Cn9CPqM1p7fabY6R-SjhpqMqrCnGVFgdVJ8b4WRN5iiWGFTr6HxQ_zgt5sEI7Mlph8IrEDk8F7kwo4TFiBkZc5KdMTDkjMlM6GLTsSaPFtzsNQRDi39b5zzdIm8zoc5QFkqIU3R__rLI-wb_JdyboDxACJpS0R-eX4x56Ta98aHu0EdWqAuQHC7OJuGnlCzROuTMvvJMYM6NwlN5NZCoTZqvpYpZUbX6NC65GC6PaMsg7yyUeTCKH3fLuNuJx1qL_o7pQaMPVO2oZ8ocwN3FFx70yichGM3CiPfoWvKrlzPm458_9r1bNKfRN5069DPOw1v5EXBOAjDYBpNfN8fB9u_sB1hjA" alt class="image--center mx-auto" /></p>
<p>Edge cases to consider:</p>
<ul>
<li><p>Property agent asks for additional information</p>
<ul>
<li><p>Lease period (1 or 2 years)</p>
</li>
<li><p>Demographic Information (Gender, Nationality, Ethnicity, Age)</p>
</li>
</ul>
</li>
<li><p>Property agent denies a viewing</p>
<ul>
<li>Landlords demographic requirements are not met</li>
</ul>
</li>
<li><p>Terminating the Agent and restarting it, it should remember/recall previous conversations.</p>
</li>
</ul>
<h3 id="heading-providing-list-of-properties">Providing list of properties</h3>
<p>Just providing a list of links to crawl and extract the property listings may not be possible, again due to <strong>Terms of Service restrictions</strong>, and heavy-handed bot prevention mechanisms of property listing websites.</p>
<p>We could resort to simply keeping a <strong>CSV/Sheets file</strong> of descriptions of properties, and Property Agents' contact details.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I hope you enjoyed the not at all real, and completely hypothetical project of using an AI Agent to schedule viewing appointments. Act responsibly, within the constraints of the law - in the real world!</p>
]]></content:encoded></item><item><title><![CDATA[Writing a TypeScript Code Generator: Templates vs AST]]></title><description><![CDATA[Code generators replace mindless coding with productivity; a pure function that produces predictable code, given a (set of) input(s). Generating boilerplate classes or templates — a common use case for Codegen.
Use-case: Generating Classes
We will be...]]></description><link>https://blog.adhikary.net/writing-a-typescript-code-generator-templates-vs-ast</link><guid isPermaLink="true">https://blog.adhikary.net/writing-a-typescript-code-generator-templates-vs-ast</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[ast]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sat, 30 Sep 2023 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Code generators replace mindless coding with productivity; a pure function that produces predictable code, given a (set of) input(s). Generating boilerplate classes or templates — a common use case for Codegen.</p>
<h1 id="heading-use-case-generating-classes"><strong>Use-case: Generating Classes</strong></h1>
<p>We will be generating components (Class) that follow a repetitive yet predictable pattern.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> HttpBinApi <span class="hljs-keyword">implements</span> ICredentialType {
 name = <span class="hljs-string">'httpbinApi'</span>;
 displayName = <span class="hljs-string">'HttpBin API'</span>;
}
</code></pre>
<p>Notice how many times the developer has to rewrite “HTTP Bin API” in different cases and styles? Moreover, using the wrong case would cause linter issues and never-ending headaches. Could this be automated?</p>
<h1 id="heading-approach-string-manipulation"><strong>Approach: 🧵 String Manipulation</strong></h1>
<p>Simply using JavaScript String functions can take us a long way. Template Strings, joins and possibly a little bit of <code>lodash</code> .</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateClass</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) </span>{
    <span class="hljs-keyword">return</span> [
        <span class="hljs-string">`export class <span class="hljs-subst">${pascalCase(name)}</span>}Api implements ICredentialType {`</span>,
        <span class="hljs-string">`  name = '<span class="hljs-subst">${camelCase(name)}</span>Api';`</span>,
        <span class="hljs-string">`  displayName = '<span class="hljs-subst">${titleCase(name)}</span> API';`</span>,
        <span class="hljs-string">`}`</span>,
    ].join(<span class="hljs-string">'\n'</span>);
}
</code></pre>
<p>While this works, it makes me <strong>uncomfortable</strong>; my mind implicitly sees fragility in this approach. What if the code generator is <strong>more complex</strong>? What if we need to iterate through <strong>arrays or objects</strong>? What if the signatures <strong>change</strong>? It seems <strong>unmaintainable</strong>.</p>
<h2 id="heading-hygen"><strong>Hygen</strong></h2>
<p>A more practical approach to string manipulation and using templates to generate code — could be <a target="_blank" href="https://www.hygen.io/">Hygen</a>. It handles file creation, manipulation of existing files gracefully.</p>
<p>The devs call it the <em>“The scalable code generator that saves you time.”</em> It is a code generation utility that integrates seamlessly into your development flow. It uses EJS templates to define your file structures.</p>
<pre><code class="lang-typescript">---
to: src/credentials/&lt;%= h.changeCase.pascal(name) %&gt;.ts
---

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> &lt;%= h.changeCase.pascal(name) %&gt; <span class="hljs-keyword">implements</span> ICredentialType {
    name = <span class="hljs-string">"&lt;%= h.changeCase.camel(name) %&gt;"</span>;
    displayName = <span class="hljs-string">"&lt;%= name %&gt;"</span>;
}
</code></pre>
<p>Check it out here: <a target="_blank" href="https://www.hygen.io/">Hygen</a></p>
<blockquote>
<p><em>Manipulating whitespace dependent languages like YAML or Python could be challenging with Hygen. — A dev who tried.</em></p>
</blockquote>
<p>Let’s admit it, in our mind, <em>“code generation is supposed to be a bit more complicated”</em>. The simplicity here may be causing the nerves!</p>
<h1 id="heading-approach-abstract-syntax-trees"><strong>Approach: 🌲 Abstract Syntax Trees</strong></h1>
<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>What if we could have a more <strong>programmatic-way</strong> of generating code? Instead of having <em>apparently meaningless</em> string concatenations, we had <strong>semantics and meanings</strong>?</p>
<p>Introducing ASTs. Code compilers usually do not compile strings of code directly. Instead, it can build up a tree-like structure of branches and objects and conditions.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*N9Y26_mQ-ZQ5jXMSMDyEKg.png" alt /></p>
<p>A tree representation of a simple TypeScript class</p>
<h2 id="heading-example-of-ast"><strong>Example of AST</strong></h2>
<p>For the HttpBinApi class mentioned at the top, the AST representation may look something like this:</p>
<pre><code class="lang-bash">
  factory.createClassDeclaration(
    [factory.createToken(ts.SyntaxKind.ExportKeyword)],
    factory.createIdentifier(<span class="hljs-string">"HttpBinApi"</span>),
    //...
    [
      factory.createPropertyDeclaration(
        factory.createIdentifier(<span class="hljs-string">"name"</span>),
        //...
        factory.createStringLiteral(<span class="hljs-string">"httpbinApi"</span>)
      ),
      factory.createPropertyDeclaration(
        factory.createIdentifier(<span class="hljs-string">"displayName"</span>),
         //...
        factory.createStringLiteral(<span class="hljs-string">"HttpBin API"</span>)
      )
    ]
  );
</code></pre>
<blockquote>
<p><em>Do check out the</em> <a target="_blank" href="https://ts-ast-viewer.com/#code/KYDwDg9gTgLgBAYwDYEMDOa4AkYzAIQEsA7AQTELkIFswlhrhiZMBJAYSmABMmZCUSACoBPMMDgBvAFBxiKRnAC8cAOQALXGABGJcoVUBuWd0Jo6KEQDkFElapx4ixOKQAKrI9IC+QA"><strong><em>TypeScript AST Viewer</em></strong></a> <em>to play around with this Syntax Tree.</em></p>
</blockquote>
<h2 id="heading-exploring-asts-on-our-own"><strong>Exploring ASTs on our own 🕵🏽</strong></h2>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*Djs2NKXLO0Mrm00qiNW-GA.png" alt /></p>
<p>TypeScript AST Viewer in Action</p>
<p>Okay we went from string manipulation to extra-terrestrial programming in a paragraph. I encourage you to use the AST Viewer and click around for now. A few questions to get you started:</p>
<ol>
<li><p>What does a <code>const</code> look like?</p>
</li>
<li><p>How about a <code>let</code> ?</p>
</li>
<li><p>A simple <code>console.log</code> ?</p>
</li>
<li><p>How about adding two numbers?</p>
</li>
<li><p>Okay, looping through an array of numbers?</p>
</li>
</ol>
<h2 id="heading-ast-to-code"><strong>AST to Code? 👩🏻‍💻</strong></h2>
<p>All along, we’ve been converting TypeScript code to AST. But how do we do the opposite? Reconstructing TypeScript code is easy with the help of the built-in <code>ts.Printer</code> .</p>
<p>Step 1: Create a Printer.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
</code></pre>
<p>Step 2: Create an Instance of a <code>SourceFile</code> .</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> sourceFile = ts.createSourceFile(
    <span class="hljs-string">'HttpBinApi.ts'</span>,
    <span class="hljs-string">''</span>,
    ts.ScriptTarget.Latest,
    <span class="hljs-literal">false</span>, <span class="hljs-comment">// setParentNodes</span>
    ts.ScriptKind.TS,
  );
</code></pre>
<p>Step 3: Render as String.</p>
<pre><code class="lang-typescript">printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1222/1*nCWD4ax4QmvdymOhz2aXVg.png" alt /></p>
<p>Check out a fully working, <a target="_blank" href="https://stackblitz.com/edit/stackblitz-starters-7ncslx"><strong>in-the-browser example</strong> right here: StackBlitz #1</a>. Do feel free to play around with it!</p>
<h2 id="heading-where-is-the-code-generator"><strong>Where is the Code-Generator? ⚙️</strong></h2>
<p>Ah yes yes, now we can assemble everything together into a semi-working code generator.</p>
<p>Step 1: Parametrised the AST representation.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> className = <span class="hljs-string">`<span class="hljs-subst">${_.upperFirst(_.camelCase(name))}</span>Api`</span>;
<span class="hljs-keyword">const</span> classIdentifier = factory.createIdentifier(className);
</code></pre>
<p>Step 2: With my trusty Co-Pilot, a large language model — I have refactored the code to make more legible.</p>
<p>Check out the <a target="_blank" href="https://stackblitz.com/edit/stackblitz-starters-bsn3ks?file=index.ts">refactored version: <strong>StackBlitz #2</strong></a>.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">console</span>.log(generateClass(<span class="hljs-string">'Cloud File Transfer'</span>));
</code></pre>
<pre><code class="lang-typescript">❯ ts-node index.ts
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CloudFileTransferApi <span class="hljs-keyword">implements</span> ICredentialType {
    name = <span class="hljs-string">"cloudFileTransferApi"</span>;
    displayName = <span class="hljs-string">"Cloud File Transfer"</span>;
}
</code></pre>
<p>There are no clear-cut winners here. Based on your requirements, you do need to make a call on <strong>simplicity vs robustness</strong>. Hope you had fun! 🎉</p>
<h1 id="heading-references-and-links-to-check-out"><strong>References and Links to Check-out</strong></h1>
<ol>
<li><p><a target="_blank" href="https://www.hygen.io/">Hygen | Hygen</a> — Code Generation Framework based on EJS Templates</p>
</li>
<li><p><a target="_blank" href="https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API">Using the Compiler API · microsoft/TypeScript Wiki (github.com)</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/rametta/typescript-code-generation-epn">Typescript Code Generation — DEV Community</a></p>
</li>
<li><p><a target="_blank" href="https://ts-ast-viewer.com/#">TypeScript AST Viewer (ts-ast-viewer.com)</a></p>
</li>
<li><p><a target="_blank" href="https://astexplorer.net/">AST explorer</a></p>
</li>
<li><p><a target="_blank" href="https://stackblitz.com/edit/stackblitz-starters-7ncslx?file=index.ts">TypeScript AST Exploration — StackBlitz</a></p>
</li>
<li><p><a target="_blank" href="https://stackblitz.com/edit/stackblitz-starters-bsn3ks?file=index.ts">TypeScript AST Exploration: Parametrizing — StackBlitz</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Hasura JWKS: JWT w/ Multiple Auth0 tenants]]></title><description><![CDATA[TL;DR - By default, Hasura does not accept multiple JWKS URLs. Thus, write a lambda or a simple HTTP API to combine the JWKS keys of multiple tenants into a single JWKS endpoint. (Bonus: Buggy Auth0 fingerprint implementation)
Prelude
Before starting...]]></description><link>https://blog.adhikary.net/hasura-jwks-jwt-w-multiple-auth0-tenants</link><guid isPermaLink="true">https://blog.adhikary.net/hasura-jwks-jwt-w-multiple-auth0-tenants</guid><category><![CDATA[Hasura]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Mon, 06 Sep 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390152321/b325d7a8-9e91-4836-b233-c63a1155585f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>TL;DR - By default, Hasura does not accept multiple JWKS URLs. Thus, write a lambda or a simple HTTP API to combine the JWKS keys of multiple tenants into a single JWKS endpoint. (Bonus: Buggy Auth0 fingerprint implementation)</p>
<h3 id="heading-prelude">Prelude</h3>
<p>Before starting, please make sure to add the Auth0 Rule as mentioned <a target="_blank" href="https://hasura.io/docs/latest/graphql/core/guides/integrations/auth0-jwt.html">in this support document</a>. Test to make sure the Hasura Claim is present in the JWT issued by Auth0.</p>
<h3 id="heading-the-auth0-jwks-bug">The Auth0 JWKS Bug</h3>
<p>Thanks to a <a target="_blank" href="https://community.auth0.com/t/certificate-thumbprint-is-longer-than-20-bytes/7794/3">pretty weird bug</a> in Auth0, if you have an old signing key generated on/before April 2020, the key has an invalid x5t fingerprint. Thus, Hasura will not work if you point it to a JWKS endpoint containing the old x5t fingerprints.</p>
<p>Thankfully, Auth0 has issued a fix, and all you need to do is <a target="_blank" href="https://community.auth0.com/t/jwk-certificate-thumbprint-is-invalid/16070/22">rotate your signing keys</a>.</p>
<h3 id="heading-observing-the-jwks-response">Observing the JWKS response</h3>
<p>The JWKS URL of your Auth0 Tenant will respond resembling the type declaration stated below.</p>
<p>(Hint: <code>https://..auth0.com/.well-known/jwks.json</code> )</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Key {
    alg: <span class="hljs-built_in">string</span>;
    kty: <span class="hljs-built_in">string</span>;
    use: <span class="hljs-built_in">string</span>;
    n: <span class="hljs-built_in">string</span>;
    e: <span class="hljs-built_in">string</span>;
    kid: <span class="hljs-built_in">string</span>;
    x5t: <span class="hljs-built_in">string</span>;
    x5c: <span class="hljs-built_in">string</span>[];
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> RootObject {
    keys: Key[];
}
</code></pre>
<p>Thus, we just need to fetch the JWKS Key objects from all our tenants and merge them into a single keys array. Let's do it.</p>
<h3 id="heading-building-the-lambda">Building the Lambda</h3>
<p>Let's list down all our JWKS endpoints in an array. Make sure to replace it with your Auth0 Domains.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> jwksUrls = [
    <span class="hljs-string">'https://foo.au.auth0.com/.well-known/jwks.json'</span>,
    <span class="hljs-string">'https://bar.au.auth0.com/.well-known/jwks.json'</span>,
    <span class="hljs-string">'https://baz.au.auth0.com/.well-known/jwks.json'</span>,
];
</code></pre>
<p>Next, time to parallelly download all the JWKs for merging. We'll be using <code>axios</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

<span class="hljs-keyword">const</span> responses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(jwksUrls.map(<span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> axios.get(url)));
<span class="hljs-keyword">const</span> keySets = responses.map(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.data.keys)
</code></pre>
<p>Okay, we have to take a break here. Recall the Auth0 x5t bug? Yeah. It turns out, even if you rotate the key, for the sake of other microservices in your system, you may decide to keep the previous key still valid. Otherwise, the previously issued tokens would become invalid and your users wouldn't stay "logged in" anymore.</p>
<p>There is a tiny workaround. It is to remove the invalid keys with the invalid x5t signatures from the <code>keySets</code>. However, this does mean that your new Hasura system will only work with newly issued JWT tokens signed with your shiny new key. Thus, we will replace that last line with,</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> keySets = responses.map(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.data.keys.filter(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> key.kid !== key.x5t));
</code></pre>
<p>Because in the faulty implementation, the kid and x5t are the same.</p>
<h3 id="heading-the-final-code-for-the-lambda">The final code for the Lambda</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event) =&gt; {
    <span class="hljs-keyword">const</span> jwksUrls = [
        <span class="hljs-string">'https://foo.au.auth0.com/.well-known/jwks.json'</span>,
        <span class="hljs-string">'https://bar.au.auth0.com/.well-known/jwks.json'</span>,
        <span class="hljs-string">'https://baz.au.auth0.com/.well-known/jwks.json'</span>,
    ];

    <span class="hljs-keyword">const</span> responses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(jwksUrls.map(<span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> axios.get(url)));
    <span class="hljs-keyword">const</span> keySets = responses.map(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.data.keys.filter(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> key.kid !== key.x5t));
    <span class="hljs-keyword">const</span> keys = [].concat(...keySets);

    <span class="hljs-keyword">const</span> response = {
        keys,
    };

    <span class="hljs-keyword">return</span> response;
};
</code></pre>
<h3 id="heading-pointing-hasura-to-the-jwks-endpoint">Pointing Hasura to the JWKs endpoint</h3>
<p>You may choose to create a lambda or host this function any way depending on your preference. Finally, once you have the endpoint to the JWKS merging API, simply point Hasura to it. Update the <code>HASURA_GRAPHQL_JWT_SECRET</code> environment variable to,</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"type"</span>:<span class="hljs-string">"RS256"</span>,
  <span class="hljs-attr">"jwk_url"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"claims_format"</span>: <span class="hljs-string">"stringified_json"</span>
}
</code></pre>
<p>The end!</p>
]]></content:encoded></item><item><title><![CDATA[I reverse-engineered TraceTogether, for the “right reasons”]]></title><description><![CDATA[When TraceTogether was rolled out in Singapore, I geeked out with the BlueTrace Protocol and the basics of how it worked. However, with my experience of volunteering for the migrant population, I knew that we needed translations, badly. We needed tra...]]></description><link>https://blog.adhikary.net/i-reverse-engineered-tracetogether-for-the-right-reasons</link><guid isPermaLink="true">https://blog.adhikary.net/i-reverse-engineered-tracetogether-for-the-right-reasons</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sat, 08 Aug 2020 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390550532/7882e033-34c6-4dc8-8fde-609dc0a22e81.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When TraceTogether was rolled out in Singapore, I geeked out with the BlueTrace Protocol and the basics of how it worked. However, with my experience of volunteering for the migrant population, I knew that we needed translations, badly. We needed translations if we wanted to an effective deployment of TraceTogether in the vulnerable population.</p>
<blockquote>
<p>With their little command over English, would most of the migrant workers be able to effectively use TraceTogether?</p>
</blockquote>
<h2 id="heading-tracing-the-contacts"><strong>Tracing the Contacts</strong></h2>
<p>I immediately texted everyone I knew, working with GovTech or SingHealth. I contacted GovTech on a few channels to connect me to the right person. I was surprised at the speed they responded with contacts! Finally, along with active help from Sudesna, a recent NUS-grad young physician, I got a few contacts to move forward.</p>
<h2 id="heading-meanwhile"><strong>Meanwhile</strong></h2>
<p>I was anxious to get the translations rolled out. <strong>I needed to start translating by the time I reached the correct person-in-charge.</strong> So, as any sane human would do, I started a Google Sheet, and tried to type in text from the app interface. Soon however, I realised this was unsustainable as some of the hidden screens would remain untranslated.</p>
<p>So, I took the Android app, and started reverse-engineering. I used a tool named apktool to decompile the app, and looked for the file containing all the “strings of text” used throughout the app. Luckily, I did find the English resources file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390299509/4126a6c9-ae49-44ee-a4bb-d584545d483b.png" alt class="image--center mx-auto" /></p>
<p>However, it was XML, and I needed to spit out a CSV/Excel file for it to be any good. Developers always try to automate everything. Spirited, I did write a simple Python script to convert this document into a CSV, uploaded to Google Sheets and started translating.</p>
<p>I was happy. I felt relieved. Now, all I had to do was to hand this over to the responsible team to be implemented.</p>
<h2 id="heading-the-contact"><strong>The Contact!</strong></h2>
<p>Finally I found a person from the Hive Team coordinating UI/UX efforts of TraceTogether. They were delighted to see the efforts, however had to let me know that, the (then) current version of the app wasn’t designed to be multilingual, and a new version with new strings would be released soon!</p>
<p>Altho, not all of TraceTogether was translated by individual contributors from the members of the public. My translations were partially accepted to some of the untranslated parts of TraceTogether. <strong>The Team was very aware of the need of the migrant population, and started their own effort of translation even before me!</strong> However, as people with hearts, they always did try to encourage us volunteers, and made opportunities for us to contribute here and there.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390725464/cfc2d4b4-01ad-4775-a569-24a3670e97d1.png" alt="Screenshot of TraceTogether App" class="image--center mx-auto" /></p>
<p>We started working to translate the newer features of the app. One of the first features I translated, was the <strong>SafeEntry check-in</strong> feature. I still get excited to see my translations on the app.</p>
<p>I believe allowing the public to participate is empowering us, giving us a feeling of achievement as we could contribute as much as we could, in helping to keep this tiny island we call home, safe. Thanks, the TT TEAM!</p>
<h2 id="heading-the-cool-t"><strong>The Cool T</strong></h2>
<p>And, I got a cool TraceTogether T as a token of appreciation :’)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390567730/eddd6e8c-1acf-4dd2-aa51-81bf5af211ee.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[GovTech SafeEntry and TraceTogether Posters in Bengali (Bangla)]]></title><description><![CDATA[Seen those SafeEntry posters in Singapore, with instructions to "log in" to your neighborhood 7-Eleven? I have translated those into Bengali (Bangla) ahead of the reopening of Singapore, from the circuit breaker. These have been translated in the hop...]]></description><link>https://blog.adhikary.net/govtech-safeentry-and-tracetogether-posters-in-bengali-bangla</link><guid isPermaLink="true">https://blog.adhikary.net/govtech-safeentry-and-tracetogether-posters-in-bengali-bangla</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sun, 31 May 2020 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Seen those SafeEntry posters in Singapore, with instructions to "log in" to your neighborhood 7-Eleven? I have translated those into Bengali (Bangla) ahead of the reopening of Singapore, from the circuit breaker. These have been translated in the hope of protecting our migrant workers and the community amidst the uncertainty.</p>
<h3 id="heading-what-is-this">What is this?</h3>
<p>SafeEntry is a simple contact tracing system used by the Government of Singapore as a measure to track the spread of COVID-19. Shops, malls, officers, and other public places put posters out instructing visitors on how to sign in. Those are now available in Bengali!</p>
<p><img src="https://i1.wp.com/adhikary.net/wp-content/uploads/2020/05/Bengali-Why-use-TraceTogether.png?ssl=1" alt /></p>
<p><img src="https://i0.wp.com/adhikary.net/wp-content/uploads/2020/05/Bengali-Portrait-SafeEntry-Mobile-_Empty.jpg?ssl=1" alt /></p>
<p><img src="https://i0.wp.com/adhikary.net/wp-content/uploads/2020/05/Bengali-Use-SingPass-Mobile-for-SafeEntry-Check-Ins-Poster-Final-scaled.jpg?ssl=1" alt /></p>
<p><img src="https://i0.wp.com/adhikary.net/wp-content/uploads/2020/05/Small_Bengali_SafeEntry_NRIC_Instructions_Poster.jpg?ssl=1" alt /></p>
<h3 id="heading-download-posters">Download Posters</h3>
<p>[Links removed as they are no longer relevant in Singapore]</p>
]]></content:encoded></item><item><title><![CDATA[Counting Weekends between Two Dates in PostgreSQL]]></title><description><![CDATA[I found myself the problem of counting the occurrence of specific "days of the week" between two dates; for, of course, generating features for a predictive analysis task. For example, the number of Fridays and Saturdays between 2019-01-01 and 2019-0...]]></description><link>https://blog.adhikary.net/counting-weekends-between-two-dates-in-postgresql</link><guid isPermaLink="true">https://blog.adhikary.net/counting-weekends-between-two-dates-in-postgresql</guid><category><![CDATA[SQL]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Fri, 22 Mar 2019 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>I found myself the problem of counting the occurrence of specific "days of the week" between two dates; for, of course, generating features for a predictive analysis task. For example, the number of Fridays and Saturdays between 2019-01-01 and 2019-01-15. And thankfully, good old PostgreSQL came to the rescue!</p>
<h3 id="heading-introducing-generateseries">Introducing <em>generate_series</em></h3>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>);
</code></pre>
<pre><code class="lang-sql">generate_series 
            1
            2
            3
            4
            5
 (5 rows)
</code></pre>
<p>And, if we want to spice it up by setting the interval, we can do that too! Let's make a list of all the ODD numbers between 1 and 10 (inclusive).</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>);
</code></pre>
<pre><code class="lang-sql">generate_series 
            1
            3
            5
            7
            9
 (5 rows)
</code></pre>
<h3 id="heading-generateseries-but-with-dates"><em>generate_series</em> but with Dates</h3>
<p>Let's try just plugging in Date Strings.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>, <span class="hljs-string">'2019-01-15'</span>);
</code></pre>
<pre><code class="lang-sql">[42725] ERROR: function generate_series(unknown, unknown) is not unique Hint: Could not choose a best candidate function. You might need to add explicit type casts.
</code></pre>
<p>Clearly, something is off. Ah, we didn't cast those values as Dates. Of course. Let's do it.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>::<span class="hljs-built_in">date</span>, <span class="hljs-string">'2019-01-15'</span>::<span class="hljs-built_in">date</span>);
</code></pre>
<pre><code class="lang-sql">[42883] ERROR: function generate_series(date, date) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 15
</code></pre>
<p>Okay that did identify our value as a date, but it still isn't working. The thing is, we need to provide the interval explicitly. Let's do it!</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>::<span class="hljs-built_in">date</span>, <span class="hljs-string">'2019-01-15'</span>::<span class="hljs-built_in">date</span>, <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>);
</code></pre>
<pre><code class="lang-sql">generate_series     
2019-01-01 00:00:00+06
...
2019-01-15 00:00:00+06
(15 rows)
</code></pre>
<p>Alright! That worked like a charm! Of course, let's make it a bit prettier.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> s::<span class="hljs-built_in">date</span>
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>, <span class="hljs-string">'2019-01-15'</span>, <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>) s;
</code></pre>
<pre><code class="lang-sql">     s      
  2019-01-01
  ...
  2019-01-15
 (15 rows)
</code></pre>
<p>Sweet! We can now generate the ranges required.</p>
<h3 id="heading-the-week-of-day">The Week of Day</h3>
<p>I'll let the query and the results talk in this bit.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span>
       s::<span class="hljs-built_in">date</span>,
       <span class="hljs-keyword">extract</span>(DOW <span class="hljs-keyword">from</span> s),
       to_char(s, <span class="hljs-string">'day'</span>)
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>, <span class="hljs-string">'2019-01-15'</span>, <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>) s;
</code></pre>
<pre><code class="lang-sql">      s      | date_part |  to_char  
 <span class="hljs-comment">------------+-----------+-----------</span>
  2019-01-01 |         2 | tuesday  
  2019-01-02 |         3 | wednesday
  2019-01-03 |         4 | thursday 
  2019-01-04 |         5 | friday   
  2019-01-05 |         6 | saturday 
  2019-01-06 |         0 | sunday   
  ...
  2019-01-14 |         1 | monday   
  2019-01-15 |         2 | tuesday  
 (15 rows)
</code></pre>
<p>Starting to make sense now? We can get a numeric value for the day of the week by extracting <code>DOW</code>from the interval. And getting the string representation is just as easy as calling <code>to_char</code>. Let's put a weekend constraint now. Check the mapping of days of the week on the table posted above. That's how we got <code>5</code> and <code>6</code>; representing <code>Friday</code> and <code>Saturday</code>.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> s::<span class="hljs-built_in">date</span>,
       <span class="hljs-keyword">extract</span>(DOW <span class="hljs-keyword">from</span> s),
       to_char(s, <span class="hljs-string">'day'</span>)
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>, <span class="hljs-string">'2019-01-15'</span>, <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>) s
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">extract</span>(DOW <span class="hljs-keyword">from</span> s) <span class="hljs-keyword">in</span> (<span class="hljs-number">5</span>, <span class="hljs-number">6</span>);
</code></pre>
<pre><code class="lang-sql">      s      | date_part |  to_char  
 <span class="hljs-comment">------------+-----------+-----------</span>
  2019-01-04 |         5 | friday   
  2019-01-05 |         6 | saturday 
  2019-01-11 |         5 | friday   
  2019-01-12 |         6 | saturday 
 (4 rows)
</code></pre>
<p>That's super cool! Now, let's <code>COUNT</code>!</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">COUNT</span>(*)
<span class="hljs-keyword">FROM</span> generate_series(<span class="hljs-string">'2019-01-01'</span>, <span class="hljs-string">'2019-01-15'</span>, <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>) s
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">extract</span>(DOW <span class="hljs-keyword">from</span> s) <span class="hljs-keyword">in</span> (<span class="hljs-number">5</span>, <span class="hljs-number">6</span>);
</code></pre>
<p>Voila!</p>
<h3 id="heading-with-a-table">With a Table</h3>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>,
       <span class="hljs-keyword">SUM</span>(<span class="hljs-keyword">CASE</span> <span class="hljs-keyword">WHEN</span> <span class="hljs-keyword">extract</span>(dow <span class="hljs-keyword">from</span> s) <span class="hljs-keyword">IN</span> (<span class="hljs-number">5</span>, <span class="hljs-number">6</span>) <span class="hljs-keyword">THEN</span> <span class="hljs-number">1</span> <span class="hljs-keyword">ELSE</span> <span class="hljs-number">0</span> <span class="hljs-keyword">END</span>)
<span class="hljs-keyword">FROM</span> tbl
<span class="hljs-keyword">JOIN</span> generate_series(
        tbl.starts_on,
        tbl.ends_on,
        <span class="hljs-string">'1 day'</span>::<span class="hljs-built_in">interval</span>) s <span class="hljs-keyword">ON</span> <span class="hljs-literal">true</span>
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">id</span>;
</code></pre>
<p>So this was my clumsy implementation, that I came up with. I am pretty sure there are better ways to pull this off. Why don't you leave your thoughts and solutions in the comments? And please don't forget to share if you learned anything new! Thanks for dropping by.</p>
]]></content:encoded></item><item><title><![CDATA[Flask-like “global” request context in Sanic (asyncio)]]></title><description><![CDATA[Although something like Flask’s globally accessible request object is considered a terrible way of writing code (explicit is better than implicit), sometimes it makes sense to use it. For example, while passing a Correlation-ID to track a request’s l...]]></description><link>https://blog.adhikary.net/flask-like-global-request-context-in-sanic-asyncio</link><guid isPermaLink="true">https://blog.adhikary.net/flask-like-global-request-context-in-sanic-asyncio</guid><category><![CDATA[Python]]></category><category><![CDATA[Flask]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Wed, 19 Sep 2018 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708390844494/ab7e0bec-0537-4c57-bfd9-20d7687f5faa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Although something like Flask’s globally accessible <code>request</code> object is considered a terrible way of writing code (explicit is better than implicit), sometimes it makes sense to use it. For example, while passing a Correlation-ID to track a request’s life cycle through your micro-services.</p>
<p>You can memorize the Correlation-ID throughout the lifecycle of a request without explicitly passing it around like juggling balls. This is actually a good approach as the Correlation ID is not a core business logic – just a distraction. We’ll see how we can implement such a request-bound “global” context in Sanic, and how to setup a simple Correlation ID implementation.</p>
<h2 id="heading-aiotask-context"><strong>aiotask-context</strong></h2>
<p><a target="_blank" href="https://web.archive.org/web/20221205005233/https://github.com/Skyscanner/aiotask-context">This nifty Python module</a> can maintain a distinct context against each asyncio Task. Which means, each request can have an associated context we can use to store and pass around passive details.</p>
<pre><code class="lang-bash">$ pip install aiotask-context
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> sanic <span class="hljs-keyword">import</span> Sanic
<span class="hljs-keyword">from</span> sanic.response <span class="hljs-keyword">import</span> json

<span class="hljs-comment"># import aiotask-context</span>
<span class="hljs-keyword">import</span> aiotask_context <span class="hljs-keyword">as</span> context

app = Sanic()

<span class="hljs-comment"># hook aiotask-context</span>
<span class="hljs-meta">@app.listener('after_server_start')</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hook_context</span>(<span class="hljs-params">app, loop</span>):</span>
    loop.set_task_factory(context.task_factory)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test</span>(<span class="hljs-params">request</span>):</span>
    <span class="hljs-keyword">return</span> json({<span class="hljs-string">"hello"</span>: <span class="hljs-string">"world"</span>})

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(host=<span class="hljs-string">"0.0.0.0"</span>, port=<span class="hljs-number">8000</span>)
</code></pre>
<p>Now we have a simple Sanic app with the context hooked up.</p>
<h2 id="heading-implementing-correlation-id-generation-and-passing"><strong>Implementing Correlation ID Generation and Passing</strong></h2>
<p>Now, let’s grab the correlation ID if it comes with the request, or generate our own otherwise. Afterwards, we need to save that value to the context for future use in other parts of the code (i.e. logging, requests to other microservices and so on).</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> uuid <span class="hljs-keyword">import</span> uuid4
<span class="hljs-keyword">import</span> aiotask_context <span class="hljs-keyword">as</span> context

<span class="hljs-meta">@app.middleware('request')</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_correlation_id</span>(<span class="hljs-params">request</span>):</span>
    cid = request.headers.get(<span class="hljs-string">'X-Correlation-ID'</span>) <span class="hljs-keyword">or</span> str(uuid4())
    context.set(<span class="hljs-string">'cid'</span>, cid)
</code></pre>
<p>And throughout the code, if you need the <code>cid</code> or any context value you have set, simply use <code>context.get(key)</code>.</p>
<p>And the last step is definitely all about responding with the Correlation ID. We’ll be sticking to the middleware for this too. We just need to update the response object from the context.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.middleware('response')</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">insert_correlation_id</span>(<span class="hljs-params">request, response</span>):</span>
    response.headers[<span class="hljs-string">"X-Correlation-ID"</span>] = context.get(<span class="hljs-string">'cid'</span>)
</code></pre>
<p>Great! Now we don’t have to write spaghetti code and get lost in passing CIDs from functions to functions. Cheers!</p>
]]></content:encoded></item><item><title><![CDATA[pyenv build depencies on Ubuntu]]></title><description><![CDATA[pyenv can get particularly annoying during building Python. Dependencies are often missing resulting in failed builds. This short blog post is outlining the required dependencies to reduce headaches for future me, and anyone else reading this.
You ha...]]></description><link>https://blog.adhikary.net/pyenv-build-depencies-on-ubuntu</link><guid isPermaLink="true">https://blog.adhikary.net/pyenv-build-depencies-on-ubuntu</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Tue, 21 Aug 2018 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>pyenv can get particularly annoying during building Python. Dependencies are often missing resulting in failed builds. This short blog post is outlining the required dependencies to reduce headaches for future me, and anyone else reading this.</p>
<p>You have probably come here seeing errors like:</p>
<pre><code class="lang-plaintext">zipimport.ZipImportError: can't decompress data; zlib not available
</code></pre>
<pre><code class="lang-plaintext">WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
</code></pre>
<p>Well, just install these and you’ll be good to go.</p>
<pre><code class="lang-bash">$ sudo apt-get build-dep python3
$ sudo apt-get install libreadline-dev libsqlite3-dev bz2-dev libssl-dev zlib1g-dev libffi-dev
</code></pre>
<p>You’re welcome.</p>
]]></content:encoded></item><item><title><![CDATA[Beginners' Guide to Effortless Doctests in Python]]></title><description><![CDATA[Doctests are essentially tests embedded in a docstring. They serve both as example use cases and test cases! A Python expression is provided along with an expected outcome, a test runner collects that and evaluates the expression.
Getting started
Let...]]></description><link>https://blog.adhikary.net/beginners-guide-to-effortless-doctests-in-python</link><guid isPermaLink="true">https://blog.adhikary.net/beginners-guide-to-effortless-doctests-in-python</guid><category><![CDATA[Python]]></category><category><![CDATA[pytest]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Wed, 20 Jun 2018 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Doctests are essentially tests embedded in a docstring. They serve both as example use cases and test cases! A Python expression is provided along with an expected outcome, a test runner collects that and evaluates the expression.</p>
<h2 id="heading-getting-started">Getting started</h2>
<p>Let's take a look at a run-of-the-mill docstring.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>(<span class="hljs-params">name</span>):</span>
    <span class="hljs-string">"""
    Returns a greeting message saying Hello.
    :param name: str
    :return: str
    """</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello, '</span> + name
</code></pre>
<p>It's a normal docstring with nothing too special. Let's try to get the doctest module to test our test-less function.</p>
<pre><code class="lang-python">$ python -m doctest -v hello.py

<span class="hljs-number">2</span> items had no tests:
    hello
    hello.hello
<span class="hljs-number">0</span> tests <span class="hljs-keyword">in</span> <span class="hljs-number">2</span> items.
<span class="hljs-number">0</span> passed <span class="hljs-keyword">and</span> <span class="hljs-number">0</span> failed.
Test passed.
</code></pre>
<p>Well, the output says it clear that we have no tests. Now, let's add a doctest. Remember how the Python Shell or REPL works? Remember how you have three arrows indicating input? Yes. Just copy that style.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>(<span class="hljs-params">name</span>):</span>
    <span class="hljs-string">"""
    Returns a greeting message saying Hello.
    :param name: str
    :return: str

    &gt;&gt;&gt; hello('Anam')
    'Hello, Anam'
    """</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello, '</span> + name
</code></pre>
<p>Time to run the doctest module again.</p>
<pre><code class="lang-python">$ python -m doctest -v hello.py

Trying:
    hello(<span class="hljs-string">'Anam'</span>)
Expecting:
    <span class="hljs-string">'Hello, Anam'</span>
ok
<span class="hljs-number">1</span> items had no tests:
    hello
<span class="hljs-number">1</span> items passed all tests:
   <span class="hljs-number">1</span> tests <span class="hljs-keyword">in</span> hello.hello
<span class="hljs-number">1</span> tests <span class="hljs-keyword">in</span> <span class="hljs-number">2</span> items.
<span class="hljs-number">1</span> passed <span class="hljs-keyword">and</span> <span class="hljs-number">0</span> failed.
Test passed.
</code></pre>
<p>Ah, that looks more like it.</p>
<h2 id="heading-expecting-exceptions">Expecting Exceptions</h2>
<p>Let's try something more fun. Let's add a case in our function, if the provided name is just composed of digits, we refuse to greet digits!</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>(<span class="hljs-params">name</span>):</span>
    <span class="hljs-string">"""
    Returns a greeting message saying Hello.
    :param name: str
    :return: str

    &gt;&gt;&gt; hello('Anam')
    'Hello, Anam'
    """</span>

    <span class="hljs-keyword">if</span> name.isdigit():
        <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">'We do not greet numbers'</span>)

    <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello, '</span> + name
</code></pre>
<p>Now, how do we test for exceptions? Well, remember the mantra.</p>
<blockquote>
<p><em>Replicate your shell; success you will be showered with upon you.</em></p>
</blockquote>
<p>So, just replicate your shell! Let's see how the shell reacts to digits.</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screen-Shot-2018-06-20-at-7.37.21-AM.png" alt /></p>
<p>So, in the doctest,</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>(<span class="hljs-params">name</span>):</span>
    <span class="hljs-string">"""
    Returns a greeting message saying Hello.
    :param name: str
    :return: str

    &gt;&gt;&gt; hello('Anam')
    'Hello, Anam'
    &gt;&gt;&gt; hello('121')
    Traceback (most recent call last):
    ...
    ValueError: We do not greet numbers
    """</span>

    <span class="hljs-keyword">if</span> name.isdigit():
        <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">'We do not greet numbers'</span>)

    <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello, '</span> + name
</code></pre>
<p>Just the first line and the last line of the exception. Don't confuse doctest with a complete, well-formatted and fully laid out stack trace, please! And just three dots to indicate there were more to it. So, let's run this again.</p>
<pre><code class="lang-python">$ python -m doctest -v hello.py

Trying:
    hello(<span class="hljs-string">'Anam'</span>)
Expecting:
    <span class="hljs-string">'Hello, Anam'</span>
ok
Trying:
    hello(<span class="hljs-string">'121'</span>)
Expecting:
    Traceback (most recent call last):
    ...
    ValueError: We do <span class="hljs-keyword">not</span> greet numbers
ok
<span class="hljs-number">1</span> items had no tests:
    hello
<span class="hljs-number">1</span> items passed all tests:
   <span class="hljs-number">2</span> tests <span class="hljs-keyword">in</span> hello.hello
<span class="hljs-number">2</span> tests <span class="hljs-keyword">in</span> <span class="hljs-number">2</span> items.
<span class="hljs-number">2</span> passed <span class="hljs-keyword">and</span> <span class="hljs-number">0</span> failed.
Test passed.
</code></pre>
<p>And yes.</p>
<h2 id="heading-in-production">In Production</h2>
<p>Of course, in production, you do need to use a test runner. Something in the category of pytest or nose. I personally prefer pytest. Let's take a look at configuring pytest for this.</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screen-Shot-2018-06-20-at-7.44.27-AM.png" alt /></p>
<p>Not so surprisingly, it discovered no tests in the default configuration. We need to add a simple flag to it --doctest-modules .</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screen-Shot-2018-06-20-at-7.47.29-AM.png" alt /></p>
<p>That seems to be working, let's try to intentionally run our tests to check if it is really working.</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screen-Shot-2018-06-20-at-7.48.39-AM.png" alt /></p>
<p>And that is working perfectly. To avoid putting the --doctest-modules flag all the time, consider making a tox.ini file to place your pytest configuration. More on this in the <a target="_blank" href="https://docs.pytest.org/en/latest/customize.html">pytest documentation</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Simple Python Profiling with IPython]]></title><description><![CDATA[Profiling is imperative to understand your application. However, getting started with profiling might seem to be a steep learning curve; but it doesn't have to be! IPython has a lot of built-in magic commands, and some of them are helpful to profile ...]]></description><link>https://blog.adhikary.net/simple-python-profiling-with-ipython</link><guid isPermaLink="true">https://blog.adhikary.net/simple-python-profiling-with-ipython</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Tue, 19 Jun 2018 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Profiling is imperative to understand your application. However, getting started with profiling might seem to be a steep learning curve; but it doesn't have to be! IPython has a lot of built-in magic commands, and some of them are helpful to profile your Python code. %timeit and %prun are among the ones I found most useful.</p>
<h2 id="heading-timeit">%timeit</h2>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screenshot-from-2018-06-19-07-16-57.png" alt /></p>
<p>%timeit does exactly what it sounds like. It times your function. It niftily (is that a word?) providers the standard deviation of multiple runs as well. So essentially you probably won't get <em>lucky by chance</em>performance reports.</p>
<h2 id="heading-prun">%prun</h2>
<p><img src="https://adhikary.net/wp-content/uploads/2018/06/Screenshot-from-2018-06-19-07-19-19.png" alt /></p>
<p>This is a rather comprehensive profiling. You can check the functions of being called, the number of times they're called, and so on. This is especially useful while writing something recursive or with a deep call stack.</p>
<p>If you are using third-party plugins or modules, often it is difficult to pinpoint the performance issue - in your code or in their code? %prun will help by inspecting the entire call stack.</p>
<p>Of course, while writing recursive functions, you can actually visualize how your number of calls grow out of proportions as the problem size increases!</p>
<p>Cheers!</p>
]]></content:encoded></item><item><title><![CDATA[Mitigating High-Traffic with Simple Static Content Generation]]></title><description><![CDATA[Your application probably does not need to execute some code each time it is used. We have been caching for decades; reducing database queries, using key-value stores, OPcode caching and the list runs on. Things become overwhelming. I believe often w...]]></description><link>https://blog.adhikary.net/mitigating-high-traffic-with-simple-static-content-generation</link><guid isPermaLink="true">https://blog.adhikary.net/mitigating-high-traffic-with-simple-static-content-generation</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Fri, 15 Jun 2018 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Your application probably <strong>does not need</strong> to execute some code each time it is used. We have been caching for decades; reducing database queries, using key-value stores, OPcode caching and the list runs on. Things become overwhelming. I believe often we can find the best answers in simplicity; complexity should not be introduced where a simple solution can help.</p>
<h2 id="heading-tldr">TL;DR</h2>
<ol>
<li><p>When your application bootstraps, build combinations of all the possible states that might result in different content among the views.</p>
</li>
<li><p>Generate the actual content for all those combinations generated above.</p>
</li>
<li><p>Store the generated content as static files, serve with nginx.</p>
</li>
<li><p>Proxy the non-static requests directly to the application.</p>
</li>
</ol>
<p>Depending on the design of your application, you probably will see a considerable number of requests getting served by nginx directly without any involvement of your backend application.</p>
<h2 id="heading-to-cache-or-not-to-cache">To Cache, or not to Cache?</h2>
<p>You probably cannot <strong>staticify</strong> everything in your application. You have to choose what needs to stay static and what needs to remain dynamic. A simple rule of thumb is volatility.</p>
<ul>
<li><p>If new records/data/rows get added frequently, that's a big no-no for staticifying it.</p>
</li>
<li><p>If the number of possible values is very high for any parameter you wish to base content generation upon, that is also a big no-no.</p>
</li>
<li><p>You cannot use static sites for validation and processing of a form.</p>
</li>
</ul>
<p>Imagine you will generate static content based on a user's account type and some other parameters.</p>
<pre><code class="lang-json">account_type (free, basic, premium, gold, platinum)
billing_type (wirecard, credit card, nets, ezlink)
is_beta_user (yes, no)
</code></pre>
<p>So, you ran into 5 x 4 x 2 = 40 possible states. So the math is easy. Things can go out proportions unless you are careful! So carefully generate and manage the combinations.</p>
<h2 id="heading-generation">Generation</h2>
<p>Simply think of this passing the context variables to a templating engine for it to render an output. That's it. You got it.</p>
<h2 id="heading-hyperlinking-and-directory-structures">Hyperlinking and Directory Structures</h2>
<p>One approach I personally prefer is to create directories for each possible value combination. So it would look like,</p>
<pre><code class="lang-json">free/index.html
free/upgrade.html
premium/index.html
premium/wirecard/billing.html
</code></pre>
<h2 id="heading-entry">Entry</h2>
<p>The application should have a dynamic entrypoint, from where the user is redirected to the appropriate static directory.</p>
<p>I just did a quick write-up, not sure if this will spark anyone's interest. If you want to know more about this, please leave a comment so that I can get to know that I have to write another followup!</p>
<p>(I used this approach to build a USSD service, where authentication doesn't need to be performed by the application. So yeah that's why it was practical!)</p>
]]></content:encoded></item><item><title><![CDATA[Learn you some HTTP for fun and glory]]></title><description><![CDATA[We all use HTTP, develop for HTTP and think that we know HTTP. But, I believe as engineers we should never take things for granted; rather we should dissect everything that comes before us, recursively as many times as possible. So, let's keep applyi...]]></description><link>https://blog.adhikary.net/learn-you-some-http-for-fun-and-glory</link><guid isPermaLink="true">https://blog.adhikary.net/learn-you-some-http-for-fun-and-glory</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Fri, 20 Apr 2018 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>We all use HTTP, develop for HTTP and think that we know HTTP. But, I believe as engineers we should never take things for granted; rather we should dissect everything that comes before us, recursively as many times as possible. So, let's keep applying this principle for HTTP.</p>
<h2 id="heading-curling">cURLing</h2>
<p>cURL is a great tool for sending HTTP requests. Let's try to send one.</p>
<pre><code class="lang-bash">curl http://httpbin.org/ip
</code></pre>
<p><img src="https://adhikary.net/wp-content/uploads/2018/04/001.png" alt /></p>
<p>Hmm, okay it can do stuff. Let's make it a bit more verbose shall we? Just add a -v flag.</p>
<pre><code class="lang-bash">curl -v http://httpbin.org/ip
</code></pre>
<p><img src="https://adhikary.net/wp-content/uploads/2018/04/002.png" alt /></p>
<p>Ah now things are interesting. Do you see a few lines starting with '&gt;'? Well those are the <strong>headers</strong> that are SENT to the server. And the lines starting with '&lt;'? They are <strong>response</strong> <strong>headers</strong> that are received. The last part is the content itself. Of course, the &lt; and &gt; are there for representation only, they are not transmitted.</p>
<h2 id="heading-telneting">Telneting</h2>
<p>telnet is a great tool to make raw socket connections and really dissect almost any TCP based protocol like HTTP. Lets try this.</p>
<pre><code class="lang-bash">telnet httpbin.org 80
</code></pre>
<p>Afterwards, type in a raw HTTP request yourself!</p>
<pre><code class="lang-http"><span class="hljs-keyword">GET</span> <span class="hljs-string">/ip</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: httpbin.org
</code></pre>
<p>Now, press enter or return <strong>twice</strong>!</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/04/Peek-2018-04-20-23-43.gif" alt /></p>
<p>Who needs Firefox, Chrome or cURL! Looks like Telnet is all we need ;) Okay enough jokes for now. This is serious business. You see in the end HTTP is just a plain socket connection that has some specific "lingo" to send requests and receive responses. (Protocol, duh).</p>
<h2 id="heading-dissecting-the-request">Dissecting the Request</h2>
<p>Let's see how exactly we made the request.</p>
<pre><code class="lang-http"><span class="hljs-keyword">GET</span> <span class="hljs-string">/ip</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: httpbin.org
</code></pre>
<p>Pretty straightforward. The HTTP method in caps, the path and the HTTP version in the first line. After that, the request headers follow. In our case we just mentioned the 'Host' header to play safe with VirtualHost-enabled systems.</p>
<blockquote>
<p><em>Back in the days, running a website was expensive because you needed an entire box (a server computer) to host a single website. Then we invented a way to serve multiple websites from the same IP address / machine with virtual hosts in the Apache Web Server.</em></p>
<p><em>The internet as we know it exists for this 'Host' header.</em></p>
</blockquote>
<p>The two newlines indicate we are done with our request, and the server can parse it and send back a response.</p>
<h2 id="heading-lets-be-bad">Let's be bad</h2>
<p>Let's send a malformed HTTP request (muhahaha).</p>
<pre><code class="lang-bash">telnet httpbin.org 80
</code></pre>
<p>Afterwards, type in a malformed request yourself!</p>
<pre><code class="lang-sql">muhahahaha
</code></pre>
<p>Now, press enter or return <strong>twice</strong>!</p>
<p><img src="https://adhikary.net/wp-content/uploads/2018/04/Peek-2018-04-20-23-53.gif" alt /></p>
<p>Yup :( It was a Bad Request. We'll write our own HTTP server with plain old sockets soon. Till then, why not explore the exciting world of HTTP response headers on Google ;) Yeah and take a look at <a target="_blank" href="https://tools.ietf.org/html/rfc2616">RFC 2616</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Getting Started with Natural Language Processing, for Developers (Part 1)]]></title><description><![CDATA[Not very long ago, NLP was limited to mathematical equations, research papers and very large organizations. However, at the present time, an abundance of open source software, libraries, corpora and learning material are available for the masses to h...]]></description><link>https://blog.adhikary.net/getting-started-with-natural-language-processing-for-developers-part-1</link><guid isPermaLink="true">https://blog.adhikary.net/getting-started-with-natural-language-processing-for-developers-part-1</guid><category><![CDATA[nlp]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Fri, 09 Sep 2016 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Not very long ago, NLP was limited to mathematical equations, research papers and very large organizations. However, at the present time, an abundance of open source software, libraries, corpora and learning material are available for the masses to harness. I had a hard time getting started with natural language processing, and I went lost in the piles of information I found online.</p>
<p>So I decided to put together a series of articles on NLP for developers. Thus I skipped mathematics, calculus and analytical geometry along with rocket science unless absolutely necessary. The series will focus on applications, rather than theories. However, I do encourage readers to get a technical understanding of how and why things work, the way they do. Let’s get started.</p>
<h3 id="heading-the-setup-for-now">The Setup (for now)</h3>
<p>First of all, we will get our feet wet with holy NLP water through our friend <a target="_blank" href="https://web.archive.org/web/20161109121649/https://textblob.readthedocs.io/en/dev/">TextBlob</a>. It is a Python library for NLP. Why Python? Because Python is very popular for the purpose of NLP, AI, ML and scientific computing in general. TextBlob has a very easy and expressive API, making it easy for others to grasp and use.</p>
<blockquote>
<p><em>You have probably heard of NLTK and how it saved the world from impending doom. So why are we not using NLTK? We are. TextBlob is a wrapper over NLTK, abstracting away many fine-tuned details. We are not here to get intimidated by NLTK, we are here to experience NLP in action.</em></p>
</blockquote>
<p>So, we will be needing:</p>
<ul>
<li><p>A computer running Mac OS X, BSD or a variant of Linux (I don’t know how things work in Windows)</p>
</li>
<li><p>Working knowledge of Python 2.x or 3.x</p>
</li>
<li><p>Gallons, Buckets, Containers or entire ship shipping ship full of patience</p>
</li>
</ul>
<p>Start off by installing TextBlob.</p>
<pre><code class="lang-bash">pip install textblob
</code></pre>
<p>We are done (for now).</p>
<h3 id="heading-hello-nlp">Hello, NLP!</h3>
<p>Let’s get into processing some sentences.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> textblob <span class="hljs-keyword">import</span> TextBlob

text = <span class="hljs-string">"Aniruddha did not attend class because he was sick. The lecturer marked him absent."</span>
blob = TextBlob(text)
</code></pre>
<p>Okay, let’s break things down. The first line imports a class, nothing fancy. The second line declares a string, nothing fancy. Ah, the third line - we are creating a TextBlob object from our text string. Our blob of text is now ready for some cool NLP! Let’s figure break the whole text down into sentences.</p>
<h4 id="heading-breaking-down-aka-tokenization">Breaking Down (aka Tokenization)</h4>
<p>Let’s try this. (BTW, we are on the Python Shell)</p>
<pre><code class="lang-python">blob.sentences
</code></pre>
<p>Output:</p>
<pre><code class="lang-nginx">[Sentence("<span class="hljs-attribute">Aniruddha</span> did not attend class because he was sick.<span class="hljs-string">"), Sentence("</span>The lecturer marked him absent.<span class="hljs-string">")]</span>
</code></pre>
<p>There are two sentences as we can see, broken down or <strong>tokenized</strong> just as we wanted. Let’s try something more granular, let’s break down the <code>Sentences</code> into <code>Words</code>.</p>
<pre><code class="lang-python">blob.sentences[<span class="hljs-number">0</span>].words
</code></pre>
<p><img src="https://web.archive.org/web/20161109121649im_/http://adhikary.net/forestryio/images/Screen%20Shot%202016-09-09%20at%207.15.05%20AM.png" alt /></p>
<p>That worked out quite well! Let’s get back to some grammar lessons from elementary school.</p>
<h4 id="heading-parts-of-speech-tagging">Parts of Speech Tagging</h4>
<p>Parts of Speech (PoS) are the individual words of a sentence, they are classified into categories like nounds, pronouns, adjectives, adverbs, prepositions etc. Identifying PoS is an essential task in NLP. Let’s see how it all works.</p>
<pre><code class="lang-python">blob.sentences[<span class="hljs-number">0</span>].pos_tags
</code></pre>
<p>Output:</p>
<pre><code class="lang-python">[(<span class="hljs-string">'Aniruddha'</span>, <span class="hljs-string">u'NNP'</span>),
 (<span class="hljs-string">'did'</span>, <span class="hljs-string">u'VBD'</span>),
 (<span class="hljs-string">'not'</span>, <span class="hljs-string">u'RB'</span>),
 (<span class="hljs-string">'attend'</span>, <span class="hljs-string">u'VB'</span>),
 (<span class="hljs-string">'class'</span>, <span class="hljs-string">u'NN'</span>),
 (<span class="hljs-string">'because'</span>, <span class="hljs-string">u'IN'</span>),
 (<span class="hljs-string">'he'</span>, <span class="hljs-string">u'PRP'</span>),
 (<span class="hljs-string">'was'</span>, <span class="hljs-string">u'VBD'</span>),
 (<span class="hljs-string">'sick'</span>, <span class="hljs-string">u'JJ'</span>)]
</code></pre>
<p>Weirdo acronyms? Well, <code>('Aniruddha', 'NNP')</code> wants to tell us that, <code>Aniruddha</code> is an <code>NNP</code>, AKA a singular proper noun. Similarly, <code>JJ</code> indicates an adjective. How do I know?</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> nltk

nltk.help.upenn_tagset(<span class="hljs-string">'NNP'</span>)
</code></pre>
<p>Now you can figure out the mysterious acronyms as well. Let’s try some transformations.</p>
<h4 id="heading-transformers">Transformers!</h4>
<p>Let’s try something even cooler. Remember our <code>sentence[1]</code>, <code>Sentence("The lecturer marked him absent.")</code>? Let’s try to make <code>lecturer</code> plural.</p>
<pre><code class="lang-python">lecturer_word = blob.sentences[<span class="hljs-number">1</span>].words[<span class="hljs-number">1</span>]
lecturer_word.pluralize()
</code></pre>
<p><img src="https://web.archive.org/web/20161109121649im_/http://adhikary.net/forestryio/images/Screen%20Shot%202016-09-09%20at%207.27.16%20AM.png" alt /></p>
<p>There are some similar operations in TextBlob, try them! Read the documentation.</p>
<h4 id="heading-synonyms-and-related-words">Synonyms and related words</h4>
<p>You could just build a very simple Dictionary of Synonyms when you have a Python interpreter. Let’s take a look at the synonyms of <code>marked</code>.</p>
<pre><code class="lang-python">marked_word = blob.sentences[<span class="hljs-number">1</span>].words[<span class="hljs-number">2</span>]
marked_word.get_synsets()
</code></pre>
<pre><code class="lang-python">[Synset(<span class="hljs-string">'tag.v.01'</span>),
Synset(<span class="hljs-string">'mark.v.02'</span>),
Synset(<span class="hljs-string">'distinguish.v.03'</span>),
Synset(<span class="hljs-string">'commemorate.v.01'</span>),
Synset(<span class="hljs-string">'mark.v.05'</span>),
Synset(<span class="hljs-string">'stigmatize.v.01'</span>),
Synset(<span class="hljs-string">'notice.v.02'</span>),
...]
</code></pre>
<p>That will enough for this part. Let me know in the comments if you liked TextBlob, and/or whether you want more stuff of NLP. Thanks for dropping by.</p>
]]></content:encoded></item><item><title><![CDATA[3 Tools To Help With Writing Scientific Papers]]></title><description><![CDATA[You are finally ready to start writing your first scientific paper, maybe for a journal or conference. But you don’t know where to start. You have heard of LaTeX, BibTex, Citations and nothing is really adding up. You just need easy and uncomplicated...]]></description><link>https://blog.adhikary.net/3-tools-to-help-with-writing-scientific-papers</link><guid isPermaLink="true">https://blog.adhikary.net/3-tools-to-help-with-writing-scientific-papers</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Thu, 08 Sep 2016 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>You are finally ready to start writing your first scientific paper, maybe for a journal or conference. But you don’t know where to start. You have heard of LaTeX, BibTex, Citations and nothing is really adding up. You just need easy and uncomplicated tools to work with. Learning about the new tools should not be more difficult than writing the paper itself! I am discussing a few tools and websites here, for beginners.</p>
<h3 id="heading-what-is-latex-and-why-does-it-matter">What is LaTeX and why does it matter?</h3>
<p>Wikipedia prescribes LaTeX as a document preparation system; the official website states it as a typesetting system. I would describe LaTeX as a system for preparing documents where fine-grained pixel-by-pixel perfection is a reality. The leading conferences or journals provide their template in LaTeX, and often in word-processor formats. Personally, I have found word processor behavior to be quite unreliable and prefer LaTeX for it’s ease and simplicity. A quick search on your favorite search engine might (and probably will) more reasons to use LaTeX.</p>
<p>BibTex is a markup format for bibliography generation. It is used a lot in par with LaTeX for generating citations according to the required styling.</p>
<h3 id="heading-sharelatex">ShareLaTeX</h3>
<p><img src="https://web.archive.org/web/20161017112908im_/https://www.sharelatex.com/img/screen@2x.png" alt /></p>
<p><a target="_blank" href="https://web.archive.org/web/20161017112908/http://www.sharelatex.com/">ShareLaTeX</a> is a website similar to Google Docs, for LaTeX. It allows collaborative editing, history tracking and free hosting online. It also helps out by providing a plethora of templates to choose from; including templates from well-reputed journals or conferences. You will not need to install anything other than a modern web browser on your computer for using ShareLaTex, everything is done online. As per expectation, it can preview and export as PDF.</p>
<h3 id="heading-citethisforme">CiteThisForMe</h3>
<p><img src="https://web.archive.org/web/20161017112908im_/http://adhikary.net/forestryio/images/Screen%20Shot%202016-09-08%20at%205.46.16%20AM.png" alt /></p>
<p><a target="_blank" href="https://web.archive.org/web/20161017112908/http://www.citethisforme.com/">CiteThisForMe</a> is a great website for managing your bibliography. You can generate citations for books, websites, journal articles and more. By the way, citations are the references you make to content your paper “borrows ideas from”. A variety of export styles are supported, including Harvard, MLA, Vancoover et cetera or the generic BibTex.</p>
<h3 id="heading-google-scholar-extension-for-chrome">Google Scholar Extension for Chrome</h3>
<p><img src="https://web.archive.org/web/20161017112908im_/http://adhikary.net/forestryio/images/Screen%20Shot%202016-09-08%20at%205.43.17%20AM.png" alt /></p>
<p>This extension lets you search for any piece of text on Google Scholar. Also lets you discover papers, generate citations all without leaving your current tabs. I find it extremely handy for generating quick citations and searching for referenced papers while reading.</p>
<p>I am planning to write down a very basic tutorial on LaTeX syntax sometimes in the near future. Please let me know in the comments if you are interested.</p>
]]></content:encoded></item><item><title><![CDATA[SSH + Root Access on Xiaomi Mi Router Nano / Lite / Youth]]></title><description><![CDATA[Obtaining ssh access along with root is as simple as flashing the Developer ROM and setting the root password via a POST request. However, the Developer ROM is completely in Chinese. Thus, it is advisable to have a copy of Google Chrome installed for...]]></description><link>https://blog.adhikary.net/ssh-root-access-on-xiaomi-mi-router-nano-lite-youth</link><guid isPermaLink="true">https://blog.adhikary.net/ssh-root-access-on-xiaomi-mi-router-nano-lite-youth</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Mon, 11 Jul 2016 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Obtaining ssh access along with root is as simple as flashing the <code>Developer ROM</code> and setting the root password via a POST request. However, the Developer ROM is completely in Chinese. Thus, it is advisable to have a copy of Google Chrome installed for automatic translation. Let’s get started.</p>
<ol>
<li><p>Download the <a target="_blank" href="https://web.archive.org/web/20161218233524/http://bigota.miwifi.com/xiaoqiang/rom/r1cl/miwifi_r1cl_all_59371_2.1.26.bin">Official Developer ROM</a></p>
</li>
<li><p>Visit <a target="_blank" href="https://web.archive.org/web/20161218233524/http://192.168.31.1/">http://192.168.31.1</a>, login and manually upgrade to the Official Developer ROM. Ignore any warning regarding downgrading.</p>
</li>
<li><p>Wait for 5-7 minutes. After the router is back on again, you need to set a root password to be able to log in. Login to the router and copy the “stok” but from the address bar. Open up a shell and,</p>
</li>
</ol>
<pre><code class="lang-bash">curl -d <span class="hljs-string">"oldPwd=your_admin_pass&amp;newPwd=desired_root_pass"</span> \
<span class="hljs-string">"http://192.168.31.1/cgi-bin/luci/;stok=&lt;stok from browser url&gt;/api/xqsystem/set_name_password"</span>
</code></pre>
<ol>
<li><p>Now a response should indicate a code. If the code is set to 0, you have successfully set your password. Otherwise if you receive a text in chinese, translate that to figure out what is wrong.</p>
</li>
<li><p>Happy Hacking!</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Cygwin + Oh-my-zsh + Solarized Theme + apt-cyg on Windows 10]]></title><description><![CDATA[As a Python developer as well as a long-time avid user of Linux and Mac OS, I just could not use a computer without a unix-like shell and a decent command-line interface. Thus kept digging until I found the perfect solution for me, the title of the p...]]></description><link>https://blog.adhikary.net/cygwin-oh-my-zsh-solarized-theme-apt-cyg-on-windows-10</link><guid isPermaLink="true">https://blog.adhikary.net/cygwin-oh-my-zsh-solarized-theme-apt-cyg-on-windows-10</guid><category><![CDATA[Windows 10]]></category><category><![CDATA[Bash]]></category><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Thu, 02 Jun 2016 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>As a Python developer as well as a long-time avid user of Linux and Mac OS, I just could not use a computer without a unix-like shell and a decent command-line interface. Thus kept digging until I found the perfect solution for me, the title of the post itself. Let’s get started.</p>
<p><img src="https://web.archive.org/web/20161220011130im_/http://i.imgur.com/bRcza7o.png" alt="cygwin" /></p>
<h3 id="heading-install-cygwin">Install Cygwin</h3>
<p>According to the website of <a target="_blank" href="https://web.archive.org/web/20161220011130/https://www.cygwin.com/">Cygwin</a>, Cygwin is “a large collection of <strong>GNU and Open Source tools</strong>which provide <strong>functionality</strong> similar to a <strong>Linux distribution</strong> on Windows.” It provides a decent terminal interface with the GNU / Unix tools you love and crave for. You should download the 32-bit (<a target="_blank" href="https://web.archive.org/web/20161220011130/https://www.cygwin.com/setup-x86.exe">setup-x86.exe</a>) or 64-bit (<a target="_blank" href="https://web.archive.org/web/20161220011130/https://www.cygwin.com/setup-x86_64.exe">setup-x86_64.exe</a>) installer according to the configuration of your computer.</p>
<p><img src="https://web.archive.org/web/20161220011130im_/http://i.imgur.com/voo38GV.png" alt="cygwin installation" /></p>
<p>Open the installer and follow the on-screen instructions, on the package selection screen, make sure to install <em>at least</em> <strong>zsh</strong>, <strong>git</strong>, <strong>nano</strong> and <strong>wget</strong> alongside the default selections. Once the installation is complete, you will find a Cygwin Terminal in your Start Menu (Is it still called start?).</p>
<p>[Note: Install the Cygwin git even if you already have Git for WIndows installed.]</p>
<h3 id="heading-set-zsh-as-the-default-shell">Set zsh as the default shell</h3>
<p>Open up Cygwin Terminal. Cygwin does not have <code>chsh</code> for changing shells, nor does it have a <code>/etc/passwd</code> file. Thus, we need to make one (Thanks <a target="_blank" href="https://web.archive.org/web/20161220011130/http://superuser.com/questions/351435/zsh-with-cygwin#comment1487113_351437">BrunoLM</a>).</p>
<pre><code class="lang-bash">mkpasswd -l -p <span class="hljs-string">"<span class="hljs-subst">$(cygpath -H)</span>"</span> &gt; /etc/passwd
</code></pre>
<p>Open the <code>/etc/passwd</code> file for editing.</p>
<pre><code class="lang-bash">nano /etc/passwd
</code></pre>
<p>You will be presented with a gigantic text file. Find <strong>the line that begins with your username</strong>. Go the the end of that line, and replace <code>/bin/bash</code> with <code>/bin/zsh</code>.</p>
<h3 id="heading-install-oh-my-zsh">Install oh-my-zsh</h3>
<p><a target="_blank" href="https://web.archive.org/web/20161220011130/https://github.com/robbyrussell/oh-my-zsh">oh-my-zsh</a> is a configuration (+ theme / plugin system) for the Z Shell. The oh-my-zsh installation script should be fetched and executed through the “wget method”, since we did not yet install curl. So, in the Cygwin Terminal and paste the following,</p>
<pre><code class="lang-bash">sh -c <span class="hljs-string">"<span class="hljs-subst">$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)</span>"</span>
</code></pre>
<p>zsh should be installed and ready for configuration.</p>
<h3 id="heading-solarized-theme-and-powerline-fonts">Solarized Theme and Powerline fonts</h3>
<p>Karlin Fox ported the Solarized theme to MinTTY (the terminal which comes by default with Cygwin), and it is available at <a target="_blank" href="https://web.archive.org/web/20161220011130/https://github.com/karlin/mintty-colors-solarized">karlin/mintty-colors-solarized</a>.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/karlin/mintty-colors-solarized.git ~/.solarized
<span class="hljs-built_in">echo</span> <span class="hljs-string">'source ~/.solarized/mintty-solarized-dark.sh'</span> &gt;&gt; ~/.zshrc <span class="hljs-comment"># for light, replace dark with light</span>
</code></pre>
<p>Some fancy zsh themes require powerline-patched fonts. Powerline patched versions of the most popular mono fonts are available at <a target="_blank" href="https://web.archive.org/web/20161220011130/https://github.com/powerline/fonts">powerline/fonts</a>. Install the ones required after cloning / downloading (zip) the repository. Make sure to change the font of MinTTY.</p>
<p><img src="https://web.archive.org/web/20161220011130im_/http://i.imgur.com/fsYzdxk.png" alt="MinTTY" /></p>
<p>Right click the title bar of the Terminal, click Options. Change your font to a Powerline patched font you installed.</p>
<h3 id="heading-install-apt-cyg">Install apt-cyg</h3>
<p><a target="_blank" href="https://web.archive.org/web/20161220011130/https://github.com/transcode-open/apt-cyg">apt-cyg</a> acts similar to apt-get, works great for installing packages! Installation is fairly straightforward,</p>
<pre><code class="lang-bash">lynx -<span class="hljs-built_in">source</span> rawgit.com/transcode-open/apt-cyg/master/apt-cyg &gt; apt-cyg
install apt-cyg /bin
</code></pre>
<p>That should help you get started!</p>
]]></content:encoded></item><item><title><![CDATA[Building Firefox OS for Symphony GoFox F15]]></title><description><![CDATA[Building Firefox OS for Symphony GoFox F15 is pretty straightforward, but requires a few extra steps than a standard Firefox OS build for most other devices. The device dolphin refers to a family of devices powered by Spreadtrum chipsets. So, logical...]]></description><link>https://blog.adhikary.net/building-firefox-os-for-symphony-gofox-f15</link><guid isPermaLink="true">https://blog.adhikary.net/building-firefox-os-for-symphony-gofox-f15</guid><dc:creator><![CDATA[Aniruddha Adhikary]]></dc:creator><pubDate>Sun, 14 Dec 2014 04:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Building Firefox OS for Symphony GoFox F15 is pretty straightforward, but requires a few extra steps than a standard Firefox OS build for most other devices. The device <code>dolphin</code> refers to a family of devices powered by Spreadtrum chipsets. So, logically, you would clone the <code>mozilla-b2g/B2G</code> repository and configure a build environment for dolphin.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/mozilla-b2g/B2G.git
<span class="hljs-built_in">cd</span> B2G
./config.sh dolphin
</code></pre>
<p>The resulting images will result in a device showing a white bootscreen if flashed to a GoFox F15. Why? If you plunge down into this repository, you will find a lot of target devices to build for. <code>scx15_x3542plus</code> is our target device, this denotes our Symphony GoFox F15. However, the device <code>scx15_sp7715ga</code> is selected by default, causing the conflict. To resolve this, just do a little search and replace in the <a target="_blank" href="http://config.sh"><code>config.sh</code></a> file.</p>
<pre><code class="lang-bash">sed -i <span class="hljs-string">'s/scx15_sp7715ga/scx15_x3542/g'</span> config.sh
</code></pre>
<p>Now, we are ready to build Firefox OS for GoFox! Make sure to use the <code>v1.4</code> or <code>v2.1</code> branch to build, upto writing the blog posts, the other branches failed to boot on GoFox F15 in my experiments.</p>
<pre><code class="lang-bash">BRANCH=v1.4 ./config.sh dolphin
</code></pre>
<p>And then finally make sure you have something to do while you wait for the very lengthy build process to complete, and issue a build.</p>
<pre><code class="lang-bash">./build.sh
</code></pre>
<p>And you will have your images (<code>boot.img</code>, <code>recovery.img</code>, <code>system.img</code>, <code>cache.img</code>, <code>userdata.img</code>) ready in <code>out/target/product/scx15_x3542</code> to be flashed via fastboot</p>
]]></content:encoded></item></channel></rss>