Skip to content

Instantly share code, notes, and snippets.

View andymatuschak's full-sized avatar

Andy Matuschak andymatuschak

View GitHub Profile
@andymatuschak
andymatuschak / AMCA.md
Last active April 21, 2021 18:47
Andy Matuschak Contributor Agreement

Andy Matuschak Contributor Agreement

This Andy Matuschak Contributor Agreement ("AMCA") applies to any contribution that you make to any product or project managed by us (the "project"), and sets out the intellectual property rights you grant us in the contributed materials. The term "us" shall mean Andy Matuschak. The term "you" shall mean the person or entity identified below. If you agree to be bound by these terms, fill in the information requested and sign the AMCA where indicated below. Read this agreement carefully before signing. These terms and conditions constitute a binding legal agreement.

  1. The term "contribution" or "contributed materials" means any source code, object code, patch, tool, sample, graphic, specification, manual, documentation, or any other material posted or submitted by you to the project.

  2. With respect to any worldwide copyrights, or copyright applications and registrations, in your contribution:

  • you hereby assign to us joint ownership, and to the extent that such a
@andymatuschak
andymatuschak / gist:c5f2b8b68821a95e5b339bfcd4bfcee1
Last active July 21, 2020 16:59
late-bound React hook callbacks, avoiding subtree re-renders when event callback deps change
function useWeakRef<T>(value: T): React.MutableRefObject<T> {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref;
}
function useByrefCallback<Args extends unknown[], Result>(
callback: (...args: Args) => Result,
@andymatuschak
andymatuschak / clozePromptPlugin.ts
Last active May 9, 2021 05:08
parsing SRS prompts from Markdown
import mdast from "mdast";
import remarkParse from "remark-parse";
import remarkStringify from "remark-stringify";
import unified from "unified";
import unist from "unist";
import { clozeNodeType, ClozePromptNode } from "./index";
// TODO: don't match clozes inside code and html blocks
const clozeRegexp = /^{(.+?)}/;
export default function clozePlugin(this: unified.Processor) {
Day 0. Due: 100∑ [21, 79, 0, 0, 0, 0, 0, 0] Reviewed: 100 States: [13, 18, 69, 0, 0, 0, 0, 0] (average 1.56)
Day 1. Due: 31∑ [13, 18, 0, 0, 0, 0, 0, 0] Reviewed: 31 States: [5, 10, 85, 0, 0, 0, 0, 0] (average 1.8)
Day 2. Due: 15∑ [5, 10, 0, 0, 0, 0, 0, 0] Reviewed: 15 States: [0, 5, 95, 0, 0, 0, 0, 0] (average 1.95)
Day 3. Due: 74∑ [0, 5, 69, 0, 0, 0, 0, 0] Reviewed: 74 States: [0, 19, 31, 50, 0, 0, 0, 0] (average 2.31)
Day 4. Due: 48∑ [0, 19, 29, 0, 0, 0, 0, 0] Reviewed: 48 States: [4, 9, 17, 70, 0, 0, 0, 0] (average 2.53)
Day 5. Due: 15∑ [4, 9, 2, 0, 0, 0, 0, 0] Reviewed: 15 States: [4, 3, 21, 72, 0, 0, 0, 0] (average 2.61)
Day 6. Due: 7∑ [4, 3, 0, 0, 0, 0, 0, 0] Reviewed: 0 States: [4, 3, 21, 72, 0, 0, 0, 0] (average 2.61)
Day 7. Due: 22∑ [4, 3, 15, 0, 0, 0, 0, 0] Reviewed: 22 States: [1, 7, 8, 84, 0, 0, 0, 0] (average 2.75)
Day 8. Due: 16∑ [1, 7, 8, 0, 0, 0, 0, 0] Reviewed: 16 States: [2, 2, 6, 90, 0, 0, 0, 0] (average 2.84)
Day 9. Due: 8∑ [2, 2, 4, 0, 0, 0, 0, 0] Reviewed: 0 States: [
@andymatuschak
andymatuschak / gdc-downloader.py
Created December 22, 2018 04:45 — forked from archagon/gdc-downloader.py
A quick and dirty script to download GDC Vault videos.
# GDC Vault videos can't be watched on mobile devices and this is a very sad thing indeed!
# (Note: this has changed for GDC2013, which lets you watch raw MP4 streams. Kudos!)
# This script is designed to circumvent this by downloading the lecture and slideshow
# videos which can then be re-encoded into whatever format you wish. Obviously, you
# won't be able to do this without access to the Vault. This is strictly for the
# convenience of legitimate Vault users!
# Note: this code is rather flimsy and was written as fast as possible for my own personal use.
# The code only works for the most recent GDC Vault videos, since they all use the same player
# format. If the XML format used to run the player is changed (as it has in the past), the code
@andymatuschak
andymatuschak / States-v3.md
Last active October 7, 2024 00:46
A composable pattern for pure state machines with effects (draft v3)

A composable pattern for pure state machines with effects

State machines are everywhere in interactive systems, but they're rarely defined clearly and explicitly. Given some big blob of code including implicit state machines, which transitions are possible and under what conditions? What effects take place on what transitions?

There are existing design patterns for state machines, but all the patterns I've seen complect side effects with the structure of the state machine itself. Instances of these patterns are difficult to test without mocking, and they end up with more dependencies. Worse, the classic patterns compose poorly: hierarchical state machines are typically not straightforward extensions. The functional programming world has solutions, but they don't transpose neatly enough to be broadly usable in mainstream languages.

Here I present a composable pattern for pure state machiness with effects,

// One note before we start: if the inhabitants of Value are a closed set,
// then making Value an enum is going to be a clearer model than using a
// protocol like this. I'm assuming you need to be able to retroactively add
// new members of Value.
// Can't use Equatable directly because of its Self requirement.
protocol HeteroEquatable {
func isEqualTo(value: HeteroEquatable) -> Bool
}
@andymatuschak
andymatuschak / MultiDirectionAdjudicatingScrollView.swift
Created January 26, 2015 19:31
Source for the Khan Academy app's unusual scrolling interactions
//
// MultiDirectionAdjudicatingScrollView.swift
// Khan Academy
//
// Created by Andy Matuschak on 12/16/14.
// Copyright (c) 2014 Khan Academy. All rights reserved.
//
import UIKit
import UIKit.UIGestureRecognizerSubclass
@andymatuschak
andymatuschak / gist:2b311461caf740f5726f
Created December 28, 2014 18:17
A pragmatic and intentionally non-abstract solution to JSON decoding / initialization that doesn't require learning about five new operators.
struct User {
let id: Int
let name: String
let email: String?
}
extension User: JSONDecodable {
static func create(id: Int, name: String, email: String?) -> User {
return User(id: id, name: name, email: email)
}
@andymatuschak
andymatuschak / CollectionViewDataSource.swift
Last active February 12, 2021 09:44
Type-safe value-oriented collection view data source
//
// CollectionViewDataSource.swift
// Khan Academy
//
// Created by Andy Matuschak on 10/14/14.
// Copyright (c) 2014 Khan Academy. All rights reserved.
//
import UIKit