2025 4

Mapscii Rendering

I asked Claude Sonnet 4.5 on GitHub Copilot: How does mapscii render vector tiles as text blocks on the terminal? What are the libraries it uses and how does it use them? Explain as a detailed tutorial with examples so that I can learn how to rasterize vector shapes on the terminal. Below’s the explanation. What’s noteworthy to me is: How it uses Braille characters to get 8 pixels per character cell (2x4 grid). How it fills polygons using (a) triangulation and (b) getting all edge points using Bresenham’s algorithm, then (c) filling horizontal spans between edge pairs. I’ll help you understand how mapscii renders vector tiles as text blocks on the terminal. Let me search through the repository to find the relevant code and understand the architecture. Now let me get more specific files to understand the rendering pipeline better:# How MapSCII Renders Vector Tiles as Text Blocks on the Terminal ...

Patterns for Short Code

I had Claude Code create a PR to update my Unicoder tool. As part of that, I prompted it to repeatedly: Shorten the code by exploring opportunities to rewrite more elegantly. Finally, I asked it: You applied several changes to refactor the code for elegance and brevity. What were the principles you applied? List them all with examples. The objective is to teach me how to shorten and simplify code elegantly. Its response was a good tutorial on refactoring to shorten and simplify code. ...

Reusable libraries

From a folder sym-linked to multiple projects, identify reusable libraries and functions. # Role and Objective - Analyze all .py, .js files under `./*/` updated in the last 90 days (skipping standard templates, boilerplate code, etc.) and update `./reuse.md` to: 1. Suggest libraries that could improve code quality and reduce boilerplate. 2. Identify reusable functions and opportunities for generalization. # Checklist Begin with a concise checklist (3-7 bullets) outlining your steps: - Enumerate all specified files under `./*/`. Note: directories under `./` are symlinks. - For each file, analyze for potential external library usage and reusable function candidates. - Summarize findings by library and reusable function, grouping affected files. - Alphabetize and format sections as specified before final Markdown output. - Validate that all files are processed. # Instructions - For each file: - Identify code that could be replaced with modern, popular libraries. - Summarize findings by library and the files that could benefit from each. - Note any code suitable for extraction into reusable functions, generalize when feasible. - Alphabetize libraries and functions in their respective sections. ## Sub-categories ### External Libraries - List each identified library (bulleted, alphabetized). - For each, sub-list the affected file(s) (bulleted, relative paths). ### Reusable Functions - For each reusable/generalized function (bulleted, alphabetized): - **Signature:** Provide as a Markdown code block. - **Docstring:** 1-line summary. - **Files Benefiting from This Function:** Bulleted list of relevant files. - **Library:** Markdown code block(s), indented. # Agentic Operation and Verification - Attempt an autonomous first pass using available information; escalate with a clarifying question only if ambiguities arise. - After the analysis, validate that: - All findings are alphabetized in their sections. - Every file is categorized. - Output matches the required Markdown structure and section order. - If success criteria are not met (e.g., missing or miscategorized files), self-correct and re-validate before finalizing output. # Output Format - All sections must be valid Markdown. - Use unordered (bulleted) lists. - Section order: 1. Checklist 2. External Libraries 3. Reusable Functions # Stop Conditions - Stop when the updated Markdown file comprehensively reflects all findings, in the correct format. - Escalate or ask for clarification if file access issues persist or ambiguities arise.

Things I Learned - 06 Jul 2025

This week, I learned: When adding a coding benchmark for LLMs, here’s a question I’d like to add. #benchmark How do I use Apache Arrow in the browser via cdn.jsdelivr.net to create a .parquet file and download it? Give me minimal working code I can paste in the browser console to test. LinkedIn has an undocumented link that shows schedules posts at https://www.linkedin.com/share/management/ which redirects to https://www.linkedin.com/feed/?shareActive=true&view=management Here’s a JS snippet you can paste in the DevTools console of an npm package version page (example) to get a Markdown list showing the versions and dates copy( $$('table[aria-labelledby="version-history"] tbody tr') .map((tr) => { const a = tr.querySelector("a"); const date = new Date(tr.querySelector("time").getAttribute("datetime")).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric", }); return `- [${a.textContent.trim()}](https://npmjs.com${a.getAttribute("href")}): ${date}.`; }) .join("\n"), ); DuckDB can read JSON APIs! Ref ⭐ When bringing in humans-in-the-loop, applications must make it easier to review and to edit the work.

2024 1

Breaking mental coding barriers with LLMs

Today, I stepped a bit beyond my comfort zone. Usually, I prefer micro-managing LLMs when writing code. This time, I was macro-managing. I needed to create a mock history of the status of a manuscript, e.g. it was submitted on this date. THEN it moved to this state on this date. THEN … etc. I have no idea what the states could be, though. So, I could send it to an LLM, and it would give a different set of states each time. Or I could write a program and lose out on variety. ...

2021 2

Cyborg scraping

LinkedIn has a page that shows the people who most recently followed you. At first, it shows just 20 people. But as you scroll, it keeps fetching the rest. I’d love to get the full list on a spreadsheet. I’m curious about: What kind of people follow me? Which of them has the most followers? Who are my earliest followers? But first, I need to scrape this list. Normally, I’d spend a day writing a program. But I tried a different approach yesterday. ...

Programming Minecraft with Websockets

Minecraft lets you connect to a websocket server when you’re in a game. The server can receive and send any commands. This lets you build a bot that you can … (well, I don’t know what it can do, let’s explore.) Minecraft has commands you can type on a chat window. For example, type / to start a command and type setblock ~1 ~0 ~0 grass changes the block 1 north of you into grass. (~ means relative to you. Coordinates are specified as X, Y and Z.) ...

2012 1

Auto reloading pages

After watching Bret Victor’s Inventing on Principle, I just had to figure out a way of getting live reloading to work. I know about LiveReload, of course, and everything I’ve heard about it is good. But their Windows version is in alpha, and I’m not about to experiment just yet. This little script does it for me instead: (function(interval, location) { var lastdate = ""; function updateIfChanged() { var req = new XMLHttpRequest(); req.open("HEAD", location.href, false); req.send(null); var date = req.getResponseHeader("Last-Modified"); if (!lastdate) { lastdate = date; } else if (lastdate != date) { location.reload(); } } setInterval(updateIfChanged, interval); })(300, window.location); It checks the current page every 300 milliseconds and reloads it if the Last-Modified header is changed. I usually include it as a minified script: ...

2011 2

Codecasting

The best way to explain code to a group of people is by walking through it. If they’re far away in space or time, then a video is the next best thing. You can recommend them to try out the best coding apps as well. The trouble with videos, though, is that they’re big. I can’t host them on my server – I’d need YouTube. Editing them is tough. You can’t copy & paste code from videos. And so on. One interesting alternative is to use presentations with audio. Slideshare, for instance, lets you share slides and sync it with audio. That almost works. But it’s still not good enough. I’d like code to be stored as code. What I really need is codecasting: a YouTube or Slideshare for code. The closest I’ve seen until day-before was etherpad or ttyrec – but neither support audio. Enter Popcorn. It’s a Javascript library from Mozilla that, among other things, can fire events when an audio/video element reaches a particular point. ...

Javascript arrays vs objects

Summary: Arrays are a lot smaller than objects, but only slightly faster on newer browsers. I’m writing an in-memory Javascript app that handles several thousand rows. Each row could be stored either as an array [1,2,3] or an object {"x":1,"y":2,"z":3}. Having read up on the performance of arrays vs objects, I thought I’d do a few tests on storing numbers from 0 to 1 million. The results for Chrome are below. (Firefox 7 was similar.) ...

2009 3

Error logging with Google Analytics

A quick note: I blogged earlier about Javascript error logging, saying that you can wrap every function in your code (automatically) in a try{} catch{} block, and log the error message in the catch{} block. I used to write the error message to a Perl script. But now I use Google’s event tracking. var s = []; for (var i in err) s.push(i + "=" + err[i]); s = s.join(" ").substr(0, 500); pageTracker._trackEvent("Error", function_name, s); The good part is that it makes error monitoring a whole lot easier. Within a day of implementing this, I managed to get a couple of errors fixed that had been pending for months. ...

Random quotes generator

The Random Quotes Generator is a simple tool that creates quotes by mixing up words on a web page. The results are often funny, but sometimes surprisingly insightful. Yes, this is the equivalent of a million monkeys typing Shakespeare, except that they’re using the works of Shakespeare as a starting point. And it doesn’t have to be Shakespeare. It could be you or your friends. ...

Client side scraping for contacts

By curious coincidence, just a day after my post on client side scraping, I had a chance to demo this to a client. They were making a contacts database. Now, there are two big problems with managing contacts. Getting complete information Keeping it up to date Now, people happy to fill out information about themselves in great detail. If you look at the public profiles on LinkedIn, you’ll find enough and more details about most people. ...

2008 3

Bound methods in Javascript

The popular way to create a class in Javascript is to define a function and add methods to its prototype. For example, let’s create a class Node that has a method hide(). var Node = function(id) { this.element = document.getElementById(id); }; Node.prototype.hide = function() { this.style.display = "none"; }; If you had a header, say Heading, then this piece of code will hide the element. var node = new Node("header"); node.hide(); If I wanted to hide the element a second later, I am tempted to use: var node = new Node("header"); setTimeout(node.hide, 1000); … except that it won’t work. setTimeout has no idea that the function node.hide has anything to do with the object node. It just runs the function. When node.hide() is called by setTimeout, the this object isn’t set to node, it’s set to window. node.hide() ends up trying to hide window, not node. ...

JPath - XPath for Javascript

XPath is a neat way of navigating deep XML structures. It's like using a directory structure. /table//td gets all the TDs somewhere below TABLE. Usually, you don't need this sort of a thing for data structures, particularly in JavaScript. Something like table.td would already work. But sometimes, it does help to have something like XPath even for data structures, so I built a simple XPath-like processor for Javascript called JPath. Here are some examples of how it would work: ...

Chaining functions in Javascript

One of the coolest features of jQuery is the ability to chain functions. The output of a function is the calling object. So instead of writing: var a = $("<div></div>"); a.appendTo($("#id")); a.hide(); … I can instead write: $("<div></div>").appendTo($("#id")).hide(); A reasonable number of predefined Javascript functions can be used this way. I make extensive use of it with the String.replace function. But where this feature is not available, you an create it in a fairly unobstrusive way. Just add this code to your script: ...

2007 7

Javascript error logging

If something goes wrong with my site, I like to know of it. My top three problems are: The site is down A page is missing Javascript isn’t working This is the last of 3 articles on these topics. I am a bad programmer I am not a professional developer. In fact, I’m not a developer at all. I’m a management consultant. (Usually, it’s myself I’m trying to convince.) Since no one pays me for what little code I write, no one shouts at me for getting it wrong. So I have a happy and sloppy coding style. I write what I feel like, and publish it. I don’t test it. Worse, sometimes, I don’t even run it once. I’ve sent little scripts off to people which wouldn’t even compile. I make changes to this site at midnight, upload it, and go off to sleep without checking if the change has crashed the site or not. But no one tells me so At work, that’s usually OK. On the few occasions where I’ve written Perl scripts or VB Macros that don’t work, people call me back within a few hours, very worried that THEY’d done something wrong. (Sometimes, I don’t contradict them.) It can be quite a stressful experience but good thing you can learn more here on how to cope up with it. On my site, I don’t always get that kind of feedback. People just click the back button and go elsewhere. Recently, I’ve been doing more Javascript work on my site than writing stuff. Usually, the code works for me. (I write it for myself in the first place.) But I end up optimising for Firefox rather than IE, and for the plugins I have, etc. When I try the same app a few months later on my media PC, it doesn’t work, and shockingly enough, no one’s bothered telling me about it all these months. They’d just click, nothing happens, they’d vanish. But their browsers can tell me The good part about writing code in Javascript is that I can catch exceptions. Any Javascript error can be trapped. So since the end of last year, I’ve started wrapping almost every Javascript function I write in a try {} catch() {} block. In the catch block, I send a log message reporting the error. The code looks something like this: ...

Handling missing pages

If something goes wrong with my site, I like to know of it. My top three problems are: The site is down A page is missing Javascript isn’t working This article covers the second topic. One thing I’m curious about is hits to non-existent pages (404s) on my site. I usually get 404s because: I renamed the page Someone typed a wrong URL Someone followed a wrong link Find the 404 ...

Website load distribution using Javascript

My music search engine shows a list of songs as you type – sort of like Google’s autosuggest feature. I load my entire list of songs upfront for this to work. Though it’s compressed to load fast, each time you load the page, it downloads about 500KB worth of song titles. My allotted bandwidth on my hosting service is 3GB per month. To ensure I don’t exceed it, I uploaded the songs list to an alternate free server: Freehostia. This keeps my load down. If I exceed Freehostia’s limit, my main site won’t be affected – just the songs. I also uploaded half of them to Google Pages, to be safe. ...

A busy break from blogging

Between July 17th and August 22nd, I saw 57 movies and read 7 books. There were Saturdays when I watched four movies back-to-back. (I tried five. Couldn’t stay awake.) Amidst this, I also cooked, cleaned, shopped… and went to office. (Oh yes, I was working 10 hours a day.) And managed to build some interesting sites which I’ll release in a while. But first, let me share the books with you. ...

Sparklines

John Resig has written a Sparklines library. Here’s an example. I wrote that HTTP download speeds not linear 182,315,313,319,314,459,441,445,453,525,567,552,577,587,580,581,590,663,639,658,616,705,720,695,739,750,720,741,803,800,800,818,800,856,796,816,866,841,836,828,861,893,859,905,881,885,946,944,943,984,1003,1012,994,979,977,986,1010,1017,1027,1000,1035,986,1006,1006,996,1022,1003,1053,1046,1061,1002,1064,1014,1039,1061,1023,1076,1081,1019,1064,1072,1089,1101,1069,1128,1125,1092,1155,1170,1067,1094,1082,1178,1211,1154,1169,1133,1161,1193,1167 and that they flatten out over time. A linear line would look like this: 180,190,201,211,221,232,242,252,262,273,283,293,304,314,324,335,345,355,365,376,386,396,407,417,427,438,448,458,468,479,489,499,510,520,530,541,551,561,572,582,592,602,613,623,633,644,654,664,675,685,695,705,716,726,736,747,757,767,778,788,798,808,819,829,839,850,860,870,881,891,901,912,922,932,942,953,963,973,984,994,1004,1015,1025,1035,1045,1056,1066,1076,1087,1097,1107,1118,1128,1138,1148,1159,1169,1179,1190,1200 The little red line here is a sparkline that’s based on real data. John’s javascript converts the data into a graph. Sparklines were introduced by Edward Tufte.

Hindi songs online

Click here to search for Hindi songs. This is an article on how I wrote the search engine. I find it a nuisance to have to go to Raaga, search for a song, not find it, then go to MusicIndiaOnline, not find it, then go to Musicplug.in, and so on until Google. So I got the list of songs from some of these sites, put it together in one place, and implemented a find-as-you-type. ...

The Next Big Language

Steve Yegge at Google talks about the features of the Next Big Language. He apparantly has inside information about the language corporates are likely to make a big push for. The comments seem to suggest Javascript 2.

2006 3

Making a Tamil transliterator

I've built a simple Tamil transliterator. You can type in words in English and it will spell them out in Tamil. You can copy-paste the Tamil above into Microsoft Word, etc. You may need to turn on tamil scripts to see the Tamil fonts above. If you have Windows 98, it may not work well. If you've visited this page recently, you will need to refresh this page as well (press F5). ...

Sanskrit transliterator

I’ve built a simple Sanskrit transliterator. You can type in words in English and it will spell them out in Sanskrit. You can copy-paste the Tamil above into Microsoft Word, etc. Browse through my Javascript to see how it works. Feel free to reuse. Comments ND 28 Aug 2006 12:00 pm: Real good and absolutely quick! Saurabh 28 Aug 2006 12:00 pm: Good work, wonder how many use Sanskrit these days though! One more thing, specific to Mac users, is that Indic support is still not mature for Firefox. Safari, the inbuilt browser does a decent job though. There was an extra “S” that was appearing after each letter in Safari. Madhu 28 Aug 2006 12:00 pm: Awesome, again what ur doing at Infy consulting, u shud be developing products at google:) KK 28 Aug 2006 12:00 pm: It is really awesome vikram 28 Aug 2006 12:00 pm: i cannot see any translation in firefox 1.5.0.12 version Animesh 28 Aug 2006 12:00 pm: Good tool, but the transliteration scheme should be replaced by more standard one. Ashwin (you know me!!) 28 Aug 2006 12:00 pm: nice one buddy!!although how would you deal with ambiguities like “om” ? Anand 28 Aug 2006 12:00 pm: Hmm, I wonder…can you please check if the small ‘‘i’’ maatra works fine? I gave the word ‘‘janani’’ and the ‘‘i’’ gave me the maatra AFTER the second ‘’na’’, while it should be BEFORE. The big ‘‘ii’’/‘‘I’’ works fine. Also words like ‘‘chithram’’ etc - basically wherever there is a small ‘‘i’’! Rama Krishna 28 Aug 2006 12:00 pm: Really Good. Keep up the good work mohana 28 Aug 2006 12:00 pm: try this swami neelkanth 28 Aug 2006 12:00 pm: thanks

Movie quote quiz

These are movie quotes. How many titles can you guess? (Use IMDb titles.) Comments Dhar 21 Jan 2006 1:55 am: Hmmm, I got 30 / 40. Nice one! ritzkini 21 Jan 2006 6:02 am: good one ! jake 21 Jan 2006 11:02 am: hey good quiz, i got 31: “seen me everyday for 16 years” should read “seen me everyday for 13 years”. S Anand 21 Jan 2006 11:02 am: Correction: “seen me everyday for 16 years” should read “seen me everyday for 13 years”. Another corrigendum 21 Jan 2006 12:55 pm: there’s a ’the’ mismatch in one of the answers S Anand 21 Jan 2006 1:14 pm: Oh, which quote? joe 21 Jan 2006 8:59 pm: why does the all time hits change? i remember seeing bill gates at 200 now it is done to 198. S Anand 21 Jan 2006 10:52 pm: I removed some duplicate entries last week (i.e. people accidentally clicking twice). Parshu 2 Feb 2006 6:37 am: how did you create this thng, when i type a name if right it becomes green and score gets updated. Kindly help me out with this technique. So i can too develop something on similar lines S Anand 2 Feb 2006 5:33 pm: The logic for turning stuff green is the onKeyUp function in those boxes. If what’s typed matches the encrypted answer, I turn the style.background attribute to green, and increment the quizCount element (which is just a span element) by 1. Hope it doesn’t sound Greek… just see the source. Ravi 3 Oct 2006 6:40 am: Good one anand. I got 34. I think i got the other 6 also but somehow not getting the names in the right format. These movies are sequels & have long names with colon etc. jb 2 Nov 2006 1:55 pm: nice Natasha & co 19 Nov 2006 6:36 am: my entire family working on this quiz for about 45 mins got 30/40! wooooo!!!! Kirsten 21 Nov 2006 11:34 am: Me n me family worked on this for lyk 30mins n we got 35/40 nice quiz…enjoyed it!!! cheers!! Kirsten & co 21 Nov 2006 11:35 am: woo! tibi 4 Jan 2007 1:41 am: i need the answers to ‘How do you solve a problem like Maria?’, ‘Everyone’s innocent in here, don’t you know that?’ and ‘How can you do that, look at me like you haven’t seen me everyday for 16 years.’ please, if you could help me… i like men 23 Jan 2007 7:22 pm: uh 40 out of 40 thats a pisser journalism7thperiod 23 Jan 2007 7:23 pm: notting hill? what kind of homo movie is that? if you ever quote that in real life kill yourself now!!! Anonymous 20 Jan 2006 12:00 pm: cool quiz Saibal 20 Jan 2006 12:00 pm: I got 36/40.. Dan 20 Jan 2006 12:00 pm: I got 40/40 ! how sad am I ! lol, but cool quiz ! look forward to the next one :-D chunk 20 Jan 2006 12:00 pm: some of these dont work when the title is right. huge nerd 20 Jan 2006 12:00 pm: good quiz i got 40 of 40 only after about 20 entires on the final question, not in imdb form. star wars: episode I - the phantom menace. otherwise awesome. Matthew 20 Jan 2006 12:00 pm: I got 40/40! Just shows how gib a movie buff i am. liz 20 Jan 2006 12:00 pm: i totally blanked out on some Batfred 20 Jan 2006 12:00 pm: Nice one, some real tough ones for once too. I had to google the rest after 34/40 as the frustration was strating to annoy me. Trevor Spence 20 Jan 2006 12:00 pm: Not good having double films! could the person that made this not think of 40 quotes from 40 different films! rhys 20 Jan 2006 12:00 pm: what is the answer to “there can only be one” is it the jet li movie “the one” Sam 19 Sep 2008 3:16 pm: Nice one know some of the other answers but cant place them george 5 Feb 2009 11:49 pm: what if there really is no spoon Larry Buesy 13 Feb 2009 7:17 pm: didn’t know much Jodie 16 Feb 2009 3:03 am: Man that was hard!!! Conner Darcy Rankin 25 Mar 2009 4:40 am: whats the answer to … How do you solve a problem like Maria?… really sweet quiz apart from this one question!!!!!! Jq 30 Sep 2010 8:21 pm: Some very neat ones ! Inflatable Bed 3 Dec 2010 1:35 am: the most memorable movie quote that i could think of is the one on Forest Gump ‘:~ KingViz 23 Dec 2011 11:27 am: Question 9 - the title absolutely does not start with “The…” Colette Cullen 10 Aug 2011 11:41 am: Great quiz (23/40)but where are the answers?

2005 7

10 places you must use Ajax

10 places you must use Ajax.

IMDb Torrent linker

IMDb Torrent linker – a GreaseMonkey script that shows torrents available when you browse the IMDb.

Delicious tags

If you move the mouse over a link, a popup appears, showing the most popular tags on del.icio.us for the link. Click on the tag to visit all related links on del.icio.us. Comments Sathish 15 Apr 2005 3:56 am: What is this post related to? Did try out the new “big del.icio.us post” script? or are you talking of something else? S Anand 15 Apr 2005 4:02 am: If you move your mouse over any of my blog posts, a tooltip pops up. Did you notice? Sathish 18 Apr 2005 5:05 am: I notice it now.. I notice it on the right hand side corner of the page.. I am using firefox to view.. is it how u planned to show it or is there a problem? S Anand 18 Apr 2005 6:03 am: Looks like a problem. I will check it out. sathish 20 Apr 2005 3:59 am: it works now..

lickr

lickr: Flickr, without the Flash. Flickr is a popular photo hosting service that uses embedded Flash files as part of their interface. On every page, there will be a little delay while a new Flash file loads. Lickr removes the need for Flash. It runs within the web browser Firefox, stripping the Flash before the user can even see it, and replacing it with an equivalent interface in pure HTML and Javascript. ...

Search box

I have introduced a “Search” box near the top. It searches for posts that contain the string (regular expression) you type in that box. Comments Jetru 17 Mar 2005 7:51 am: Superb! man you are smart! S Anand 17 Mar 2005 9:29 am: Just Javascript, actually. Jetru 17 Mar 2005 5:48 pm: Whatever.Looks impressive here. ritzkini 24 Mar 2005 5:18 am: tooo much !! too bloody much ! bu the event isnt shown taking place and fasssssssssssst !! good on u ! Deshi 24 Mar 2005 6:19 pm: Like he says, this is quite simple to do. But it makes the page more clutterred. Blogs have to be simple, and easy to read.. Kind of loses the purpose Jetru 26 Mar 2005 5:14 pm: No I like this format, except for the Permalink button S Anand 28 Mar 2005 3:17 am: Yeah, I don’t like the Permalink button either. Any suggestions?

How Google Maps works

How Google Maps works: a look behind the Javascript of Google Maps. Whereas GMail uses XMLHttp to make calls back to the server, Google Maps uses a hidden IFrame. The method has its benefits. The push-pins and info-popups are a different matter. Simply placing them is no big trick; an absolutely-positioned transparent GIF does the trick nicely. The shadows, however, are a different matter. They are PNGs with 8-bit alpha channels. ...

New commenting system

I’ve managed to get my commenting system to work. Feedback welcome. Comments ashish 25 Jan 2005 12:00 pm: cool harish_an 25 Jan 2005 12:00 pm: hey snand… howdy? back to regular blogging i guess ritzkini 25 Jan 2005 12:00 pm: good to have u back anand…been irregular with ur posts last few months… SHAMIT 25 Jan 2005 12:00 pm: Javascript ?

2003 1

Tracking visitors geographically

Geobytes is a piece of Javascript you can insert in your page, that will show visitors where they are from. via FilterCoffee

2002 1

Mozilla

I’m trying Mozilla. It has native SOAP support. So I can make a web page that has dynamic Google searches (and Amazon booklists, etc) without a web-server.

2001 1

w3schools

Learn web-development at w3schools.