Evan Hahn's projects
The highlights:
- Signal: a messaging app that puts privacy first. I made many contributions to the open source iOS and desktop apps.
- Helmet helps secure Express.js web apps by setting HTTP response headers. Adam Baldwin created the project and I took over as the primary maintainer in 2013. I’ve learned a lot along the way. The project was downloaded over 167 million times in 2023.
- Express in Action: a book I wrote about Express.js and its ecosystem. Published in 2016 so it’s a little outdated, but I’m proud of it.
- HumanizeDuration.js turns milliseconds into duration strings. For example, it turns 361,000 milliseconds into “6 minutes, 1 second”. Dozens of contributors have localized it into 58 different languages.
- dotfiles are how I configure my Linux and macOS machines. I’ve been maintaining this repository for a long time and wrote some reflections about it.
Books
I’ve written many guides, tutorials, and how-tos. Two of those got turned into books:
- Express.js in Action, a Manning book
- JavaScript Testing with Jasmine, an O’Reilly book
Jobs
I currently work at Digital Democracy building peer-to-peer software to help frontline communities defend their environmental and human rights.
Signal is a non-profit encrypted messenger used by millions around the world. I worked on the iOS and Desktop apps. I built many things including an encrypted group calling feature, a privacy-preserving donations feature, and much more.
Airtable is a tool to organize anything. I was on the Platform team where I worked on the REST API, Extensions (formerly known as Apps and Blocks), and much more. I learned a ton about programming, prioritization, product, and puppies.
Braintree lets developers easily accept payments. I was on the Contextual Commerce (now called Extend) team where I did a lot of Clojure and Ruby. Before that, I spent a lot of time building Braintree’s SDKs. My biggest project was Hosted Fields, a fancy way to accept credit cards on a webpage. We even got a patent for it, which I have mixed feelings about.
I’ve also done some part-time work for Codecademy with their “Learn React” course, Cooler with their climate change API, and Kanary with their matching infrastructure.
Before graduating college, I had a few other part-time jobs, mostly internships:
Counsyl, now Myriad Genetics, aimed to give everybody “access to vital information about their bodies to help them confidently make choices about their lives”. They did this by doing complicated genetic tests and presenting them to patients in accessible ways. I wrote a lot of Django and Python code for them, and even programmed a small robot! One of the coolest parts of the internship was seeing all of the people in white lab coats, something I will likely never wear. Fun fact: they were my third internship in a row that had a nearly-boundless supply of string cheese.
Sencha provides frameworks for building cross-platform applications. They had me working on their Sencha Architect team. Architect describes itself as a “visual app builder”, and I’d describe it as a huge, powerful JavaScript application that I helped to work on. I learned a bunch about Ext JS and Sencha Touch, and spent a few weeks deep in Node.js as well.
UniversityNow provided affordable, accredited online higher education. The first weeks of my internship were fixing bugs and implementing small features in Rails, but then I spent the rest of the summer working on their real-time chat feature. I learned Backbone.js and wrote a whole lot of Jasmine specs.
Fetchnotes was a note-taking app that aims to be “your mind’s best friend”. Their homepage and web app got a redesign by a brilliant designer, and I coded them both up! I bumbled my way through Ember.js to make it work. Soon after, a TechCrunch story was written and it got tens of thousands of hits! And it worked! Scary stuff. The service is no longer around.
Rockmelt was acquired by Yahoo awhile after I left. While I was there, they built a social browser; a fork of Google Chrome that baked things like Facebook and Twitter right into the browser. I worked on some internal help pages. Designers gave me PNGs and I gave them their “Quick Guide”! I also did some other pages for them (such as their What’s New page or some fixes on their homepage) and a lot of internal JavaScript unit tests.
Projects
See the highlights for a less boring list.
- A wallpaper from a NASA photo
- America’s DJ was a Twitter bot that tweets fake DJ names pulled from US military operations. You can find the source here.
- American police shooting countdown, my entry to JS1024 2020
- arraywrap.js wraps an element in an array if it isn’t one already
- backbone-getnset adds custom getters and setters to Backbone.js models
- Bits Required implements “how many bits do we need to represent integer X?” in various languages
- Brainfuck interpreter, in Python
- Brainfuck syntax highlighting for Atom
- Brainfuck web app, a simple web app written in Brainfuck
- BRAINFUCK2000, a powerful JavaScript Brainfuck interpreter for the stars
- BREACH helper for Node helps to mitigate BREACH attacks by adding a random-length HTML comment helper
- BrowserIs asks questions about Node.js requests useragents. Made for Express
- C program to repeat a string forever
- Caesar shift in JavaScript and CoffeeScript
- Canvas to favicon sends a
<canvas>
to the favicon - Check ECMAScript Version Compatibility checks that your JavaScript is compatible with the right version of ECMAScript
- ChicagoCTA is a Mastodon bot that tweets alerts from Chicago public transit
- ChiPy Mentorship Program had me as a mentor in the Fall 2017 cohort
- Circles 1K is 639 bytes of trippy and was an entry to JS1k
- ClimateAction.tech community support
- Close the popups was my entry to JS1k 2019
- coinflip.js randomly returns
true
orfalse
- connect-appcache adds Appcache middleware to Connect/Express
- Content Security Policy sandbox is a little test app for playing around with Content Security Policy
- context.clear is a small library for clearing a HTML5 canvas
- Custom Steam icons for Zineth, Lode Runner 2
- cyborg.txt is a collection of robots.txt utilities for Node
- Deep Proxy uses JavaScript proxies to allow deep property access
- document.head shim for CommonJS
- Dragon Scales was my entry for JS1k 2014
- dw_red.vim is a red-heavy Vim colorscheme
- Euler Method calculator in C++
- Evan Hahn’s 100 dope beats of the day
- EvanSpec is a souped-up
assert
for C++ - Expecting.js is an assertion module for JavaScript
- Facebook autopoker Chrome extension (or the source)
- ffmpeg buddy helps you build ffmpeg commands
- Fireworks was my entry to JS1k 2016
- FLoC Block is a small Express middleware to block Google’s FLoC tracking
- Flood is a game I didn’t invent but did implement. A friend didn’t like the version she was playing, so I made one that she liked
- Fudo is an adorable friend that was made from scratch in 36 hours at a hackathon. Art by Lulu Tang. Sound and code help from David Jackson
- functional state machine is a small JavaScript state machine that’s purely functional
- get the latest Node version from Node
- Gopher Node lets you write Gopher servers with Node
- Gribbagrab is an asynchronous JavaScript and CSS loader that’s meant to be inlined
- haha.sh is a simple shell script that generates hearty laughter
- Helmet for Crystal is a collection of security handlers for the Crystal programming language
- Helmet is a collection of security middlewares for Express
- Hide the Facebook news feed
- How many English words are alphabetical?
- HTML Pack inlines CSS and JavaScript for an HTML page and then minifies everything
- HumanizeDuration.js turns milliseconds into English durations, or many other languages
- image to table converts images to all-HTML
<table>
tags - Internet Creator, my entry to JS1024 2022
- Is GitHub Up? is a command-line tool that tels you if GitHub is online
- iscp is an interactive scp, because I always forget the syntax
- isExpress is a function for detecting Express applications
- ISO 3166 country list maps things like “DE” to “Germany” and vice-versa
- JavaScript Jabber episode 311: “Securing Express Apps with Helmet.js with Evan Hahn”
- JavaScript/CoffeeScript sleepsort
- journ is a command-line journal
- JSCPP is a shoddy attempt to port some of JavaScript’s standard library to C++
- JSTypes is a small JavaScript library that deals with variable types
- Legend of Zelda: Tears of the Kingdom prerelease roundups (as of April 2023, as of February 2023, as of January 2023, as of December 2022, as of November 2022, as of September 2022, as of August 2022, as of May 2022, as of April 2022, as of March 2022, as of December 2021)
- Lil’ pages is a collection of little web-based utilities
- Link’s Awakening.txt is a Mastodon bot that periodically posts text from The Legend of Zelda: Link’s Awakening
- Lucky Picross, my entry to JS1024 ‘23. Won third place!
- luhncheck is a little website that runs a number through a Luhn validator
- mailtolink.js creates
mailto:
links from JavaScript - map-invert inverts JavaScript Maps
- map-omit removes keys from JavaScript Maps
- Meme.js is a canvas-based meme generator I worked on for now-defunct Buddy Meme
- MiniClass is yet another JavaScript library that allows for simple classical OO. It’s tiny
- minidots are a couple of dotfiles I use when SSHing or in VMs
- MouseTracker.js creates an object called
mouse
and keeps itsx
andy
properties updated - Naps and their effectiveness
- nimi mute is a dictionary for the Toki Pona mini-language
- Node Hyperdrive import is an experimental Node module that lets you import packages from Hyperdrive
- Node torrent import is an experimental Node module that lets you import packages from BitTorrent. See my accompanying blog post
- NONOGRAM NIGHTS is a spooky puzzle where you use logic to uncover a mysterious picture
- Origin won 7th place in the 2013 js13kgames. I also wrote a little blog post about it
- Paint the box, my entry to JS1024 2021
- Percentage.js is a simple function to convert numbers to percentages, like 0.12 to 12%
- Persisted JSON objects are plain JavaScript objects that save themselves to the file system after every change
- Pie Time was my entry to JS1k 2015. I also wrote a post about it
- Pinboard to Standard Notes Importer moves Pinboard bookmarks into Standard Notes. See the source code
- PNG Chunk Editor lets you edit the bytes that make up a PNG image, and I made it in an hour
- PNG Chunk Explorer lets you explore the bytes that make up a PNG image
- Potions was my entry to JS1k 2017
- Predicting the next Zelda’s release date based on historical data
- Proof of concept: drop-in JSON replacement that produces smaller payloads
- Pushbullet CLI is a command-line interface to Pushbullet. I’m no longer the maintainer
- pwgen is a little webpage for generating passwords
- python -m json.tool for JavaScript emulates Python’s
json.tool
in pure JavaScript - QR It turns text into QR
- random-word is a CLI tool to pick a random word from a file
- Reddit’s /r/dailyprogrammer challenge solutions
- Remember The Milk script to export tasks as CSV
- Remember The Milk script to find tasks with invalid start times
- Remember The Milk script to estimate selected tasks
- rename is an interactive version of the
mv
command - ring-secure-headers adds security HTTP headers to Ring apps (for Clojure)
- RTS camera for Unity is a little utility for RTS games in Unity. Made it for a university course
- scrabbler is a small Scrabble cheater written in Python
- ScriptInclude adds
include
to browser-based JavaScript and is tiny - setAttributes helps you call
.setAttribute
on a DOM node more easily - Simple Statistics is a Crystal shard for simple statistical operations, such as median or standard deviation
- Single Color Image lets you generate a PNG that’s just one color. It’s a simple app with a simple API
- SnackWrap allows you to watch files and run a shell command every time a file changes. Not as focused as Grunt or Sprockets
- startInterval is like JavaScript’s
setInterval
but it starts immediately. It was made for a guide - Study guides from my time as an undergraduate at the University of Michigan: semester 3, semester 4, semester 5, and semester 6
- Sqids Crystal is a port of the Sqids serialization format to Crystal
- The TypeScript Grunt skeleton
- Tic Tac Toe in Lua
- Ticker is a lightweight wrapper around
requestAnimationFrame
- Time in Korea is a simple Android app that tells you the time in South Korea
- tiny “coming soon” page
- TinyTar is a tiny library (376 bytes gzipped) for creating tar files
- toki pona to hex converts the Toki Pona language to and from hex
- Truth table generator for CoffeeScript. Made to take the tedium out of a homework assignment
- Try EJS
- Try LiScript
- Two’s complement utility for converting from two’s complement numbers
- Two-factor authentication list
- untouched gets pristine copies of built-in objects (like Array or JSON) even if they’ve been modified
- User Agent Bag parses user agents per RFC7231
- UTF-21 is a toy character encoding like UTF-8
- VimL syntax highlighting for Atom
- What if the English language had syntax highlighting?
- when-file-exists calls a callback when a file is created
- wren-please is an assertion library for Wren
- wren-vector is a 3D vector library for Wren
- XML to text turns XML to plain text with Python
- Zap was my entry to JS1k 2018. It was an honorable mention—read my post about it
- ZoomContext lets you pan and zoom around an HTML5 canvas
Open source contributions
A big list of open source projects I’ve contributed to, but don’t run myself.
- 350.org’s Climate Strike Poster generator
- Fix border loading issues
- Add starter ESLint config
- Dependency updates (wdm, Backbone and Underscore, and Middleman)
- Arrow
- Authenticator
- Awesome Crystal
- bash-guide
- brittle
- clj-http
- CO2.js
- Constellate
- DefinitelyTyped
- Various Helmet-related changes and code reviews (#8818, #8820, #9017, #9018, #9162, #9248, #9273, #39673, #44235, #44228)
better-sqlite3
updatesbig-sparse-array
typesconnect
changes and code reviews (#24883, #40409, #40776)keygrip
tidyingnanobench
typesreact-virtualized
tweaks (#58648, #58705)sub-encoder
types@mapbox/whoots-js types
yauzl-promise
updates
- Deno
- Express
- @fastify/static
- flow-typed
- GRDB
- host-validation
- if-emoji
- KineticJS
- Mapeo
- methods
- node-process-limits
- nonolib
- Percentage
- pngjs
- Pony
- Qwerty Hancock
- random-access-file
- shurikenJS
- Signal
- statuses
- Sqids JavaScript
- Tab Center Redux
- url2green-js
- Vapor Security Headers
- WebTorrent
- yauzl-promise