Skip to content

Instantly share code, notes, and snippets.

@andrewchilds
andrewchilds / saveGPT.bookmarklet.js
Last active January 11, 2024 13:21
Download ChatGPT conversations as markdown files.
javascript:function parseChatGPTData(data) { const mapping = data.mapping; const conversationTitle = data.title; const createDate = new Date(data.create_time * 1000).toISOString().slice(0, 10); const messagesArray = Object.values(mapping) .filter(node => node.message) .map(node => { const message = node.message; const sender = message.author.role === 'user' ? 'You' : 'Assistant'; const content = message.content.parts.join(''); const createTime = message.create_time; return { sender: sender, content: content, createTime: createTime, }; }); messagesArray.sort((a, b) => a.createTime - b.createTime); return { date: createDate, title: conversationTitle, messages: messagesArray.map(({ sender, content }) => ({ sender, content })), }; } function download(filename, text) { const element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); e
@andrewchilds
andrewchilds / README.md
Last active June 27, 2023 13:03
How to configure HAProxy to proxy h2 (encrypted http2) to h2c (plain text http2) connections

How to configure HAProxy to support end-to-end (e2e) connections that switch from h2 to h2c

This was tested to work using HAProxy 2.8 on Ubuntu 20.04.

Use case

This lets you run a cluster of API servers configured to use HTTP/2 (for example, Fastify using { http2: true }), behind a HAProxy LB, so that you can serve typical REST API requests as well as SSE (Server Side Events) streaming connections, so that you can do fancy real-time page updates in your app.

Using HTTP/2 resolves the "6 concurrent HTTP connections" limit imposed by Chrome/Firefox/etc, which means the web app would become unresponsive if the user has 6+ tabs open with the app simultaneously.

@andrewchilds
andrewchilds / deepGet.js
Last active January 11, 2023 22:38 — forked from harish2704/lodash.get.js
Simple, standalone, vanilla implementation of lodash.get
// Simple implementation of lodash.get
// Handles arrays, objects, and any nested combination of the two.
// Also handles undefined as a valid value - see test case for details.
// Based on: https://gist.github.com/harish2704/d0ee530e6ee75bad6fd30c98e5ad9dab
export function deepGet(obj, query, defaultVal) {
query = Array.isArray(query) ? query : query.replace(/(\[(\d)\])/g, '.$2').replace(/^\./, '').split('.');
if (!(query[0] in obj)) {
return defaultVal;
}
obj = obj[query[0]];
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@andrewchilds
andrewchilds / clientCache.js
Last active June 22, 2022 18:12
Proposal: A client-side key-value store interface
const tableName = 'crayons';
const crayons = [
{ id: 1, color: 'blue', updated_at: new Date('2022-02-10T11:31:25-0500') },
{ id: 2, color: 'black', updated_at: new Date('2022-02-10T11:31:25-0500') },
{ id: 3, color: 'brown', updated_at: new Date('2022-02-10T11:31:25-0500') },
{ id: 4, color: 'green', updated_at: new Date('2022-02-10T11:31:25-0500') },
];
// Upsert multiple entries to a table, returning number of rows changed
@andrewchilds
andrewchilds / getTimezoneOffset.js
Created May 3, 2022 18:37
Convert a minute-based timezone offset like `240` to an offset like `"-04:00"`.
// Converts a getTimezoneOffset() offset to one that can be used in new Date().
// Examples:
// Eastern Standard Time: 240 -> '-04:00'
// India Standard Time: -330 -> '+05:30'
// Australian Central Western Standard Time: -525 -> '+08:45'
export function getTimezoneOffset(d) {
return convertTimezoneOffset(d.getTimezoneOffset());
}
export function convertTimezoneOffset(offset) {
@andrewchilds
andrewchilds / deepClone.js
Created April 28, 2022 01:07
Simple, standalone, vanilla implementation of lodash.cloneDeep
// Simple implementation of lodash.cloneDeep
// Does not clone functions or handle recursive references.
export function deepClone(original) {
if (original instanceof RegExp) {
return new RegExp(original);
} else if (original instanceof Date) {
return new Date(original.getTime());
} else if (Array.isArray(original)) {
return original.map(deepClone);
} else if (typeof original === 'object' && original !== null) {
@andrewchilds
andrewchilds / gist:11831dc82093e53d41af
Last active September 10, 2021 16:22
Rollbar RQL Cheat Sheet
# List users by average and maximum session length.
SELECT person, max(client.runtime_ms), avg(client.runtime_ms)
FROM item_occurrence
GROUP BY 1
ORDER BY 2 DESC
# List active date ranges for each deploy.
SELECT client.javascript.code_version, min(timestamp), max(timestamp)
FROM item_occurrence
GROUP BY 1
@andrewchilds
andrewchilds / google-meet-kindergarten-edition.css
Last active September 25, 2020 02:25
Google Meet: Kindergarten Edition
/*
This is a quick attempt to make Google Meet work better for someone in Kindergarten
(one in particular - it may or may not work for yours).
Requirements:
- I used the "Stylebot" extension to make this CSS work, but any other related extension should also work.
Changes:
- Hides the "who's here" rotating carousel which is distracting.
@andrewchilds
andrewchilds / clubhouse.sh
Last active January 23, 2020 00:07
Clubhouse/git/deploy utility functions
# Clubhouse / git / deploy utility functions
#
# API docs: https://clubhouse.io/api
#
# Assuming the following:
# 1. We have a range of git commits that represent the changes being deployed
# 2. Our git branches and pull requests use the username/ch123/story-name format,
# so that "ch123" ends up in a commit message
# 3. We have a Clubhouse API token set to the $CLUBHOUSE_API_TOKEN environment variable
#