Merge pull request #6 from barrett-ruth/ci

ci (prettier + astro)
This commit is contained in:
Barrett Ruth 2025-11-09 16:43:52 -05:00 committed by GitHub
commit 0caab7c0c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 1023 additions and 206 deletions

View file

@ -21,7 +21,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
cache: "pnpm"
- name: Install dependencies
run: pnpm install

36
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,36 @@
name: CI
on:
pull_request:
push:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Prettier check
run: pnpm prettier --check .
- name: Astro check
run: pnpm astro check
- name: Build
run: pnpm build

View file

@ -4,6 +4,68 @@ import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import path from "path";
const midnight = {
name: "midnight",
type: "dark",
colors: {
"editor.background": "#121212",
"editor.foreground": "#e0e0e0",
},
tokenColors: [
{
scope: [
"storage.type",
"storage.modifier",
"keyword.control",
"keyword.operator.new",
],
settings: { foreground: "#7aa2f7" },
},
{
scope: [
"string",
"constant",
"constant.numeric",
"constant.language",
"constant.character",
"number",
],
settings: { foreground: "#98c379" },
},
],
};
const daylight = {
name: "daylight",
type: "light",
colors: {
"editor.background": "#f5f5f5",
"editor.foreground": "#1a1a1a",
},
tokenColors: [
{
scope: [
"storage.type",
"storage.modifier",
"keyword.control",
"keyword.operator.new",
],
settings: { foreground: "#3b5bdb" },
},
{
scope: [
"string",
"constant",
"constant.numeric",
"constant.language",
"constant.character",
"number",
],
settings: { foreground: "#2d7f3e" },
},
],
};
export default defineConfig({
build: {
format: "file",
@ -23,7 +85,10 @@ export default defineConfig({
},
markdown: {
shikiConfig: {
theme: "github-light",
themes: {
light: daylight,
dark: midnight,
},
langs: [],
wrap: true,
},

View file

@ -7,10 +7,14 @@
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"prepare": "husky"
"prepare": "husky",
"check": "astro check"
},
"lint-staged": {
"*.{js,ts,jsx,tsx,astro,html,md,json,yml,yaml}": "prettier --write"
"*.{js,ts,jsx,tsx,astro,html,md,json,yml,yaml,css}": [
"prettier --write",
"astro check"
]
},
"dependencies": {
"@astrojs/mdx": "^4.3.6",
@ -19,6 +23,7 @@
"remark-math": "^6.0.0"
},
"devDependencies": {
"@astrojs/check": "^0.9.5",
"@typescript-eslint/parser": "^8.46.0",
"husky": "^9.1.7",
"lint-staged": "^16.2.3",

552
pnpm-lock.yaml generated
View file

@ -21,6 +21,9 @@ importers:
specifier: ^6.0.0
version: 6.0.0
devDependencies:
'@astrojs/check':
specifier: ^0.9.5
version: 0.9.5(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)
'@typescript-eslint/parser':
specifier: ^8.46.0
version: 8.46.0(eslint@9.27.0)(typescript@5.9.3)
@ -42,12 +45,30 @@ importers:
packages:
'@astrojs/check@0.9.5':
resolution: {integrity: sha512-88vc8n2eJ1Oua74yXSGo/8ABMeypfQPGEzuoAx2awL9Ju8cE6tZ2Rz9jVx5hIExHK5gKVhpxfZj4WXm7e32g1w==}
hasBin: true
peerDependencies:
typescript: ^5.0.0
'@astrojs/compiler@2.13.0':
resolution: {integrity: sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==}
'@astrojs/internal-helpers@0.7.3':
resolution: {integrity: sha512-6Pl0bQEIChuW5wqN7jdKrzWfCscW2rG/Cz+fzt4PhSQX2ivBpnhXgFUCs0M3DCYvjYHnPVG2W36X5rmFjZ62sw==}
'@astrojs/language-server@2.16.0':
resolution: {integrity: sha512-oX2KkuIfEEM5d4/+lfuxy6usRDYko0S02YvtHFTrnqW0h9e4ElAfWZRKyqxWlwpuPdciBPKef5YJ7DFH3PPssw==}
hasBin: true
peerDependencies:
prettier: ^3.0.0
prettier-plugin-astro: '>=0.11.0'
peerDependenciesMeta:
prettier:
optional: true
prettier-plugin-astro:
optional: true
'@astrojs/markdown-remark@6.3.7':
resolution: {integrity: sha512-KXGdq6/BC18doBCYXp08alHlWChH0hdD2B1qv9wIyOHbvwI5K6I7FhSta8dq1hBQNdun8YkKPR013D/Hm8xd0g==}
@ -65,6 +86,9 @@ packages:
resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==}
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
'@astrojs/yaml2ts@0.2.2':
resolution: {integrity: sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ==}
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
@ -85,6 +109,28 @@ packages:
'@capsizecss/unpack@2.4.0':
resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==}
'@emmetio/abbreviation@2.3.3':
resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==}
'@emmetio/css-abbreviation@2.1.8':
resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==}
'@emmetio/css-parser@https://codeload.github.com/ramya-rao-a/css-parser/tar.gz/370c480ac103bd17c7bcfb34bf5d577dc40d3660':
resolution: {tarball: https://codeload.github.com/ramya-rao-a/css-parser/tar.gz/370c480ac103bd17c7bcfb34bf5d577dc40d3660}
version: 0.4.0
'@emmetio/html-matcher@1.3.0':
resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==}
'@emmetio/scanner@1.0.4':
resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==}
'@emmetio/stream-reader-utils@0.1.0':
resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==}
'@emmetio/stream-reader@2.2.0':
resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==}
'@emnapi/runtime@1.5.0':
resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
@ -674,6 +720,32 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
'@volar/kit@2.4.23':
resolution: {integrity: sha512-YuUIzo9zwC2IkN7FStIcVl1YS9w5vkSFEZfPvnu0IbIMaR9WHhc9ZxvlT+91vrcSoRY469H2jwbrGqpG7m1KaQ==}
peerDependencies:
typescript: '*'
'@volar/language-core@2.4.23':
resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==}
'@volar/language-server@2.4.23':
resolution: {integrity: sha512-k0iO+tybMGMMyrNdWOxgFkP0XJTdbH0w+WZlM54RzJU3WZSjHEupwL30klpM7ep4FO6qyQa03h+VcGHD4Q8gEg==}
'@volar/language-service@2.4.23':
resolution: {integrity: sha512-h5mU9DZ/6u3LCB9xomJtorNG6awBNnk9VuCioGsp6UtFiM8amvS5FcsaC3dabdL9zO0z+Gq9vIEMb/5u9K6jGQ==}
'@volar/source-map@2.4.23':
resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==}
'@volar/typescript@2.4.23':
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
'@vscode/emmet-helper@2.11.0':
resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==}
'@vscode/l10n@0.0.18':
resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==}
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -684,9 +756,20 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
ajv-draft-04@1.0.0:
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
ajv: ^8.5.0
peerDependenciesMeta:
ajv:
optional: true
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
@ -820,6 +903,10 @@ packages:
resolution: {integrity: sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==}
engines: {node: '>=20'}
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
clone@2.1.2:
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
engines: {node: '>=0.8'}
@ -937,6 +1024,9 @@ packages:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'}
emmet@2.4.11:
resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==}
emoji-regex@10.5.0:
resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==}
@ -965,6 +1055,10 @@ packages:
engines: {node: '>=18'}
hasBin: true
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
@ -1058,6 +1152,9 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
@ -1104,6 +1201,10 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-east-asian-width@1.4.0:
resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==}
engines: {node: '>=18'}
@ -1270,9 +1371,18 @@ packages:
json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
jsonc-parser@2.3.1:
resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==}
jsonc-parser@3.3.1:
resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
katex@0.16.23:
resolution: {integrity: sha512-7VlC1hsEEolL9xNO05v9VjrvWZePkCVBJqj8ruICxYjZfHaHbaU53AlP+PODyFIXEnaEIEWi3wJy7FPZ95JAVg==}
hasBin: true
@ -1308,6 +1418,9 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
log-update@6.1.0:
resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
engines: {node: '>=18'}
@ -1522,6 +1635,9 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
nano-spawn@1.0.3:
resolution: {integrity: sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==}
engines: {node: '>=20.17'}
@ -1619,6 +1735,9 @@ packages:
parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -1751,6 +1870,20 @@ packages:
remark-stringify@11.0.0:
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
request-light@0.5.8:
resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==}
request-light@0.7.0:
resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@ -1935,6 +2068,12 @@ packages:
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
engines: {node: '>=16'}
typesafe-path@0.2.2:
resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==}
typescript-auto-import-cache@0.3.6:
resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@ -2116,6 +2255,98 @@ packages:
vite:
optional: true
volar-service-css@0.0.66:
resolution: {integrity: sha512-XrL1V9LEAHnunglYdDf/7shJbQXqKsHB+P69zPmJTqHx6hqvM9GWNbn2h7M0P/oElW8p/MTVHdfjl6C8cxdsBQ==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
volar-service-emmet@0.0.66:
resolution: {integrity: sha512-BMPSpm6mk0DAEVdI2haxYIOt1Z2oaIZvCGtXuRu95x50a5pOSRPjdeHv2uGp1rQsq1Izigx+VR/bZUf2HcSnVQ==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
volar-service-html@0.0.66:
resolution: {integrity: sha512-MKKD2qM8qVZvBKBIugt00+Bm8j1ehgeX7Cm5XwgeEgdW/3PhUEEe/aeTxQGon1WJIGf2MM/cHPjZxPJOQN4WfQ==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
volar-service-prettier@0.0.66:
resolution: {integrity: sha512-CVaQEyfmFWoq3NhNVExoyDKonPqdacmb/07w7OfTZljxLgZpDRygiHAvzBKIcenb7rKtJNHqfQJv99ULOinJBA==}
peerDependencies:
'@volar/language-service': ~2.4.0
prettier: ^2.2 || ^3.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
prettier:
optional: true
volar-service-typescript-twoslash-queries@0.0.66:
resolution: {integrity: sha512-PA3CyvEaBrkxJcBq+HFdks1TF1oJ8H+jTOTQUurLDRkVjmUFg8bfdya6U/dWfTsPaDSRM4m/2chwgew5zoQXfg==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
volar-service-typescript@0.0.66:
resolution: {integrity: sha512-8irsfCEf86R1RqPijrU6p5NCqKDNzyJNWKM6ZXmCcJqhebtl7Hr/a0bnlr59AzqkS3Ym4PbbJZs1K/92CXTDsw==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
volar-service-yaml@0.0.66:
resolution: {integrity: sha512-q6oTKD6EMEu1ws1FDjRw+cfCF69Gu51IEGM9jVbtmSZS1qQHKxMqlt2+wBInKl2D+xILtjzkWbfkjQyBYQMw7g==}
peerDependencies:
'@volar/language-service': ~2.4.0
peerDependenciesMeta:
'@volar/language-service':
optional: true
vscode-css-languageservice@6.3.8:
resolution: {integrity: sha512-dBk/9ullEjIMbfSYAohGpDOisOVU1x2MQHOeU12ohGJQI7+r0PCimBwaa/pWpxl/vH4f7ibrBfxIZY3anGmHKQ==}
vscode-html-languageservice@5.6.0:
resolution: {integrity: sha512-FIVz83oGw2tBkOr8gQPeiREInnineCKGCz3ZD1Pi6opOuX3nSRkc4y4zLLWsuop+6ttYX//XZCI6SLzGhRzLmA==}
vscode-json-languageservice@4.1.8:
resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==}
engines: {npm: '>=7.0.0'}
vscode-jsonrpc@8.2.0:
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
engines: {node: '>=14.0.0'}
vscode-languageserver-protocol@3.17.5:
resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
vscode-languageserver-textdocument@1.0.12:
resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==}
vscode-languageserver-types@3.17.5:
resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
vscode-languageserver@9.0.1:
resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==}
hasBin: true
vscode-nls@5.2.0:
resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==}
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
@ -2142,6 +2373,10 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@9.0.2:
resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
engines: {node: '>=18'}
@ -2149,6 +2384,19 @@ packages:
xxhash-wasm@1.1.0:
resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yaml-language-server@1.19.2:
resolution: {integrity: sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg==}
hasBin: true
yaml@2.7.1:
resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
engines: {node: '>= 14'}
hasBin: true
yaml@2.8.1:
resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==}
engines: {node: '>= 14.6'}
@ -2158,6 +2406,10 @@ packages:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
@ -2193,10 +2445,47 @@ packages:
snapshots:
'@astrojs/check@0.9.5(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)':
dependencies:
'@astrojs/language-server': 2.16.0(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)
chokidar: 4.0.3
kleur: 4.1.5
typescript: 5.9.3
yargs: 17.7.2
transitivePeerDependencies:
- prettier
- prettier-plugin-astro
'@astrojs/compiler@2.13.0': {}
'@astrojs/internal-helpers@0.7.3': {}
'@astrojs/language-server@2.16.0(prettier-plugin-astro@0.14.1)(prettier@3.6.2)(typescript@5.9.3)':
dependencies:
'@astrojs/compiler': 2.13.0
'@astrojs/yaml2ts': 0.2.2
'@jridgewell/sourcemap-codec': 1.5.5
'@volar/kit': 2.4.23(typescript@5.9.3)
'@volar/language-core': 2.4.23
'@volar/language-server': 2.4.23
'@volar/language-service': 2.4.23
fast-glob: 3.3.3
muggle-string: 0.4.1
volar-service-css: 0.0.66(@volar/language-service@2.4.23)
volar-service-emmet: 0.0.66(@volar/language-service@2.4.23)
volar-service-html: 0.0.66(@volar/language-service@2.4.23)
volar-service-prettier: 0.0.66(@volar/language-service@2.4.23)(prettier@3.6.2)
volar-service-typescript: 0.0.66(@volar/language-service@2.4.23)
volar-service-typescript-twoslash-queries: 0.0.66(@volar/language-service@2.4.23)
volar-service-yaml: 0.0.66(@volar/language-service@2.4.23)
vscode-html-languageservice: 5.6.0
vscode-uri: 3.1.0
optionalDependencies:
prettier: 3.6.2
prettier-plugin-astro: 0.14.1
transitivePeerDependencies:
- typescript
'@astrojs/markdown-remark@6.3.7':
dependencies:
'@astrojs/internal-helpers': 0.7.3
@ -2258,6 +2547,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@astrojs/yaml2ts@0.2.2':
dependencies:
yaml: 2.8.1
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.27.1': {}
@ -2279,6 +2572,29 @@ snapshots:
transitivePeerDependencies:
- encoding
'@emmetio/abbreviation@2.3.3':
dependencies:
'@emmetio/scanner': 1.0.4
'@emmetio/css-abbreviation@2.1.8':
dependencies:
'@emmetio/scanner': 1.0.4
'@emmetio/css-parser@https://codeload.github.com/ramya-rao-a/css-parser/tar.gz/370c480ac103bd17c7bcfb34bf5d577dc40d3660':
dependencies:
'@emmetio/stream-reader': 2.2.0
'@emmetio/stream-reader-utils': 0.1.0
'@emmetio/html-matcher@1.3.0':
dependencies:
'@emmetio/scanner': 1.0.4
'@emmetio/scanner@1.0.4': {}
'@emmetio/stream-reader-utils@0.1.0': {}
'@emmetio/stream-reader@2.2.0': {}
'@emnapi/runtime@1.5.0':
dependencies:
tslib: 2.8.1
@ -2764,12 +3080,66 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
'@volar/kit@2.4.23(typescript@5.9.3)':
dependencies:
'@volar/language-service': 2.4.23
'@volar/typescript': 2.4.23
typesafe-path: 0.2.2
typescript: 5.9.3
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
'@volar/language-core@2.4.23':
dependencies:
'@volar/source-map': 2.4.23
'@volar/language-server@2.4.23':
dependencies:
'@volar/language-core': 2.4.23
'@volar/language-service': 2.4.23
'@volar/typescript': 2.4.23
path-browserify: 1.0.1
request-light: 0.7.0
vscode-languageserver: 9.0.1
vscode-languageserver-protocol: 3.17.5
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
'@volar/language-service@2.4.23':
dependencies:
'@volar/language-core': 2.4.23
vscode-languageserver-protocol: 3.17.5
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
'@volar/source-map@2.4.23': {}
'@volar/typescript@2.4.23':
dependencies:
'@volar/language-core': 2.4.23
path-browserify: 1.0.1
vscode-uri: 3.1.0
'@vscode/emmet-helper@2.11.0':
dependencies:
emmet: 2.4.11
jsonc-parser: 2.3.1
vscode-languageserver-textdocument: 1.0.12
vscode-languageserver-types: 3.17.5
vscode-uri: 3.1.0
'@vscode/l10n@0.0.18': {}
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
acorn: 8.15.0
acorn@8.15.0: {}
ajv-draft-04@1.0.0(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
@ -2777,6 +3147,13 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
ajv@8.17.1:
dependencies:
fast-deep-equal: 3.1.3
fast-uri: 3.1.0
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
ansi-align@3.0.1:
dependencies:
string-width: 4.2.3
@ -2988,6 +3365,12 @@ snapshots:
slice-ansi: 7.1.2
string-width: 8.1.0
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
clone@2.1.2: {}
clsx@2.1.1: {}
@ -3076,6 +3459,11 @@ snapshots:
dset@3.1.4: {}
emmet@2.4.11:
dependencies:
'@emmetio/abbreviation': 2.3.3
'@emmetio/css-abbreviation': 2.1.8
emoji-regex@10.5.0: {}
emoji-regex@8.0.0: {}
@ -3129,6 +3517,8 @@ snapshots:
'@esbuild/win32-ia32': 0.25.10
'@esbuild/win32-x64': 0.25.10
escalade@3.2.0: {}
escape-string-regexp@4.0.0: {}
escape-string-regexp@5.0.0: {}
@ -3253,6 +3643,8 @@ snapshots:
fast-levenshtein@2.0.6: {}
fast-uri@3.1.0: {}
fastq@1.19.1:
dependencies:
reusify: 1.1.0
@ -3303,6 +3695,8 @@ snapshots:
fsevents@2.3.3:
optional: true
get-caller-file@2.0.5: {}
get-east-asian-width@1.4.0: {}
github-slugger@2.0.0: {}
@ -3542,8 +3936,14 @@ snapshots:
json-schema-traverse@0.4.1: {}
json-schema-traverse@1.0.0: {}
json-stable-stringify-without-jsonify@1.0.1: {}
jsonc-parser@2.3.1: {}
jsonc-parser@3.3.1: {}
katex@0.16.23:
dependencies:
commander: 8.3.0
@ -3586,6 +3986,8 @@ snapshots:
lodash.merge@4.6.2: {}
lodash@4.17.21: {}
log-update@6.1.0:
dependencies:
ansi-escapes: 7.1.1
@ -4090,6 +4492,8 @@ snapshots:
ms@2.1.3: {}
muggle-string@0.4.1: {}
nano-spawn@1.0.3: {}
nanoid@3.3.11: {}
@ -4191,6 +4595,8 @@ snapshots:
dependencies:
entities: 6.0.1
path-browserify@1.0.1: {}
path-exists@4.0.0: {}
path-key@3.1.1: {}
@ -4377,6 +4783,14 @@ snapshots:
mdast-util-to-markdown: 2.1.2
unified: 11.0.5
request-light@0.5.8: {}
request-light@0.7.0: {}
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
resolve-from@4.0.0: {}
restore-cursor@5.1.0:
@ -4604,6 +5018,12 @@ snapshots:
type-fest@4.41.0: {}
typesafe-path@0.2.2: {}
typescript-auto-import-cache@0.3.6:
dependencies:
semver: 7.7.3
typescript@5.9.3: {}
ufo@1.6.1: {}
@ -4733,6 +5153,103 @@ snapshots:
optionalDependencies:
vite: 6.3.6(@types/node@24.7.0)(yaml@2.8.1)
volar-service-css@0.0.66(@volar/language-service@2.4.23):
dependencies:
vscode-css-languageservice: 6.3.8
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
volar-service-emmet@0.0.66(@volar/language-service@2.4.23):
dependencies:
'@emmetio/css-parser': https://codeload.github.com/ramya-rao-a/css-parser/tar.gz/370c480ac103bd17c7bcfb34bf5d577dc40d3660
'@emmetio/html-matcher': 1.3.0
'@vscode/emmet-helper': 2.11.0
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
volar-service-html@0.0.66(@volar/language-service@2.4.23):
dependencies:
vscode-html-languageservice: 5.6.0
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
volar-service-prettier@0.0.66(@volar/language-service@2.4.23)(prettier@3.6.2):
dependencies:
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
prettier: 3.6.2
volar-service-typescript-twoslash-queries@0.0.66(@volar/language-service@2.4.23):
dependencies:
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
volar-service-typescript@0.0.66(@volar/language-service@2.4.23):
dependencies:
path-browserify: 1.0.1
semver: 7.7.3
typescript-auto-import-cache: 0.3.6
vscode-languageserver-textdocument: 1.0.12
vscode-nls: 5.2.0
vscode-uri: 3.1.0
optionalDependencies:
'@volar/language-service': 2.4.23
volar-service-yaml@0.0.66(@volar/language-service@2.4.23):
dependencies:
vscode-uri: 3.1.0
yaml-language-server: 1.19.2
optionalDependencies:
'@volar/language-service': 2.4.23
vscode-css-languageservice@6.3.8:
dependencies:
'@vscode/l10n': 0.0.18
vscode-languageserver-textdocument: 1.0.12
vscode-languageserver-types: 3.17.5
vscode-uri: 3.1.0
vscode-html-languageservice@5.6.0:
dependencies:
'@vscode/l10n': 0.0.18
vscode-languageserver-textdocument: 1.0.12
vscode-languageserver-types: 3.17.5
vscode-uri: 3.1.0
vscode-json-languageservice@4.1.8:
dependencies:
jsonc-parser: 3.3.1
vscode-languageserver-textdocument: 1.0.12
vscode-languageserver-types: 3.17.5
vscode-nls: 5.2.0
vscode-uri: 3.1.0
vscode-jsonrpc@8.2.0: {}
vscode-languageserver-protocol@3.17.5:
dependencies:
vscode-jsonrpc: 8.2.0
vscode-languageserver-types: 3.17.5
vscode-languageserver-textdocument@1.0.12: {}
vscode-languageserver-types@3.17.5: {}
vscode-languageserver@9.0.1:
dependencies:
vscode-languageserver-protocol: 3.17.5
vscode-nls@5.2.0: {}
vscode-uri@3.1.0: {}
web-namespaces@2.0.1: {}
webidl-conversions@3.0.1: {}
@ -4754,6 +5271,12 @@ snapshots:
word-wrap@1.2.5: {}
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@9.0.2:
dependencies:
ansi-styles: 6.2.3
@ -4762,10 +5285,39 @@ snapshots:
xxhash-wasm@1.1.0: {}
y18n@5.0.8: {}
yaml-language-server@1.19.2:
dependencies:
'@vscode/l10n': 0.0.18
ajv: 8.17.1
ajv-draft-04: 1.0.0(ajv@8.17.1)
lodash: 4.17.21
prettier: 3.6.2
request-light: 0.5.8
vscode-json-languageservice: 4.1.8
vscode-languageserver: 9.0.1
vscode-languageserver-textdocument: 1.0.12
vscode-languageserver-types: 3.17.5
vscode-uri: 3.1.0
yaml: 2.7.1
yaml@2.7.1: {}
yaml@2.8.1: {}
yargs-parser@21.1.1: {}
yargs@17.7.2:
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
yocto-queue@0.1.0: {}
yocto-queue@1.2.1: {}

View file

@ -4,6 +4,12 @@ function urlToTopic() {
return pathParts[2];
}
function getTextColor() {
return getComputedStyle(document.documentElement)
.getPropertyValue("--text")
.trim();
}
function setUpParameters(render, parameters, modelPrefix) {
parameters.forEach((param) => {
const slider = document.getElementById(`slider${modelPrefix}${param}`);
@ -22,7 +28,7 @@ function setUpParameters(render, parameters, modelPrefix) {
function drawSolowGraph() {
const L = 150,
K_MAX = 500,
margin = { top: 20, right: 30, bottom: 20, left: 50 };
margin = { top: 50, right: 55, bottom: 40, left: 75 };
const [A, d, s, alpha] = setUpParameters(
drawSolowGraph,
@ -49,29 +55,29 @@ function drawSolowGraph() {
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const x = d3.scaleLinear().domain([0, K_MAX]).range([0, width]);
svg
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.call(d3.axisBottom(x));
xAxis.selectAll("text").style("font-size", "1.5em");
xAxis
.append("text")
.attr("fill", "#000")
.attr("x", width + 10)
.attr("y", -10)
.style("text-anchor", "end")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("K");
const Y_MAX = solowOutput(K_MAX) + K_MAX / 10;
const y = d3.scaleLinear().domain([0, Y_MAX]).range([height, 0]);
svg
.append("g")
.call(d3.axisLeft(y))
const yAxis = svg.append("g").call(d3.axisLeft(y));
yAxis.selectAll("text").style("font-size", "1.5em");
yAxis
.append("text")
.attr("fill", "#000")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "start")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("Y");
const outputData = Array.from({ length: K_MAX }, (_, k) => ({
@ -162,7 +168,6 @@ function drawSolowGraph() {
.attr("y1", y((d * k_star) / s))
.attr("x2", x(k_star))
.attr("y2", y(0))
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("stroke-dasharray", "5,5");
@ -201,7 +206,7 @@ const updateRomerTable = (romerData) => {
function drawRomerGraph() {
const T_MAX = 100,
margin = { top: 20, right: 100, bottom: 20, left: 50 };
margin = { top: 50, right: 110, bottom: 40, left: 75 };
const [z, L, l, A0] = setUpParameters(
drawRomerGraph,
@ -234,31 +239,33 @@ function drawRomerGraph() {
}
const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
svg
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.call(d3.axisBottom(x));
xAxis.selectAll("text").style("font-size", "1.5em");
xAxis
.append("text")
.attr("fill", "#000")
.attr("x", width + 10)
.attr("y", -10)
.style("text-anchor", "end")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("t");
const y = d3
.scaleLinear()
.domain([0, romerData[romerData.length - 1].Y])
.range([height, 0]);
svg
const yAxis = svg
.append("g")
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")))
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
yAxis.selectAll("text").style("font-size", "1.5em");
yAxis
.append("text")
.attr("fill", "#000")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "start")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("log(Y)");
svg
@ -290,7 +297,7 @@ function drawRomerlGraph() {
z = 0.01,
L = 50,
A0 = 50,
margin = { top: 20, right: 100, bottom: 20, left: 50 };
margin = { top: 50, right: 110, bottom: 40, left: 75 };
const [l, t0] = setUpParameters(drawRomerlGraph, ["lChange", "t0"], "");
@ -327,31 +334,33 @@ function drawRomerlGraph() {
}
const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
svg
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.call(d3.axisBottom(x));
xAxis.selectAll("text").style("font-size", "1.5em");
xAxis
.append("text")
.attr("fill", "#000")
.attr("x", width + 10)
.attr("y", -10)
.style("text-anchor", "end")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("t");
const y = d3
.scaleLinear()
.domain([0, romerData[romerData.length - 1].Y])
.range([height, 0]);
svg
const yAxis = svg
.append("g")
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")))
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
yAxis.selectAll("text").style("font-size", "1.5em");
yAxis
.append("text")
.attr("fill", "#000")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "start")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("log(Y)");
svg
@ -374,7 +383,6 @@ function drawRomerlGraph() {
.attr("y1", y(romerData[T_MAX - 1].Y))
.attr("x2", x(t0))
.attr("y2", height)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("stroke-dasharray", "4");
@ -439,7 +447,7 @@ function calculateRomerSolowData(
function drawRomerSolowGraph() {
const T_MAX = 100,
margin = { top: 20, right: 100, bottom: 20, left: 50 };
margin = { top: 50, right: 110, bottom: 40, left: 75 };
const [z, l, L, A0, s, d, alpha] = setUpParameters(
drawRomerSolowGraph,
@ -473,31 +481,33 @@ function drawRomerSolowGraph() {
);
const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
svg
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.call(d3.axisBottom(x));
xAxis.selectAll("text").style("font-size", "1.5em");
xAxis
.append("text")
.attr("fill", "#000")
.attr("x", width + 10)
.attr("y", -10)
.style("text-anchor", "end")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("t");
const y = d3
.scaleLinear()
.domain([0, romerSolowData[romerSolowData.length - 1].Y])
.range([height, 0]);
svg
const yAxis = svg
.append("g")
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")))
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
yAxis.selectAll("text").style("font-size", "1.5em");
yAxis
.append("text")
.attr("fill", "#000")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "start")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("log(Y)");
svg
@ -570,31 +580,33 @@ function drawRomerSolowChangeGraph() {
);
const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
svg
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.call(d3.axisBottom(x));
xAxis.selectAll("text").style("font-size", "1.5em");
xAxis
.append("text")
.attr("fill", "#000")
.attr("x", width + 10)
.attr("y", -10)
.style("text-anchor", "end")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("t");
const y = d3
.scaleLinear()
.domain([0, romerSolowData[romerSolowData.length - 1].Y])
.range([height, 0]);
svg
const yAxis = svg
.append("g")
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")))
.call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
yAxis.selectAll("text").style("font-size", "1.5em");
yAxis
.append("text")
.attr("fill", "#000")
.attr("x", 0)
.attr("y", -10)
.style("text-anchor", "start")
.style("font-size", "1.5em")
.style("font-size", "2em")
.text("log(Y)");
svg
@ -617,7 +629,6 @@ function drawRomerSolowChangeGraph() {
.attr("y1", y(romerSolowData[T_MAX - 1].Y))
.attr("x2", x(t0))
.attr("y2", height)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("stroke-dasharray", "4");
@ -629,18 +640,27 @@ function drawRomerSolowChangeGraph() {
.text("log10(Y)");
}
document.addEventListener("DOMContentLoaded", function () {
drawSolowGraph();
drawRomerGraph();
drawRomerlGraph();
drawRomerSolowGraph();
drawRomerSolowChangeGraph();
window.onresize = () => {
drawSolowGraph();
drawRomerGraph();
drawRomerlGraph();
drawRomerSolowGraph();
drawRomerSolowChangeGraph();
};
window.onresize = () => {
drawSolowGraph();
drawRomerGraph();
drawRomerlGraph();
drawRomerSolowGraph();
drawRomerSolowChangeGraph();
};
new MutationObserver(() => {
drawSolowGraph();
drawRomerGraph();
drawRomerlGraph();
drawRomerSolowGraph();
drawRomerSolowChangeGraph();
}).observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});

View file

@ -11,6 +11,16 @@
width: 60%;
}
.graph svg line,
.graph svg path.domain,
.graph svg .tick line {
stroke: var(--text);
}
.graph svg text {
fill: var(--text);
}
.slider {
display: flex;
align-items: center;
@ -27,7 +37,7 @@
appearance: none;
width: 100%;
height: 2px;
background: black;
background: var(--text);
cursor: pointer;
outline: none;
transform: translateY(-50%);
@ -36,26 +46,29 @@
.slider input::-webkit-slider-thumb {
-webkit-appearance: none;
width: 2px;
height: 15px;
background: black;
cursor: col-resize;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--text);
cursor: pointer;
position: relative;
}
.slider input::-moz-range-thumb {
width: 2px;
height: 15px;
background: black;
cursor: col-resize;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--text);
cursor: pointer;
position: relative;
border: none;
}
.slider input::-webkit-slider-runnable-track,
.slider input::-moz-range-track {
width: 100%;
height: 2px;
background: black;
background: var(--text);
border: none;
}
@ -64,6 +77,10 @@
justify-content: center;
}
.sliders li {
list-style: none;
}
.romer-table-container {
display: flex;
justify-content: center;
@ -79,7 +96,7 @@
#romer-table th,
#romer-table td {
border: 1px solid black;
border: 1px solid var(--border);
text-align: center;
padding: 5px;
}

View file

@ -22,7 +22,7 @@ li {
.post-title::before {
content: "";
position: absolute;
background-color: var(--topic-color, black);
background-color: var(--topic-color, var(--text));
height: 30px;
width: 2px;
bottom: -10px;
@ -32,7 +32,7 @@ li {
.post-title::after {
content: "";
position: absolute;
background-color: var(--topic-color, black);
background-color: var(--topic-color, var(--text));
width: 200px;
height: 2px;
bottom: -10px;
@ -103,7 +103,7 @@ article h3::before,
.post-article h3::before {
position: absolute;
left: 0;
color: var(--topic-color, #000);
color: var(--topic-color, var(--text));
margin-right: 0.5em;
}
@ -118,12 +118,13 @@ article pre {
padding: 1rem;
overflow-x: auto;
border-radius: 4px;
background: var(--code-bg) !important;
border: 1px solid var(--border);
}
pre * {
background: var(--code-bg) !important;
[data-theme="dark"] .astro-code,
[data-theme="dark"] .astro-code span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
}
:not(pre) > code {
@ -133,7 +134,7 @@ pre * {
white-space: nowrap;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--code-bg) !important;
background: var(--code-bg);
}
.astro-code {

View file

@ -38,4 +38,4 @@
}
</style>
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>

View file

@ -40,4 +40,4 @@ const promptText = topic ? `barrett@ruth:~$ ${topic}` : "barrett@ruth:~$";
}
</style>
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>

View file

@ -30,7 +30,7 @@ const lines = Astro.props.code.trim().split(/\r?\n/);
<pre
class="pseudocode-block">
{lines.map((line, i) => (
<div class="pseudocode-line" key={i}>
<div class="pseudocode-line">
<span class="line-number">{i + 1}.</span>
<span class="line-content">{line}</span>
</div>

View file

@ -4,8 +4,7 @@ date: "30/07/2024"
useKatex: true
---
import { Code } from 'astro:components';
import { Code } from "astro:components";
# context
@ -15,7 +14,6 @@ While working for [TRB Capital Management](https://trbcap.com/), certain strateg
Design a data structure supporting the following operations:
- `build(size_t capacity)` : initialize the data structure with capacity/window size `capacity`
The data structure must always hold $\leq$ `capacity` prices.
- `void push_back(double value)`

View file

@ -103,7 +103,7 @@ def countFairPairs(self, nums, lower, upper):
## optimizing the approach
If we interpret the criteria this way, the above approach is relatively efficient. To improve this approach, we'll need to reinterpret the constraints. Forget about the indexing and consider the constraint in aggregate. We want to find all $i,j$ with $x=nums$i$+nums$j$$ such that $i\neq j,lower\leq x\leq upper$.
If we interpret the criteria this way, the above approach is relatively efficient. To improve this approach, we'll need to reinterpret the constraints. Forget about the indexing and consider the constraint in aggregate. We want to find all $i,j$ with $x=nums[i]+nums[j]$ such that $i\neq j,lower\leq x\leq upper$.
We _still_ need to reduce the “dimensionality” of the problem—there are just too many moving parts to consider at once. This seems challening. Let's simplify the problem to identify helpful ideas: pretend `lower` does not exist (and, of course, that `nums` is sorted).

View file

@ -14,7 +14,9 @@ This post offers a basic introduction to the Solow, Romer, and Romer-Solow econo
The Solow Model is an economic model of production that incorporates the idea of capital accumulation. Based on the [Cobb-Douglas production function](https://en.wikipedia.org/wiki/Cobb%E2%80%93Douglas_production_function), the Solow Model describes production as follows:
$$Y_t=F(K_t,L_t)=\bar{A}K_t^\alpha L_t^{1-\alpha}$$
$$
Y_t=F(K_t,L_t)=\bar{A}K_t^\alpha L_t^{1-\alpha}
$$
With:
@ -41,7 +43,9 @@ Visualizing the model, namely output as a function of capital, provides helpful
Letting $(L_t,\alpha)=(\bar{L}, \frac{1}{3})$, it follows that:
$$Y_t=F(K_t,L_t)=\bar{A}K_t^{\frac{1}{3}} \bar{L}^{\frac{2}{3}}$$
$$
Y_t=F(K_t,L_t)=\bar{A}K_t^{\frac{1}{3}} \bar{L}^{\frac{2}{3}}
$$
Utilizing this simplification and its graphical representation below, output is clearly characterized by the cube root of capital:
@ -119,17 +123,20 @@ When investment is completely disincentivized by depreciation (in other words, $
Using this equilibrium condition, it follows that:
$$Y_t^*=\bar{A}{K_t^*}^\alpha\bar{L}^{1-\alpha}$$
$$\rightarrow \bar{d}K_t^*=\bar{s}\bar{A}{K_t^*}^\alpha\bar{L}^{1-\alpha}$$
$$\rightarrow K^*=\bar{L}(\frac{\bar{s}\bar{A}}{\bar{d}})^\frac{1}{1-\alpha}$$
$$\rightarrow Y^*=\bar{A}^\frac{1}{1-\alpha}(\frac{\bar{s}}{\bar{d}})^\frac{\alpha}{1-\alpha}\bar{L}$$
$$
\begin{align*}
Y_t^* &= \bar{A}{K_t^*}^\alpha\bar{L}^{1-\alpha} \\
\bar{d}K_t^* &= \bar{s}\bar{A}{K_t^*}^\alpha\bar{L}^{1-\alpha} \\
K^* &= \bar{L}(\frac{\bar{s}\bar{A}}{\bar{d}})^\frac{1}{1-\alpha} \\
Y^* &= \bar{A}^\frac{1}{1-\alpha}(\frac{\bar{s}}{\bar{d}})^\frac{\alpha}{1-\alpha}\bar{L}
\end{align*}
$$
Thus, the equilibrium intensive form (output per worker) of both capital and output are summarized as follows:
$$(k^*,y^*)=(\frac{K^*}{\bar{L}},\frac{Y^*}{\bar{L}}) =((\frac{\bar{s}\bar{A}}{\bar{d}})^\frac{1}{1-\alpha}, \bar{A}^\frac{1}{1-\alpha}(\frac{\bar{s}}{\bar{d}})^\frac{\alpha}{1-\alpha})$$
$$
(k^*,y^*)=(\frac{K^*}{\bar{L}},\frac{Y^*}{\bar{L}}) =((\frac{\bar{s}\bar{A}}{\bar{d}})^\frac{1}{1-\alpha}, \bar{A}^\frac{1}{1-\alpha}(\frac{\bar{s}}{\bar{d}})^\frac{\alpha}{1-\alpha})
$$
### analysis
@ -138,7 +145,6 @@ Using both mathematical intuition and manipulating the visualization above, we f
- $\bar{A}$ has a positive relationship with steady-state output
- Capital is influenced by workforce size, TFP, and savings rate
- Capital output share's $\alpha$ impact on output is twofold:
1. Directly through capital quantity
2. Indirectly through TFP
@ -147,7 +153,9 @@ Using both mathematical intuition and manipulating the visualization above, we f
Lastly (and perhaps most importantly), exogenous parameters $\bar{s}, \bar{d}$, and $\bar{A}$ all have immense ramifications on economic status. For example, comparing the difference in country $C_1$'s output versus $C_2$'s using the Solow Model, we find that a difference in economic performance can only be explained by these factors:
$$\frac{Y_1}{Y_2}=\frac{\bar{A_1}}{\bar{A_2}}(\frac{\bar{s_1}}{\bar{s_2}})^\frac{\alpha}{1-\alpha}$$
$$
\frac{Y_1}{Y_2}=\frac{\bar{A_1}}{\bar{A_2}}(\frac{\bar{s_1}}{\bar{s_2}})^\frac{\alpha}{1-\alpha}
$$
We see that TFP is more important in explaining the differences in per-capital output ($\frac{1}{1-\alpha}>\frac{\alpha}{1-\alpha},\alpha\in[0,1)$). Notably, the Solow Model does not give any insights into how to alter the most important predictor of output, TFP.
@ -168,7 +176,9 @@ The Model divides the world into two parts:
The Romer Models' production function can be modelled as:
$$Y_t=F(A_t,L_{yt})=A_tL_{yt}$$
$$
Y_t=F(A_t,L_{yt})=A_tL_{yt}
$$
With:
@ -179,7 +189,9 @@ Assuming $L_t=\bar{L}$ people work in the economy, a proportion $\bar{l}$ of the
Further, this economy garners ideas with time at rate $\bar{z}$: the "speed of ideas". Now, we can describe the quantity of ideas tomorrow as function of those of today: <u>the Law of Ideal Motion</u> (I made that up).
$$A_{t+1}=A_t+\bar{z}A_tL_{at}\leftrightarrow\Delta A_{t+1}=\bar{z}A_tL_{at}$$
$$
A_{t+1}=A_t+\bar{z}A_tL_{at}\leftrightarrow\Delta A_{t+1}=\bar{z}A_tL_{at}
$$
Analagously to capital in the solow model, ideas begin in the economy with some $\bar{A}_0\gt0$ and grow at an _exponential_ rate. At its core, this is because ideas are non-rivalrous; more ideas bring about more ideas.
@ -280,19 +292,27 @@ Playing with the sliders, this graph may seem underwhelming in comparison to the
To find the output in terms of exogenous parameters, first note that
$$L_t=\bar{L}\rightarrow L_{yt}=(1-\bar{l})\bar{L}$$
$$
L_t=\bar{L}\rightarrow L_{yt}=(1-\bar{l})\bar{L}
$$
Now, all that remains is to find ideas $A_t$. It is assumed that ideas grow at some rate $g_A$:
$$A_t=A_0(1+g_A)^t$$
$$
A_t=A_0(1+g_A)^t
$$
Using the growth rate formula, we find:
$$g_A=\frac{\Delta A_{t+1}-A_t}{A_t}=\frac{A_t+\bar{z}A_tL_{at}-A_t}{A_t}=\bar{z}L_{at}=\bar{z}\bar{l}\bar{L}$$
$$
g_A=\frac{\Delta A_{t+1}-A_t}{A_t}=\frac{A_t+\bar{z}A_tL_{at}-A_t}{A_t}=\bar{z}L_{at}=\bar{z}\bar{l}\bar{L}
$$
Thus, ideas $A_t=A_0(1+\bar{z}\bar{l}\bar{L})^t$. Finally, output can be solved the production function:
$$Y_t=A_t L_{yt}=A_0(1+\bar{z}\bar{l}\bar{L})^t(1-\bar{l})\bar{L}$$
$$
Y_t=A_t L_{yt}=A_0(1+\bar{z}\bar{l}\bar{L})^t(1-\bar{l})\bar{L}
$$
### analysis
@ -385,7 +405,9 @@ From previous analysis it was found that $g_A=\bar{z}\bar{l}\bar{L}$.
Based on the Law of Capital Motion,
$$g_K=\frac{\Delta K_{t+1}}{K_t}=\bar{s}\frac{Y_t}{K_t}-\bar{d}$$
$$
g_K=\frac{\Delta K_{t+1}}{K_t}=\bar{s}\frac{Y_t}{K_t}-\bar{d}
$$
Because growth rates are constant on the Balanced Growth Path, $g_K$ must be constant as well. Thus, so is $\bar{s}\frac{Y_t}{K_t}-\bar{d}$; it must be that $g_K^*=g_Y^*$.
@ -393,24 +415,35 @@ The model assumes population is constant, so $g_{\bar{L}}=0\rightarrow g_{\bar{L
Combining these terms, we find:
$$g_Y^*=\bar{z}\bar{l}\bar{L}+\alpha g_Y^*+(1-\alpha)\cdot 0\rightarrow$$
$$g_Y^*=\frac{\bar{z}\bar{l}\bar{L}}{1-\alpha}$$
$$
\begin{align*}
g_Y^* &= \bar{z}\bar{l}\bar{L}+\alpha g_Y^*+(1-\alpha)\cdot 0 \\
g_Y^* &= \frac{\bar{z}\bar{l}\bar{L}}{1-\alpha}
\end{align*}
$$
Solving for $Y_t^*$ is trivial after discovering $g_K=g_Y$ must hold on a balanced growth path.
Invoking the <u>Law of Capital Motion</u> with magic chants,
$$g_K^*=\bar{s}\frac{Y_t^*}{K_t^*}-\bar{d}=g_Y^*\rightarrow K_t^*=\frac{\bar{s}Y_t^*}{g_Y^*+\bar{d}}$$
$$
g_K^*=\bar{s}\frac{Y_t^*}{K_t^*}-\bar{d}=g_Y^*\rightarrow K_t^*=\frac{\bar{s}Y_t^*}{g_Y^*+\bar{d}}
$$
Isolating $Y_t^*$,
$$Y_t^*=A_t^* (\frac{\bar{s}Y_t^*}{g_Y^*+\bar{d}})^\alpha ({(1-\bar{l})\bar{L}})^{1-\alpha}$$
$$\rightarrow {Y_t^*}^{1-\alpha}=A_t^*(\frac{\bar{s}}{g_Y^*+\bar{d}})^\alpha({(1-\bar{l})\bar{L}})^{1-\alpha}$$
$$
\begin{align*}
Y_t^* &= A_t^* (\frac{\bar{s}Y_t^*}{g_Y^*+\bar{d}})^\alpha ({(1-\bar{l})\bar{L}})^{1-\alpha} \\
{Y_t^*}^{1-\alpha} &= A_t^*(\frac{\bar{s}}{g_Y^*+\bar{d}})^\alpha({(1-\bar{l})\bar{L}})^{1-\alpha}
\end{align*}
$$
Plugging in the known expressions for $A_t^*$ and $g_Y^*$, a final expression for the Balanced Growth Path output as a function of the endogenous parameters and time is obtained:
$$Y_t^*={(A_0(1+\bar{z}\bar{l}\bar{L})^t})^\frac{1}{1-\alpha}(\frac{\bar{s}}{\frac{\bar{z}\bar{l}\bar{L}}{1-\alpha}+\bar{d}})^\frac{\alpha}{1-\alpha}(1-\bar{l})\bar{L}$$
$$
Y_t^*={(A_0(1+\bar{z}\bar{l}\bar{L})^t})^\frac{1}{1-\alpha}(\frac{\bar{s}}{\frac{\bar{z}\bar{l}\bar{L}}{1-\alpha}+\bar{d}})^\frac{\alpha}{1-\alpha}(1-\bar{l})\bar{L}
$$
### analysis

View file

@ -5,7 +5,7 @@ useKatex: true
useD3: true
---
import Pseudocode from '@components/Pseudocode.astro';
import Pseudocode from "@components/Pseudocode.astro";
A computer science student attempting to learn proofs.
@ -14,16 +14,19 @@ A computer science student attempting to learn proofs.
## E
Minimize-Digit-Diff($l, r$):
1. Initialize $ans=18$, the largest possible value of $f(l, x) + f(x, r)$ with $l \leq r\leq 10^9$
2. For $i:=1$ to $200$:
- Let $x$ be a random sample from the open interval $[l, r]$
- Let $cost:=f(l, x) + f(x, r)$, computed in $O(1)$ time
- $ans:=min(ans,cost)$
- Let $x$ be a random sample from the open interval $[l, r]$
- Let $cost:=f(l, x) + f(x, r)$, computed in $O(1)$ time
- $ans:=min(ans,cost)$
3. Return $ans$
---
*Proof.*
_Proof._
We are interested in minimizing the expected probability of failure over $t\leq10^4$ tests. Firstly, consider a single test (i.e. a single $(l,r)$ input):
@ -32,7 +35,6 @@ Thus, a digit has approximately a $1-\frac{1}{5}=\frac{4}{5}$ probability of min
It follows that the candidate then has roughly a $(\frac{4}{5})^9\approx13\%$ chance of minimizing the entire score $f(l,x)+f(x,r)$.
So, one random sample $x$ has a $100-13\approx87\%$ chance of being a suboptimal candidate.
Consider sampling $n$ times--the probability of all random samples being suboptimal is $0.87^n$. Let's only settle for a probability of failure near $1/10^{10}$ and solve for our number of trials:
$$
@ -57,14 +59,14 @@ Maximize-F(s):
---
*Proof.*
_Proof._
Let $X$ and $Y$ be the number of occurrences of zeroes and ones in the substring $p$ of $s$. Then, $f(p)=max(X, Y)=\frac{X+Y+|X-Y|}{2}$. The goal is to compute:
$$
\begin{align*}
\sum_{1\leq r\leq n}\sum_{1\leq l<r} f(s[l:r+1])&=\sum_{1\leq r\leq n}\sum_{1\leq l<r} \frac{X+Y+|X-Y|}{2}
&=\frac{1}{2}(\sum_{1\leq r\leq n}\sum_{1\leq l<r} X+Y+\sum_{1\leq r\leq n}\sum_{1\leq l<r} |X-Y|)
\sum_{1\leq r\leq n}\sum_{1\leq l<r} f(s[l:r+1]) &= \sum_{1\leq r\leq n}\sum_{1\leq l<r} \frac{X+Y+|X-Y|}{2} \\
&= \frac{1}{2}(\sum_{1\leq r\leq n}\sum_{1\leq l<r} X+Y+\sum_{1\leq r\leq n}\sum_{1\leq l<r} |X-Y|)
\end{align*}
$$
@ -81,9 +83,9 @@ As $S_i<S_{j>i}$, $|S_{j>i}-S_i|=S_{j>i}-S_i$--the sum is unchanged. Rewriting t
$$
\begin{align*}
\sum_{1\leq r\leq n}\sum_{1\leq l<r} |X-Y| &=\sum_{1\leq r\leq n}\sum_{1\leq l<r}S_r-\sum_{1\leq r\leq n}\sum_{1\leq l<r}S_l
&=\sum_{1\leq r\leq n}r\cdot S_r-\sum_{1\leq l<r\leq n} S_l
&=\sum_{1\leq r\leq n}r\cdot S_r-\sum_{1\leq r\leq n} (n-r)\cdot S_r
\sum_{1\leq r\leq n}\sum_{1\leq l<r} |X-Y| &= \sum_{1\leq r\leq n}\sum_{1\leq l<r}S_r-\sum_{1\leq r\leq n}\sum_{1\leq l<r}S_l \\
&= \sum_{1\leq r\leq n}r\cdot S_r-\sum_{1\leq l<r\leq n} S_l \\
&= \sum_{1\leq r\leq n}r\cdot S_r-\sum_{1\leq r\leq n} (n-r)\cdot S_r
\end{align*}
$$
@ -96,11 +98,12 @@ $\blacksquare$
## A
Count-Pairs($n$):
1. Return $n-1$
---
*Proof.*
_Proof._
Suppose $(a,b)\in\mathbb{N}^2$. Because $a=n-b$ and $a\geq1$, it follows that $1\leq b\leq n-1$. Each choice of $b$ yields a unique $a=n-b$, so there are $n-1$ unique solutions.
@ -109,15 +112,17 @@ $\blacksquare$
## B
Mirror-String($s$):
1. Reverse $s$
2. For each character $c$ in $s$:
- If $c$ is "w": Print($c$)
- If $c$ is "p": Print($q$)
- If $c$ is "q": Print($p$)
- If $c$ is "w": Print($c$)
- If $c$ is "p": Print($q$)
- If $c$ is "q": Print($p$)
---
*Proof.*
_Proof._
The string appears fipped on the y-axis from within the score due to the perspective
shifting. Structurally, it is read right-to-left. "p"/"q"/"w" appear as "q"/"p"/"w" when flipped on its y-axis.
@ -127,11 +132,12 @@ $\blacksquare$
## C
Seat-Monkeys($a$, $b$, $c$, $m$):
1. Return $min(m, a)+min(m, b)+min(c, 2\cdot m-(min(m, a) + min(m, b)))$
---
*Proof.*
_Proof._
Consider an assignment of monkeys $S$ that sits the $a$ and $b$ monkeys in the first and second row and then fills the remaining seats with the $c$ monkeys.
@ -140,11 +146,16 @@ Assume there exists a more optimal assignment of monkeys $S^{'}$. WLOG, assume $
$S^{'}$ can only differ from $S$ as follows:
1. Seats a $c$ monkey in row 1 instead of an $a$ monkey
- $S^{'}$ leaves an $a$ monkey unseated. $S$ seats this monkey instead--the same number of monkeys are seated in $S$.
- $S^{'}$ leaves an $a$ monkey unseated. $S$ seats this monkey instead--the same number of monkeys are seated in $S$.
2. Seats a $c$ monkey in row 2 instead of a $b$ monkey
- $S^{'}$ leaves a $b$ monkey unseated. $S$ seats this monkey instead--the same number of monkeys are seated in $S$.
- $S^{'}$ leaves a $b$ monkey unseated. $S$ seats this monkey instead--the same number of monkeys are seated in $S$.
3. Does not seat a monkey where $S$ has
- $S$ seats more than $S^{'}$.
- $S$ seats more than $S^{'}$.
In all cases, $S^{'}$ is no better than S, therefore $S$ is optimal.
@ -153,21 +164,26 @@ $\blacksquare$
## D
Construct-B($a$):
1. Let $b$ be an array of size $n=\#a$ and $X$ be the set of numbers in $a$.
2. For each element $x$ of $a$ at index $i$:
- If $x\in X$:
- $b[i]:=x$
- $X:=X \backslash \{x\}$
3. Let $Y=\{1,2,\cdots,n\}\backslash X$
4. For each element $x$ of $b$ at index $i$:
- If $b[i]$ is NIL:
- $b[i]:=\text{first-element}(Y)$
- $Y:=Y\backslash\{\text{first-element}{(Y)}\}$
5. Return $b$
---
*Proof.*
_Proof._
Consider the array $b$ from Construct-B.
@ -182,17 +198,21 @@ $\blacksquare$
## E
Count-Pairs($l_1$, $l_2$, $r_1$, $r_2$, $k$):
1. Let $A:=\lfloor log_k(r_2/l_1)\rfloor$
2. Let $B:=\lfloor max(0, log_k(l_2/r_1))\rfloor$
3. Let $\text{total}:=0$
4. For each $A\leq i\leq B$:
- Let $r=\lfloor r_2/ k^n\rfloor$
- Let $l=\lfloor l_2/k^n\rfloor$
- $\text{total} := \text{total} + max(0, r - l + 1)$
5. Return $\text{total}$
---
*Proof.*
_Proof._
Each value of $n$ corresponds to a line with slope $k^n$ because $y/x=k^n\leftrightarrow y=x\cdot k^n$. The problem can be visualized as follows:
@ -206,12 +226,13 @@ For each $n_0$ in this range, the smallest $x$ satisfying $y=x\cdot k^n_0$ is $\
1. Let $A=\sum a$ and $B=\sum b$.
2. For each query with requested beauty $q$:
- If $\exists (i,j)\in(\{1,2,\cdots,n\},\{1,2,\cdots,m\}):(A-a[i])\cdot(B-b[j])=x$, print "YES"
- Otherwise, print "NO"
---
*Proof.*
_Proof._
The beauty of the grid equals $B=\sum_i \sum_j M_{i,j}=\sum_i\sum_j a_i\cdot b_j=\sum_i(a_i\cdot \sum_j b_j)=(\sum_i a_i)\cdot (\sum_j b_j)$.
@ -231,14 +252,16 @@ If such $a_i$ and $b_j$ exist, the operation can be performed.
1. Let $G$ be the input graph
2. Let $\text{ans}=0$
3. For each component $C$ in $G$:
- Let $\text{cycle}$ be the set of nodes in the cycle of $C$
- Let $d=max_{u\in \text{cycle}}\text{Distance-To-Cycle(C, u)}$
- $\text{ans}:=max(\text{ans}, d)$
- Let $\text{cycle}$ be the set of nodes in the cycle of $C$
- Let $d=max_{u\in \text{cycle}}\text{Distance-To-Cycle(C, u)}$
- $\text{ans}:=max(\text{ans}, d)$
4. Return $\text{ans}$
---
*Proof.*
_Proof._
Consider some $v_i\in V$. There must exist an edge $e=(v_i,v_j),i\neq j$. Following this path from $v_i$, the each edge must map to a previously seen node, forming a cycle, or a new node. Because the graph is finite, the path starting any $v_i$ must contain a cycle. Thus, G is a graph of components with one cycle each.
@ -260,18 +283,20 @@ $\blacksquare$
1. Let $G$ be the input graph
2. Let $\text{ans}=0$
3. For each component $C$ in $G$:
- Let $U$ be the set of all nodes not in the cycle of $C$
- Let $\text{count}$ be the number of plushies each spider has
- Let $\text{par}$ be the set of parents for each spider
- Run a multi-source BFS simulating the state transitions on $U$. For each iteration at year $y$:
- $\text{count[u]}:=\text{count[u]}+\sum_{p\in \text{par[u]}}\text{count[p]}$
- $\text{ans}:=max(\text{ans}, \text{count[u]})$
- $y:=y+1$
- Let $U$ be the set of all nodes not in the cycle of $C$
- Let $\text{count}$ be the number of plushies each spider has
- Let $\text{par}$ be the set of parents for each spider
- Run a multi-source BFS simulating the state transitions on $U$. For each iteration at year $y$:
- $\text{count[u]}:=\text{count[u]}+\sum_{p\in \text{par[u]}}\text{count[p]}$
- $\text{ans}:=max(\text{ans}, \text{count[u]})$
- $y:=y+1$
4. Return $\text{ans}$
---
*Proof.*
_Proof._
Consider some $v_i\in V$. There must exist an edge $e=(v_i,v_j),i\neq j$. Following this path from $v_i$, the each edge must map to a previously seen node, forming a cycle, or a new node. Because the graph is finite, the path starting any $v_i$ must contain a cycle. Thus, G is a graph of components with one cycle each.
@ -295,7 +320,9 @@ $\blacksquare$
- Let $\text{Colwise}$ be the column-wise 2D-prefix coefficient sum matrix of $A$
- Let $\text{Rowwise}$ be the row-wise 2D-prefix coefficient sum matrix of $A$
- Let $\text{Submatrix-Sum}(x_1,y_1,x_2,y_2)$ compute the sum of the submatrix of $M$ bounded by $(x_1,y_1)$ and $(x_2,y_2)$
1. For each query $x_1,x_2,y_1,y_2$:
- Let $w=y_2-y_1+1$
- Let $prefix=\text{Submatrix-Sum}(\text{Prefix},x_1,y_1,x_2,y_2)$
- Let $rowsum=\text{Submatrix-Sum}(\text{Rowwise},x_1,y_1,x_2,y_2)$
@ -304,7 +331,7 @@ $\blacksquare$
---
*Proof.*
_Proof._
Mathematically formulated:

View file

@ -71,19 +71,19 @@ This lead me to the follow structure:
![multi-threaded-design](/multithreading-a-gui/multi-threaded-implementation.webp)
- Three callback groups are triggered at differing intervals according to their urgency on the GUI node
- A thread-safe queue[^2] processes all ingested data for each callback group
- A thread-safe queue[^2] processes all ingested data for each callback group
- Every 10ms, the GUI is updated, highest to lowest urgency messages first
- The `MainWindow` houses the visualization widgets as before&mdash;however, the GUI thread actually performs the update logic
- GUI Widgets were re-implemented to be thread-safe with basic locking, a small amount of overhead for safe memory access
## \*actual\* multi-threaded implementation
Sounds good, right? Well, I should've done my research first. The Qt framework has *already internalized* the logic for this entire paradigm of multithreaded code. Turns out all I need are:
Sounds good, right? Well, I should've done my research first. The Qt framework has _already internalized_ the logic for this entire paradigm of multithreaded code. Turns out all I need are:
- [Signals/slots](https://doc.qt.io/qt-6/signalsandslots.html) and a `Qt::QueuedConnection`
- Running the GUI with `MultithreadedExecutor`
As it turns out, signals and slots *automatically* leverage ROS's internal thread-safe message queue, ensuring deserialization one at a time.
As it turns out, signals and slots _automatically_ leverage ROS's internal thread-safe message queue, ensuring deserialization one at a time.
The following (final) design employs two threads:
@ -132,8 +132,8 @@ Elegantly, registering a signal/slot with `Qt::QueuedConnection` does all of the
Looking back, this GUI should've been implemented with a modern web framework such as [React](https://react.dev/) with [react-ros](https://github.com/flynneva/react-ros?tab=readme-ov-file). CAR needs high-speed, reactive data, and a QtC++ front-end is simply not meant for this level of complexity. I made it a lot harder than it needed to be with my lack of due diligence, but the single-threaded GUI event loop in ROS is more harm than help.
[^1]: See [the ROS documentation](https://docs.ros.org/en/foxy/How-To-Guides/Using-callback-groups.onhtml) to learn more. The CAR publishes various topic-related data at set rates, so I'm looking to run various groups of mutually exclusive callbacks at a set interval (i.e. `MutuallyExclusive`)
[^2]: The simplest implementation did the job:
```cpp
@ -179,3 +179,4 @@ Looking back, this GUI should've been implemented with a modern web framework su
}
...
};
```

View file

@ -9,7 +9,7 @@ Given the recent switch to the [Marelli flag system](https://www.racecar-enginee
# the problem
Our original state machine implementation had grown organically over several racing seasons. What started as a simple finite state machine under a more trivial flag system grew vastly more complex as it maladapted to the new flag system. Specifically, the original flag system only had one flag system for the entire track and a few car-specific ones (i.e. request to retire the car after a rules violation). The Marelli flag system has both flag *and* vehicle flags, each of which enforces different requirements.
Our original state machine implementation had grown organically over several racing seasons. What started as a simple finite state machine under a more trivial flag system grew vastly more complex as it maladapted to the new flag system. Specifically, the original flag system only had one flag system for the entire track and a few car-specific ones (i.e. request to retire the car after a rules violation). The Marelli flag system has both flag _and_ vehicle flags, each of which enforces different requirements.
The state machine worked "fine" for its initial use case:
@ -29,7 +29,7 @@ State_Machine:
2. Subsequently, the code was read in and parsed with a [cpp yaml library](https://github.com/jbeder/yaml-cpp).
3. Since all of this was done at runtime, `state_actions`, `entry_condition`, and `next_states` were *manually parsed*, hard-coded in a sort of custom language encoded in a string. Opening up our codebase, I found this set of foundational structs that the data was converted into:
3. Since all of this was done at runtime, `state_actions`, `entry_condition`, and `next_states` were _manually parsed_, hard-coded in a sort of custom language encoded in a string. Opening up our codebase, I found this set of foundational structs that the data was converted into:
```cpp
struct Action {
@ -83,9 +83,9 @@ I knew state machines were ubiquitous in software so I explored a few previous a
1. One big switch: nested conditions (i.e. all combinations of vehicle + track flags) seemed a bit nightmarish to look at as we continue to build out the state machine
2. [Boost SMS](https://www.boost.org/library/latest/msm/): this and other existing libraries looked enticing but three things stopped me:
1. Integrating dependencies into our production code is simple but takes time for other members of the team to vet it
2. It also bloats our deployment latency and final size because:
3. It is overkill and writing things from scratch is more fun
1. Integrating dependencies into our production code is simple but takes time for other members of the team to vet it
2. It also bloats our deployment latency and final size because:
3. It is overkill and writing things from scratch is more fun
3. A minimalist and expressive approach:
@ -121,7 +121,6 @@ enum class StateID { State1, State2, ..., Last };
A transition has entry and exit conditions which are compositions of state (i.e. just our bitmask) and an arbitrary action (i.e. a lambda). The entry/exit bits must be set/unset in order to enter/exit the state.
```cpp
struct Transition {
VehicleTrackFlags entry;

View file

@ -6,6 +6,7 @@ const base = z.object({
date: z.string().optional(),
useKatex: z.boolean().optional(),
useD3: z.boolean().optional(),
scripts: z.array(z.string()).optional(),
redirect: z.string().optional(),
});

View file

@ -12,12 +12,17 @@ Things have changed since I last documented my competitive programming setup [he
After many months of using the aforementioned `make` based setup, I had a few qualms:
- <u>I'm lazy</u>: I grew tired of copying (and mis-copying) inputs, outputs, etc from online judges.
- <u>I'm lazy</u>: I frequently submitted incorrect solutions after erroneously asserting that my outputs matched those of the sample test cases
- <u>External dependencies</u>: it unsettles me that my bare-bones setup required copy-pasting an entire suite of scripts
- <u>Non-native NeoVim experience</u>: while composition and the UNIX philosophy are great, there's only so much you can do with pipes and files.
- Raw I/O files meant I couldn't see colored stdin/stdout
- Fine-grained per-testcase I/O was suspect--isolating and running a subset of test cases required manual intervention
- <u>I'm lazy</u>: I grew tired of copying (and mis-copying) inputs, outputs,
etc from online judges.
- <u>I'm lazy</u>: I frequently submitted incorrect solutions after erroneously
asserting that my outputs matched those of the sample test cases
- <u>External dependencies</u>: it unsettles me that my bare-bones setup
required copy-pasting an entire suite of scripts
- <u>Non-native NeoVim experience</u>: while composition and the UNIX philosophy
are great, there's only so much you can do with pipes and files. - Raw I/O
files meant I couldn't see colored stdin/stdout - Fine-grained per-testcase
I/O was suspect--isolating and running a subset of test cases required manual
intervention
The solution was to leverage Neovim's great APIs to give me granular control over every aspect of my problem-solving experience.
@ -25,22 +30,42 @@ The solution was to leverage Neovim's great APIs to give me granular control ove
The GitHub page documents the plugin well enough so I'll avoid re-hashing it here. Instead, what's more interesting to document is why I thought this was a worthwhile experience.
1. <u>Making Something Useful for Others</u>: cp.nvim is an opportunity for me to make my first open-source project "right"--not some side project or demo, but a *real*, usable tool that I'll be rolling out to the public soon. I consider the following in my active development of the plugin:
1. <u>Making Something Useful for Others</u>: cp.nvim is an opportunity for me
to make my first open-source project "right"--not some side project or demo,
but a *real*, usable tool that I'll be rolling out to the public soon. I
consider the following in my active development of the plugin:
- Comprehensive continuous integration (*real* testing, linting, and more)
- Comprehensive continuous integration (_real_ testing, linting, and more)
- [LuaRocks](https://luarocks.org/) integration (the future of NeoVim package management)
- Concise and thorough Vimdoc documentation that communicates effectively
- Modern lua tooling: use of [busted](https://lunarmodules.github.io/busted/), [selene](https://kampfkarren.github.io/selene/) and more integrated with the NeoVim lua interpreter
- Sensible user defaults & extreme customization
- Proper versioning, tagging, and releases
2. <u>The Neovim Community</u>: I'm elated to finally give back to the community (even if no one uses this plugin). [folke](https://github.com/folke), [bfredl](https://github.com/bfredl), and [echasnovski](https://github.com/echasnovski) are my greatest inspirations as an open-source developer and I've had enough of taking without giving back.
2. <u>The Neovim Community</u>: I'm elated to finally give back to the community
(even if no one uses this plugin). [folke](https://github.com/folke),
[bfredl](https://github.com/bfredl), and
[echasnovski](https://github.com/echasnovski) are my greatest inspirations as
an open-source developer and I've had enough of taking without giving back.
- In the coming months I plan to contribute to [NeoVim core](https://github.com/neovim/neovim), including making `:checkhealth` asynchronous and integrating an [mdx](https://mdxjs.com/) parser.
3. <u>Learning Random things</u>: I think this plugin is *really* cool by virtue of its efficacy and the miscellany of knowledge I accrued in the 15k+ LOC as of version v0.3.0. Some things I learned include:
3. <u>Learning Random things</u>: I think this plugin is *really* cool by virtue
of its efficacy and the miscellany of knowledge I accrued in the 15k+ LOC as
of version v0.3.0. Some things I learned include:
- <u>ANSI terminal colors and escape codes</u>: I wrote my own stateful ANSI escape sequence parser to map raw bytes to native NeoVim highlighted text
- <u>Extmarks</u>: NeoVim extmarks (`:h extmarks`) are extremely powerful. Here, I used them to apply dynamic highlighting across various components of the plugin but I also plan to leverage virtual text to catch compile errors in real-time
- <u>VIM filetypes and diffing</u>: Vim is strange and the event-based system is fragile. I faced filetype detection race conditions and odd side effects of functions (such as `:diffthis` resetting `foldcolumn`).
- <u>[LuaCATS](https://github.com/LuaCATS)</u>: apparently writing comments is the best way to typecheck in lua...
- <u>The (Neo)Vim event loop</u>: Scraper subprocesses spawned with `vim.system`. Though a powerful API, I often had to obey the event loop and wrap side effects with `vim.schedule` to ensure they ran after jobs finished. This was useful to defer UI updates.
- <u>ANSI terminal colors and escape codes</u>: I wrote my own stateful ANSI
escape sequence parser to map raw bytes to native NeoVim highlighted text
- <u>Extmarks</u>: NeoVim extmarks (`:h extmarks`) are extremely powerful. Here,
I used them to apply dynamic highlighting across various components of the
plugin but I also plan to leverage virtual text to catch compile errors in
real-time
- <u>VIM filetypes and diffing</u>: Vim is strange and the event-based system is
fragile. I faced filetype detection race conditions and odd side effects of
functions (such as `:diffthis` resetting `foldcolumn`).
- <u>[LuaCATS](https://github.com/LuaCATS)</u>: apparently writing comments is
the best way to typecheck in lua...
- <u>The (Neo)Vim event loop</u>: Scraper subprocesses spawned with
`vim.system`. Though a powerful API, I often had to obey the event loop and
wrap side effects with `vim.schedule` to ensure they ran after jobs finished.
This was useful to defer UI updates.

View file

@ -83,7 +83,7 @@ Restart=on-failure
[Install]
WantedBy=multi-user.target
````
```
12. I use the name `main` instead of `master` as my default branch (it's less letters, ok?)--set this up on the server too:

View file

@ -52,7 +52,9 @@ const {
case "git":
return "#cc5500";
default:
return "#000000";
return getComputedStyle(document.documentElement)
.getPropertyValue("--text")
.trim();
}
};
</script>

View file

@ -1,5 +1,5 @@
---
const { frontmatter, post } = Astro.props;
const { frontmatter } = Astro.props;
---
<html lang="en">
@ -10,7 +10,7 @@ const { frontmatter, post } = Astro.props;
<link rel="stylesheet" href="/styles/posts.css" />
<link rel="stylesheet" href="/styles/git.css" />
<slot name="head" />
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>
</head>
<body>
<header class="post-header">

View file

@ -22,14 +22,6 @@ interface Props {
const { frontmatter, post } = Astro.props as Props;
const { title, description, useKatex = false, useD3 = false } = frontmatter;
const filePath = post?.id ?? "";
const categoryFromId = (filePath.split("/")[0] ?? "").replace(
/\.(mdx?|MDX?)$/,
"",
);
const category =
(frontmatter.category ?? post?.collection ?? categoryFromId) || "";
let documentTitle = title;
if (post?.collection === "git" && post?.slug) {
documentTitle = `${post.slug}.git`;
@ -40,7 +32,7 @@ if (post?.collection === "git" && post?.slug) {
documentTitle = `${post.slug}`;
}
const topicColor = getTopicColor(post.collection);
const topicColor = getTopicColor(post?.collection);
---
<BaseLayout title={documentTitle} description={description}>
@ -57,10 +49,14 @@ const topicColor = getTopicColor(post.collection);
/>
)
}
{useD3 && <script src="https://d3js.org/d3.v7.min.js" is:inline />}
<slot name="head" />
</Fragment>
<div class="post-container" style={`--topic-color: ${topicColor};`}>
<div
class="post-container"
style={topicColor ? `--topic-color: ${topicColor};` : ""}
>
<header class="post-header">
<h1 class="post-title">{title}</h1>
{frontmatter.date && <p class="post-meta">{frontmatter.date}</p>}
@ -72,9 +68,9 @@ const topicColor = getTopicColor(post.collection);
</div>
<Fragment slot="scripts">
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>
<script src="/scripts/centerKatex.js" is:inline></script>
{frontmatter.scripts?.map((src) => <script type="module" src={src} />)}
{frontmatter.scripts?.map((src) => <script src={src} is:inline />)}
<slot name="scripts" />
</Fragment>
</BaseLayout>

View file

@ -10,7 +10,7 @@ import BaseLayout from "../layouts/BaseLayout.astro";
<script>
document.addEventListener("DOMContentLoaded", function () {
const base = (window && window.TERMINAL_PROMPT) || "barrett@ruth:~$ ";
const base = "barrett@ruth:~$ ";
const el = document.querySelector(".terminal-prompt");
if (!el) return;
@ -26,11 +26,7 @@ import BaseLayout from "../layouts/BaseLayout.astro";
})();
};
if (window && typeof window.clearPrompt === "function") {
window.clearPrompt(250, type);
} else {
type();
}
type();
});
</script>

View file

@ -2,13 +2,18 @@
import { getCollection } from "astro:content";
import PostLayout from "../../layouts/PostLayout.astro";
import * as collections from "../../content/config";
import type { PostCollection, AnyCollectionEntry } from "../../types";
export async function getStaticPaths() {
const categories = Object.keys(collections.collections).filter(
(c) => c !== "git" && c !== "gists",
);
) as PostCollection[];
const entries: Array<{
params: { category: string; slug: string };
props: { post: AnyCollectionEntry };
}> = [];
const entries = [];
for (const category of categories) {
const docs = await getCollection(category);
for (const doc of docs) {
@ -21,6 +26,10 @@ export async function getStaticPaths() {
return entries;
}
interface Props {
post: AnyCollectionEntry;
}
const { post } = Astro.props;
const category = Astro.params.category;
const { Content } = await post.render();
@ -34,7 +43,7 @@ if (post.data?.redirect) {
<PostLayout frontmatter={post.data} post={post}>
<Fragment slot="head">
<title>{pageTitle}</title>
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>
</Fragment>
<Content />
</PostLayout>

View file

@ -3,6 +3,7 @@ import BaseLayout from "../../layouts/BaseLayout.astro";
import { getCollection } from "astro:content";
import { sortItem } from "../../utils/sort.js";
import * as collections from "../../content/config";
import type { PostCollection } from "../../types";
export async function getStaticPaths() {
return Object.keys(collections.collections)
@ -12,7 +13,7 @@ export async function getStaticPaths() {
}));
}
const category = Astro.params.category;
const category = Astro.params.category as PostCollection;
const title = "Barrett Ruth";
const posts = await getCollection(category);

View file

@ -11,7 +11,7 @@ gists.sort(sortItem);
<BaseLayout title={title}>
<slot name="head" slot="head">
<link rel="stylesheet" href="/styles/index.css" />
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>
</slot>
<div class="content">

View file

@ -11,7 +11,7 @@ repos.sort(sortItem);
<BaseLayout title={title}>
<slot name="head" slot="head">
<link rel="stylesheet" href="/styles/index.css" />
<script type="module" src="/scripts/index.js"></script>
<script src="/scripts/index.js" is:inline></script>
</slot>
<div class="content">

View file

@ -2,11 +2,26 @@
import BaseLayout from "../layouts/BaseLayout.astro";
import { sortItem } from "../utils/sort.js";
import { getCollection } from "astro:content";
import type { PostCollection } from "../types";
const title = "Barrett Ruth";
const CATS = ["algorithms", "software", "meditations", "autonomous-racing"];
const CATS: PostCollection[] = [
"algorithms",
"software",
"meditations",
"autonomous-racing",
];
const postsByCategory = {};
type PostData = {
id: string;
slug: string;
data: {
title: string;
date: string | null;
};
};
const postsByCategory: Record<string, PostData[]> = {};
for (const c of CATS) {
const entries = await getCollection(c);
entries.sort(sortItem);
@ -46,8 +61,8 @@ for (const c of CATS) {
<div class="posts" id="posts"></div>
</div>
<script slot="scripts" define:vars={{ postsByCategory }}>
<script slot="scripts" define:vars={{ postsByCategory }} is:inline>
window.postsByCategory = postsByCategory;
</script>
<script slot="scripts" type="module" src="/scripts/index.js"></script>
<script slot="scripts" src="/scripts/index.js" is:inline></script>
</BaseLayout>

18
src/types.ts Normal file
View file

@ -0,0 +1,18 @@
import type { CollectionEntry } from "astro:content";
export type CollectionKey =
| "algorithms"
| "software"
| "meditations"
| "autonomous-racing"
| "git"
| "gists";
export type PostCollection = Exclude<CollectionKey, "git" | "gists">;
export type AnyCollectionEntry =
| CollectionEntry<"algorithms">
| CollectionEntry<"software">
| CollectionEntry<"meditations">
| CollectionEntry<"autonomous-racing">
| CollectionEntry<"git">
| CollectionEntry<"gists">;

View file

@ -11,6 +11,6 @@ export function getTopicColor(topicName) {
case "git":
return "#cc5500";
default:
return "#000000";
return null;
}
}