I love working with data, trying new tools, and playing with maps. These are artifacts I've created over time: personal GitHub projects, brown bag presentations, blog posts, and Ignite talks. Some I use every week, others seemed like a good idea at the time but only of historical interest.

Maps & geospatial

alidade
2026

A toolkit for managing GIS projects as code, built for working with an LLM. Treats a GIS project as build output: Python is the source of truth, and the same project spec renders to QGIS project files, ArcGIS Pro layer files, ArcGIS Online hosted layers, or static PNG maps. Describe a map change in plain English and let an LLM implement it; the project is reproducible from a fresh checkout and fully diffable in git.

Python geodata QGIS ArcGIS

Habitat suitability analysis for goat grazing at San José's Alum Rock Park. Combines a USGS elevation DEM, Santa Clara County vegetation data, and OpenStreetMap data to compute slope, classify vegetation by lifeform, and run a weighted overlay to identify grazeable patches. Ranks candidate staging areas by distance-weighted access to high-priority terrain. Built with the alidade toolkit. Also published as an ArcGIS story map.

Python geodata ArcGIS

An ArcGIS story map created for the GIST-11: Intro to Mapping & Spatial Reasoning course at Foothill College. A pair of maps with a slider compares pre-European and modern habitat extents. iNaturalist observations of key species map illustrate persistence of habitats, and Santa Clara County Parks trails enable public access. Switch to static PDF version when story map link expires.

geodata

Interactive and print maps for habitat restoration work areas in San José's Alum Rock Park, with context information sources from a Google Sheet.

JavaScript geodata

Final project for SJSU GEOG 172 - Cartography and Data Visualization: a map comparing mean commute time in the San Francisco - San José urban area in 2000 and 2019. Built with R from census data and visualized with ggplot2.

R geodata

Export Strava activities, convert to GeoJSON, and display on a Map Tiler map. Add layers for Bay Area Ridge and Bay Shoreline trails. Display picnic tables from Open Street Map.

Python geodata GPX GeoJSON Map Tiler Open Street Map JavaScript Overpass API

A deep dive into working with GPS track data from Strava GPX files. Based on https://github.com/kielni/activity-map.

Brown bag Python geodata GPX GeoJSON Map Tiler

A history of geodata, from Hipparchus' spherical earth to John Harrison's marine chronometer to GeoJSON.

Brown bag geodata
mfol-map
2018

Draw markers on a Google map with API event data. Search for events with a Places search box. Show event data in popup on click of marker.

JavaScript geodata Google Maps

Building a map from a spreadsheet, with the Mapbox and Google Sheets APIs.

geodata Mapbox AWS Lambda

The Guadalupe River Trail is an amazing panorama of the city of San Jose.

geodata

Draw a map geo data (from TopoJSON URL, TopJoSON document on Google Drive, or GeoJSON document on Google Drive) plus fill color data (from Google Sheet)

JavaScript geodata

Everything else

A presentation covering passwords, passkeys, two-factor authentication, identity theft, data brokers, device hygiene, credit protection, phishing, and social media risks. Plain HTML and CSS, built with Reveal.js.

HTML

I set up an AWS Lambda function to that uses a PyToch model to detect when an aurora is visible on the AuroraMAX live feed, then send an alert so I can go outside and look. A web view displays images where a strong aurora was detected, along with a timeline for the past 24 hours.

Python AWS Lambda PyTorch

I tried to make sense of wildly inaccurate solar + battery quote, then created my own Python model using pandas and lots of matplotlib charts. I modeled hourly flows from the grid and solar sources, to and from a battery, and exports to grid. I appplied complex PG&E credits, reviewed variations of arbitrage strategies, and illustrated how these affect cost and sourcing patterns.

Python
diy-pocket
2025

A minimal AWS-hosted setup for saving articles, designed as a DIY alternative to Pocket.

Python AWS Lambda

Cut through the noise, save time, focus on the fun parts; that's the dream. AI agents to set filters and collect additional information from booking.com and Airbnb sites. The browser-use library seems promising, but it doesn't really work.

Python OpenAI API

Brown bag presentation on natural language-driven browser automation, based on work in https://github.com/kielni/travel_agent.

Brown bag

Create summary sheets for college research with OpenAI API.

Python OpenAI API
photos
2024

Python scripts to organize photos, including collecting photos from Apple Photos, extracting metadata, and archiving on S3. See also LivePhotos for the web, on transforming LivePhotos so they can be embedded on a page and played by any browser.

Python

Planning to view the 2024 solar eclipse: why and where to go.

Ignite
ipeds-sql
2023

Get IPEDS college data into a human-friendly modern SQL database. Integrated Postsecondary Education Data System (IPEDS) is a system of interrelated surveys conducted annually by the National Center for Education Statistics.

Python AWS Lambda

Alviso the (mostly) forgotten port of San José.

Ignite
car-count
2022

Get car count data from SNAPS vehicle detection API and send to a Google Sheet.

Python AWS Lambda

Fairbanks cloud cover forecast, for aurora viewing planning.

Python AWS Lambda

A history of smart home automation: visions from the past and reality of today.

Brown bag

Google's AppSheet platform: No code / low code (was: wizards) + Sheets (was: Access) = app magic!

Brown bag AppSheet

The story of Buzz Holstrom's epic solo journey 1,100 miles down the Colorado River through the Grand Canyon. "I find I have already had my reward -- in the doing of the thing."

Ignite

Running production-scale tests with AWS Batch showed that merging data with SQLAlchemy reduced our Storage IO costs and accumulation of dead tuples.

Blog database SQLAlchemy

Migrating from Postgres to Aurora was easy. Storage IO usage nearly doubled our costs. We reduced them by resizing instances and repacking tables.

Blog AWS database

Description of how I organize and share my photos, with metadata, codecs, Python script, and S3.

Brown bag Python

A guide to the Firebase realtime database, including real-time data synchronization, security rules, and data structures.

Brown bag Firebase

Randomly select 10 dinner ideas from Pocket saves tagged with "dinner." Solve the "what's for dinner?" question with saved recipes.

Python

Alexa skill for Hillbrook School calendar.

Python AWS Lambda

A Chrome extension to set read date and rate a book on Goodreads from Kindle Cloud Reader.

JavaScript Chome extension

A deep dive into Python logging, including handlers, formatters, and configuration. Also covers JSON, Docker, and celery logging.

Brown bag Python

Packrafting equipment and adventures in Silicon Valley.

Ignite

A JavaScript application to browse and filter my Steam games library. Display logo, description, and tags, and hide or star games.

JavaScript

Generate searchable documentation for a tree of Starbound assets. Reads object and status effect files, generates documentation files, and runs a web server for browsing the content.

Python

Visiting onsens in Japan.

Ignite

Python worker bees for collecting and processing data. Aggregate RSS feeds into daily page with AWS Lambda and S3.

Python AWS Lambda RSS

History of the Stanley Cup, the oldest existing trophy to be awarded to a professional sports franchise.

Ignite

Silicon Valley has seasons. They're not the same as yours, and you need to get outside the city to experience them.

Ignite
whats-on
2017

A simple Vue.js application maintain a list of TV shows in chronological order from last watched to most recent, backed by a Firebase realtime database.

JavaScript Vue.js Firebase

Display per-store shopping lists, with realtime updates via Firebase.

JavaScript Vue.js Firebase Chome extension

In the olden days, software used to come in a box. Now, we can make sure our users always have fresh baked software. Ember apps in the cloud help.

Blog Ember AWS

The page object pattern makes writing acceptance tests for an Ember select2 component easier and faster.

Blog Ember

A tale of robots, gold stars, and code coverage.

Blog Slack

In a previous blog, I described how we deploy Ember apps to S3 buckets, and promised a follow up article about how we use a staging bucket to preview changes before pushing to production. In this article, I'll describe how we added shared development and staging buckets to our Ember deployment setup.

Blog Ember AWS

How serving Ember apps from S3 and Cloudfront simplified dev environments, sped up builds and deploys, and made our production infrastructure smaller and more scalable Gridium's Tikkit application has three separate front-end Ember apps that all talk to a common API.

Blog Ember AWS

Gridium's work order management system runs on a microservices architecture, with Docker containers managed by Kubernetes. We've divided our application into small, reusable components, each of which runs in its own Docker container.

Blog AWS Elasticsearch Docker

Creating a prototype for a new product idea with AWS building blocks

Blog AWS

Ignite talk about how and why to buy local grass-fed beef, in quarter-cow increments.

Ignite