Skip to content

Instantly share code, notes, and snippets.

View alanchrt's full-sized avatar

Alan Christopher Thomas alanchrt

View GitHub Profile
@alanchrt
alanchrt / data-platform-setup.md
Created June 25, 2026 05:21
Duramata data platform setup

Data Platform Setup

Architecture

Lifecycle analytics use Cloudflare Pipelines writing raw NDJSON events into R2. Workers emit semantic events such as sprite_created; RARRA metrics are SQL queries over those events, not categories computed at write time. If the activation definition changes, update the SQL and re-query historical data.

The API worker is the producer:

@alanchrt
alanchrt / android-play-testing-setup.md
Created June 24, 2026 19:37
Google Play closed testing setup for Duramata Android

Google Play closed testing — manual setup steps

This change adds a Google Play closed testing (alpha track) build to the production CI lane. Each app.* release now runs two Android builds in parallel:

  • android-build → the existing internal build (production profile), unchanged, still installable by Expo/EAS testers via a direct link.
  • android-build-play → a new Play Store build (production-play profile) that auto-submits to the closed testing (alpha) track.
@alanchrt
alanchrt / loops-contact-segmentation.md
Created June 23, 2026 23:49
Loops contact segmentation for a waitlist flow (queued → approved → activated)

Loops Contact Segmentation for a Waitlist Flow

TL;DR

Don't use lists for lifecycle state. Use a custom contact property (subscriptionStatus) and the sendEvent endpoint.


Why Not Mailing Lists?

Keybase proof

I hereby claim:

  • I am alanchrt on github.
  • I am alanchrt (https://keybase.io/alanchrt) on keybase.
  • I have a public key whose fingerprint is 0817 268C 001E DA3F C325 DF8A CDF1 536E CA70 A16C

To claim this, I am signing this object:

@alanchrt
alanchrt / triangulate.js
Created January 22, 2014 20:08
Triangulation of three points and radii
var distancePoints = function(p1, p2) {
// Find the distance between two points
return Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
};
var intersectCircles = function (c1, r1, c2, r2) {
// Find the points of intersection for two circles
// Based on: http://stackoverflow.com/a/3349134
var d = distancePoints(c1, c2);
if (d > r1 + r2) // Circles do not overlap
@alanchrt
alanchrt / listen.py
Created October 15, 2013 20:24
Listening for MindWave headsets to be attached and connecting automatically
import json, serial, threading, time
import mindwave
headsets = [
{
'name': 'red',
'headset': mindwave.Headset('/dev/tty.MindWaveMobile-DevA', open_serial=False),
},
{
'name': 'green',
@alanchrt
alanchrt / connect.py
Created October 15, 2013 20:11
Connecting MindwaveMobile bluetooth headsets
headsets = [
{
'name': 'red',
'headset': mindwave.Headset('/dev/tty.MindWaveMobile-DevA', open_serial=False),
},
{
'name': 'green',
'headset': mindwave.Headset('/dev/tty.MindWaveMobile-DevA-1', open_serial=False),
},
]
@alanchrt
alanchrt / index.html
Created August 22, 2013 21:53
Leap/WebGL Video Wall
<!doctype html>
<html>
<head>
<title>Reinventing Retail</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
background: #000;
margin: 0;
overflow: hidden;
@alanchrt
alanchrt / gist:1014534
Created June 8, 2011 14:35
Batch Geocode - Google App Script
/*****************************************************************************\
* Batch Spreadsheet Geocoding Script *
* Author: Alan Christopher Thomas *
* http://alanchristopherthomas.com/ *
\*****************************************************************************/
function onOpen() {
// Add the Geocode menu
SpreadsheetApp.getActiveSpreadsheet().addMenu("Geocoder", [{
name: "Geocode addresses",