<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Karthik D</title>
    <description>The latest articles on DEV Community by Karthik D (@kdqed).</description>
    <link>https://dev.to/kdqed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F204417%2F990f327b-e974-480a-91c6-f64b1be41f21.png</url>
      <title>DEV Community: Karthik D</title>
      <link>https://dev.to/kdqed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kdqed"/>
    <language>en</language>
    <item>
      <title>Introducing Zaturn MCP</title>
      <dc:creator>Karthik D</dc:creator>
      <pubDate>Fri, 25 Apr 2025 10:02:46 +0000</pubDate>
      <link>https://dev.to/kdqed/introducing-zaturn-mcp-442a</link>
      <guid>https://dev.to/kdqed/introducing-zaturn-mcp-442a</guid>
      <description>&lt;p&gt;Hello folks, I'm working on Zaturn: an AI co-pilot for analyzing your data.&lt;/p&gt;

&lt;p&gt;Zaturn MCP enables querying and understanding your data using natural language. Instead of writing SQL or Python, you describe what you're looking for in plain English, and AIs can translate that into structured queries, run them against your data sources, and return results, often with visualizations or summaries where useful.&lt;/p&gt;

&lt;p&gt;Zaturn integrates with Claude Desktop (or any MCP-compatible client), so you can plug in your databases, describe your goals or questions, and get back answers that make sense in context. You can ask things like “Who are our highest-spending users this quarter?” or even broader prompts like “What trends should we look into based on this dataset?”&lt;/p&gt;

&lt;p&gt;Under the hood, Zaturn enables AI to inspect the schema, generate queries, and build a thread of reasoning around what it finds — not just a single chart, but a sequence of observations, follow-ups, and possible next steps. It’s a way to explore data conversationally, without needing to load up a Jupyter notebook or wrestle with BI dashboards.&lt;/p&gt;

&lt;p&gt;Check it out at &lt;a href="https://github.com/kdqed/zaturn" rel="noopener noreferrer"&gt;https://github.com/kdqed/zaturn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>sql</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Dear "international" companies, stop asking me for my last name and credit card</title>
      <dc:creator>Karthik D</dc:creator>
      <pubDate>Mon, 10 May 2021 16:17:06 +0000</pubDate>
      <link>https://dev.to/kdqed/dear-international-companies-stop-asking-me-for-my-last-name-and-credit-card-4jeh</link>
      <guid>https://dev.to/kdqed/dear-international-companies-stop-asking-me-for-my-last-name-and-credit-card-4jeh</guid>
      <description>&lt;p&gt;Dear "international" companies, stop asking me for my last name and credit card, because I don't have either!&lt;/p&gt;

&lt;p&gt;Yes, the .com stuff did start in the US, but technology is now international and products need to be more inclusive of cultural aspects. I live in India and in this post I'm covering two most annoying aspects of non-inclusive UX design as per my experience. I have picked them in particular because they seemed to have become the default for most designers, who blindly put them in without a thought for the target user base.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What's in a name(s)?
&lt;/h2&gt;

&lt;p&gt;My official name is Karthik D, and the D actually stands for my dad's name and isn't my last name. I really wonder if my family ever had a last name - in India, that could have been a caste/religion name, which my great-great-grandfather had postfixed to his name as Chakrapani Mudaliar, or a native place name which my great grandfather had prefixed as an initial to his name AC Shankarraj (AC = Arcot Chakrapani). I appreciate the idea of caste name becoming irrelevant, and I really hope someday caste also becomes irrelevant in this country. My grandfather dropped the native place name Arcot probably because he wasn't born or raised there. I really don't know. From my grandfather onwards, we have been only been using father's name as an initial, and also either prefixing or suffixing it, inconsistently, as we please. My early school records say D. Karthik while in most other places it is Karthik D. &lt;/p&gt;

&lt;p&gt;My intention is not to put up my family history on a design blog, but the problem is, I cannot offer the above explanation when I land on a sign-up form and the last name field is mandatory. Mostly I get away with entering "Karthik" for first name and "D" for last name, but some notorious sites complain the last name is too short. WTF! I then have to enter my last name as "Devan" which is my dad's name, and then voila! The site starts addressing me as Mr. Devan. That's not me, that's my dad, you #$^#s! &lt;/p&gt;

&lt;p&gt;To make my point with more examples: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Family Name comes before the given name is some countries (eg: Japan, Korea, Hungary)&lt;/li&gt;
&lt;li&gt;In Spain, people have a first name followed by two surnames - one from each parent.&lt;/li&gt;
&lt;li&gt;In India (mind you, this is where things go haywire), there is no dominant naming pattern at all: a person can have anywhere between zero to 8 names or even more. This may include one or more given names, parents' names, family names, place names, caste names, occupation names, nick names and not even to mention a plethora of honorifics like Mr., Shri., Thiru. that change from language to language which people may want to enter in the name field. We have a "Farokh Engineer" who is actually a sportsperson. I have also given my example above as a case to illustrate that naming pattern is not consistent even within a family.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point is, for most use cases, the name of the user is not at all relevant to the service provided by the website/app. Yet, multiple and even very well known companies demand a last name while signing up. Even the likes of Google and Facebook. Its not like I cannot search the web or send emails without having a last name. I'm sure Facebook can still sell my data without needing my last name. It has simply become the default for UX design and this needs to change. May be a single "Full Name" field or "What should we call you?" or "Name as per government identification" will make things easier for the user, save priceless real estate on the front-end and a precious column in the database too!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Credit card eh? What's that?
&lt;/h2&gt;

&lt;p&gt;My next rant is about credit card payments being the only option on plenty of international services, which are actually trying to expand in the Indian market. This includes cloud services providers such as DigitalOcean, AWS, Google Cloud etc, and a host of entertainment services such as Netflix, YouTube Premium, MUBI etc.&lt;/p&gt;

&lt;p&gt;Firstly, not everyone is eligible for a credit card. In India, credit cards are used by a very privileged few who are eligible for it, while most of the population struggles to use a debit card despite having one. As of today, &lt;a href="https://www.npci.org.in/what-we-do/upi/product-overview" rel="noopener noreferrer"&gt;UPI&lt;/a&gt; is the most user friendly payment option available here. &lt;/p&gt;

&lt;p&gt;Second, not everyone wants to use a credit card. While I only recently became eligible to get a credit card, I do not use one because it is an additional hassle. I'd rather use a debit card and pay directly from bank account balance rather than pay from a card and pay off another bill at the end of the month. Also, I personally do not like being in debt or borrowing money, and plenty of cultures around the world discourage taking debts.&lt;/p&gt;

&lt;p&gt;Thirdly, they are a security nightmare. Most card numbers can be charged without authentication i.e., cash can be drawn from the cards with just the card number, and most websites insist on using such cards. In India, most banks disable this kind of charging by default and the card only be charged with a second-factor authentication via OTP sent to the user's phone. Netbanking and UPI transactions need user authentication too. Data breaches leading to stolen credit card numbers have been a major issue worldwide, while stolen NetBanking IDs or UPI IDs are practically useless without passwords and access to the user's device.&lt;/p&gt;

&lt;h2&gt;
  
  
  To conclude
&lt;/h2&gt;

&lt;p&gt;It is very shocking to see how blatantly companies have ignored local and cultural preferences in key aspects of design such as names and payments. What is more shocking is that, very popular companies such as Google &amp;amp; Facebook with billions of users in countries such as India, have compeltely ignored these aspects too. If you're a designer or developer or product lead reading this, it is my kind request that you do some research on cultural preferences of your intended audience before blindly putting in the defaults.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>culture</category>
      <category>database</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Hosting a website / webserver on your PC / Laptop using Reverse SSH Tunnel on a custom domain name</title>
      <dc:creator>Karthik D</dc:creator>
      <pubDate>Tue, 20 Apr 2021 05:30:43 +0000</pubDate>
      <link>https://dev.to/kdqed/hosting-a-website-webserver-on-your-pc-laptop-using-reverse-ssh-tunnel-on-a-custom-domain-name-11ma</link>
      <guid>https://dev.to/kdqed/hosting-a-website-webserver-on-your-pc-laptop-using-reverse-ssh-tunnel-on-a-custom-domain-name-11ma</guid>
      <description>&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A cloud server with SSH access to be used as jump server (yes you still need one)&lt;/li&gt;
&lt;li&gt;Local PC or Laptop&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE:&lt;br&gt;
If you do not have a cloud server, you can use &lt;a href="https://localhost.run/" rel="noopener noreferrer"&gt;localhost.run&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Step 1: Make sure you are able to SSH into your server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i &amp;lt;private_key_file&amp;gt; &amp;lt;username&amp;gt;@&amp;lt;your_domain_or_ip&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Setup the tunnel&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i &amp;lt;private_key_file&amp;gt; -N -T -R &amp;lt;remote port&amp;gt;:localhost:&amp;lt;local port&amp;gt; &amp;lt;username&amp;gt;@&amp;lt;your_domain_or_ip&amp;gt;
# e.g.:
ssh -i private.key -N -T -R 2523:localhost:8000 user@kdnanmaga.xyz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example will tunnel port number 8000 on my local machine to port number 2523 on the remote machine&lt;/p&gt;

&lt;p&gt;Step 3: Verify the tunnel is working&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# On local machine
$ python3 -m http.server 8000 # Or any other test server

# On cloud machine
$ curl http://localhost:2523
# You must be able to see the contents of your local folder printed here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4: Setup a reverse proxy using NGINX on the cloud server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install NGINX if not present
$ sudo apt install nginx

# Add server block as shown below
$ sudo nano /etc/nginx/sites-available/local

# Symlink and activate
$ sudo ln -s /etc/nginx/sites-available/local /etc/nginx/sites-enabled/
$ sudo systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# File contents for /etc/nginx/sites-available/local
server{
  server_name &amp;lt;your domain name&amp;gt;;
  location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_pass http://localhost:2523/;
    proxy_redirect off;
    proxy_read_timeout 240s;
  }

  listen 80;
}    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5: Make sure DNS for the domain name you used above has an A record poiting to your server IP&lt;/p&gt;

&lt;p&gt;Step 6: Install SSL certificate using Let's Encrypt so you can access via https://&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt install python-certbot-nginx
$ sudo certbot --nginx -d &amp;lt;your domain name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the commands in Step 2 and Step 3 still running, you should be able to access your local machine via the domain name now! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find me on twitter: @&lt;a href="https://twitter.com/1upkd" rel="noopener noreferrer"&gt;1upkd&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Loading a large json file into elixir's ETS (Erlang Term Storage) Cache using Jaxon</title>
      <dc:creator>Karthik D</dc:creator>
      <pubDate>Tue, 13 Apr 2021 10:19:58 +0000</pubDate>
      <link>https://dev.to/kdqed/loading-a-large-json-file-into-elixir-s-ets-erlang-term-storage-cache-using-jaxon-43bf</link>
      <guid>https://dev.to/kdqed/loading-a-large-json-file-into-elixir-s-ets-erlang-term-storage-cache-using-jaxon-43bf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://kdnanmaga.xyz/how-to-load-a-large-json-file-into-elixir-ets-cache/" rel="noopener noreferrer"&gt;Original article: https://kdnanmaga.xyz/how-to-load-a-large-json-file-into-elixir-ets-cache/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Elixir's ETS cache is an in-memory data store that can be accessed across processes. It can be used to build lookup tables such as geocoders, translators etc. in web applications.&lt;/p&gt;

&lt;p&gt;For an application I was building, I had to load a large dataset (~500k rows) of geocodes into an ETS table before the webserver endpoint starts. This data can be shared across all the processes that handle incoming requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  First attempt: Load the file and then parse
&lt;/h2&gt;

&lt;p&gt;At first, I attempted loading the file into memory, then parsing it with Jason and...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# here my json is one single root object with key-value pairs
def load_file(filename, tablename) do      
  :ets.new(tablename, [:named_table])
  with {:ok, body} &amp;lt;- File.read(filename), {:ok, json} &amp;lt;- Jason.decode(body),
  do: load_from_map(json, tablename)
end

defp load_from_map(parsed_map, tablename) do
  :ets.new(tablename, [:named_table])
  for {k,v} &amp;lt;- parsed_map do
    :ets.insert(tablename, {k,v})
  end
end              
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It worked, but it took quite a while and hogged quite some RAM. My machine with 4GB RAM froze for about a minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming to the rescue
&lt;/h2&gt;

&lt;p&gt;At this point, I thought there could be a better way to do this, may be something that doesn't involve reading the entire file into memory. That's when I found &lt;a href="https://github.com/boudra/jaxon" rel="noopener noreferrer"&gt;Jaxon&lt;/a&gt;, a streaming JSON Parser. So now the file is opened as a stream and the JSON is parsed as the stream is being read. Pretty neat right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# here my json is an array of objects {"k":&amp;lt;key&amp;gt;,"v":&amp;lt;value&amp;gt;}
def load_file(filename, tablename) do      
  :ets.new(tablename, [:named_table])
  filename
  |&amp;gt; File.stream!()
  |&amp;gt; Jaxon.Stream.from_enumerable()
  |&amp;gt; Jaxon.Stream.query([:root, :all])
  |&amp;gt; Stream.each(fn (kv) -&amp;gt; :ets.insert(tablename, {kv["k"],kv["v"]}) end)
  |&amp;gt; Stream.run()
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first this didn't seem to work and I was disappointed until I realized I my JSON wasn't pretty and was just a single line. I generated a multi-line pretty JSON and voila! It worked!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find me on twitter: &lt;a href="https://twitter.com/xqzkio" rel="noopener noreferrer"&gt;@xqzkio&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>elixir</category>
      <category>cache</category>
      <category>jaxon</category>
      <category>json</category>
    </item>
  </channel>
</rss>
