Compare commits

..

No commits in common. "wip" and "main" have entirely different histories.
wip ... main

302 changed files with 1512 additions and 4288 deletions

View file

@ -1 +0,0 @@
3.12

View file

@ -1,57 +0,0 @@
# f3l
activity tracker. 100% compliant with the activitypub "federated server" conformance profile.
## what does it do
per the "federated server" conformance profile of the activitypub specification, you can:
- POST an as2 Activity to outbox for delivery processing
- POST an as2 Activity to inbox to receive deliveries
## what does it NOT do
anything not required by the activitypub specification is out of scope. this includes but is not limited to:
- behaviors and side effects that are recommended in activitypub but not required.
- behaviors and side effects not described in activitypub. this is an implementation of the activitypub protocol. it aims to be compliant with the activitypub specification and nothing more.
- anything the "fediverse" does.
- authentication and authorization. if you want that, use a reverse proxy.
## why
to prove a point.
many activitypub partisans talk about how easy it is to implement activitypub, and how doing so enables compatibility with numerous projects, many of which are part of what is called the "fediverse". to anyone who looks further into these claims, it should quickly become apparent that activitypub is a necessary but not sufficient component of the communication protocol of the fediverse. furthermore, the "protocol of the fediverse" is implicit, not explicit; there is no formal definition for the complete set of behavioral requirements that are prerequisite to communicating with any given fediverse project which nominally speaks "activitypub". in the absence of such a formal definition, softwares that participate in the "fediverse" often implement "activitypub" as defined by some primary target for their interoperability. for example, a project targeting interoperability with mastodon will likely follow <https://docs.joinmastodon.org/spec/activitypub> in implementing what is informally known as the "mastodon flavour", "mastodon profile", or "mastodon protocol".
this project therefore exists as a counterbalance to the above issue. rather than targeting "activitypub" as defined by the "mastodon protocol", it targets "activitypub" as defined by the "activitypub specification".
## is this useful
maybe. probably not to most people, especially if you want to talk to people on the "fediverse". but i intend to use this to power a page on my website that tracks my activities. this is the most minimal viable usage of activitypub that i can think of. the page will be available at https://trwnh.com/now or something, and it will draw its data from https://trwnh.com/activities or some other thing which will be reverse proxied.
## the requirements
almost everything is optional, including delivery (per https://github.com/swicg/meetings/tree/main/2023-11-17#ap-issue-297 errata). one could argue that it is possible to fully comply with activitypub by implementing outbox and inbox endpoints that accept an HTTP POST and then do absolutely nothing with it, but
### section 7.1.1: outbox
- target inboxes for delivery based on values of to/cc/audience/bto/bcc (errata https://github.com/swicg/meetings/tree/main/2023-11-17#ap-issue-297 changes this to a SHOULD but not incorporated yet)
### section 7: s2s delivery
- don't add new recipients other than what's in the addressing properties (to/cc/audience/bto/bcc)
- dereference any collections "with the user's credentials"; limit collection depth when discovering inboxes
- dedupe the final recipients list
- exclude yourself from the recipients list (per https://github.com/w3c/activitypub/issues/480 maybe this should be relaxed)
- POST to any ldp:inbox discovered with `Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"` (arguably this type should have never been defined, but it is what it is) (also per errata https://github.com/swicg/meetings/tree/main/2023-11-17#ap-issue-297 this is changed to a SHOULD but not incorporated yet)
- Create/Update/Delete/Follow/Add/Remove/Like/Block/Undo (and Announce?) require an `object`
- Add/Remove require a `target`
### 7.1.2: inbox forwarding
- forward any activity being seen for the first time if the to/cc/audience contains a collection owned by you and the activity is relevant to some local object (by way of inReplyTo, object, target, tag)
### 7.5: Follow activity
- if you get a Follow in the inbox and respond with a Reject Follow, do not add that actor to your followers

View file

@ -1,164 +0,0 @@
from typing import Iterable, Set
from fastapi import FastAPI, Request, Response, status, HTTPException
from fastapi.responses import PlainTextResponse
import httpx
from starlette.exceptions import HTTPException as StarletteHTTPException
from uuid_extensions import uuid7str
import mimeparse
from mimeparse import parse_mime_type
import json
app = FastAPI()
SUPPORTED_CONTENT_TYPES = [
'application/activity+json',
'application/ld+json',
'text/turtle',
]
THE_ACTOR_NAMESPACE = 'http://localhost:8000/'
# Override JSON error responses to plain text instead
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
return PlainTextResponse(
content=str(exc.detail),
status_code=exc.status_code,
headers=exc.headers,
)
async def get_inboxes_from_resources(resources: Iterable[str]) -> Set[str]:
"""
Discover an ldp:inbox for every resource passed in.
"""
pass
async def get_inbox_from_resource(resource: str) -> str:
"""
Discover an ldp:inbox for a resource.
"""
try:
async with httpx.AsyncClient() as client:
if not '#' in resource:
response = await client.head(resource)
links = response.links
print(links)
return
response = await client.get(resource)
except:
pass
@app.post("/outbox")
async def post_outbox(request: Request) -> Response:
"""
Accept a notification payload and deliver to ActivityPub targets,
per the S2S "Federated Server" conformance profile.
"""
try:
# Validate Content-Type
(
mime_maintype,
mime_subtype,
mime_params
) = parse_mime_type(
request.headers.get('Content-Type'),
)
mime_type = mime_maintype + '/' + mime_subtype
if mime_type not in SUPPORTED_CONTENT_TYPES:
raise HTTPException(
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
headers={
'Accept-Post': ', '.join(SUPPORTED_CONTENT_TYPES)
},
detail=(
'HTTP Error 415: Unsupported Media Type\n'
f'This endpoint does not requests of the type {mime_type}\n\n'
'The supported types are:\n\n'
f'{'\n'.join(SUPPORTED_CONTENT_TYPES)}'
),
)
# Handle notification payload
IS_ACTIVITYSTREAMS = (
mime_type == 'application/activity+json'
or (
mime_type == 'application/ld+json'
and mime_params.get('profile') == 'https://www.w3.org/ns/activitystreams'
)
)
if IS_ACTIVITYSTREAMS:
"""
We can use shorthand terms because it is guaranteed
to be compacted against AS2 context at least.
"""
body = await request.body()
activity = json.loads(body)
# Get delivery targets
as_to = activity.get('to', [])
as_cc = activity.get('cc', [])
as_audience = activity.get('audience', [])
as_bto = activity.get('bto', [])
as_bcc = activity.get('bcc', [])
# TODO: Expand collections into actors
# Deduplicate the final recipients list
delivery_targets = set(as_to + as_cc + as_audience + as_bto + as_bcc)
# Find their inboxes
inboxes = await get_inboxes_from_resources(delivery_targets)
else:
"""
We should use full IRIs and treat this as RDF.
"""
# TODO: do this
raise HTTPException(
status_code=status.HTTP_501_NOT_IMPLEMENTED,
detail=(
'HTTP Error 501: Not Implemented\n'
'I still need to add support for non-AS2 payloads...'
),
)
# Prepare Location header for response and persist activity to storage
path = f'activities/{uuid7str()}'
location = THE_ACTOR_NAMESPACE+path
headers = {
'Location': location
}
# Respond with 201 Created + Location header
return PlainTextResponse(
content=f'Created activity at {location}',
status_code=status.HTTP_201_CREATED,
headers=headers,
)
except mimeparse.MimeTypeParseException as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=(
'HTTP Error 400: Bad Request.\n'
'Could not parse the Content-Type of the request.\n\n'
f'{e}'
),
)
except json.JSONDecodeError as e:
line_where_the_error_occurs = str(body, encoding='utf-8').split('\n')[e.lineno-1]
before_the_error = line_where_the_error_occurs[max(0,e.colno-11):e.colno]
after_the_error = line_where_the_error_occurs[e.colno:min(e.colno+10,len(line_where_the_error_occurs))]
where_the_error_occurs = before_the_error + after_the_error + '\n' + '.'*(len(before_the_error)-1) + '^'
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=(
'HTTP Error 400: Bad Request.\n'
'Content-Type was detected as JSON-based, '
'but request body could not be parsed as JSON.\n\n'
f'{e}\n'
f'{where_the_error_occurs}'
),
)
@app.post("/inbox")
async def post_inbox(request: Request):
pass

View file

@ -1,23 +0,0 @@
from fastapi import Response, status
from ..server import app
@app.get("/resource1")
async def test_resource() -> Response:
response = Response(status_code=status.HTTP_200_OK)
response.headers.append('Link', '<https://inbox.example>; rel="http://www.w3.org/ns/ldp#inbox"')
return response
@app.get("/resource2")
async def test_resource2() -> Response:
response = Response(status_code=status.HTTP_200_OK)
response.headers.append('Link', '<https://inbox.example>; rel="http://www.w3.org/ns/ldp#inbox"')
response.headers.append('Link', '<https://inbox.example>; rel="unrelated"')
return response
@app.get("/resource3")
async def test_resource2() -> Response:
response = Response(status_code=status.HTTP_200_OK)
response.headers.append('Link', '<https://inbox.example>; rel="http://www.w3.org/ns/ldp#inbox"')
response.headers.append('Link', '<https://inbox.example>; rel="unrelated"')
return response

View file

@ -1,12 +0,0 @@
[project]
name = "f3l"
version = "0.1.0"
description = "activity tracker. 100% compliant with activitypub s2s."
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi[standard]>=0.115.4",
"python-mimeparse>=2.0.0",
"rdflib>=7.1.1",
"uuid7>=0.1.0",
]

View file

@ -1,600 +0,0 @@
version = 1
requires-python = ">=3.12"
resolution-markers = [
"python_full_version < '3.13'",
"python_full_version >= '3.13'",
]
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
]
[[package]]
name = "anyio"
version = "4.6.2.post1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
]
[[package]]
name = "certifi"
version = "2024.8.30"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 },
]
[[package]]
name = "click"
version = "8.1.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "platform_system == 'Windows'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
]
[[package]]
name = "dnspython"
version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 },
]
[[package]]
name = "email-validator"
version = "2.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "dnspython" },
{ name = "idna" },
]
sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 },
]
[[package]]
name = "f3l"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "fastapi", extra = ["standard"] },
{ name = "python-mimeparse" },
{ name = "rdflib" },
{ name = "uuid7" },
]
[package.metadata]
requires-dist = [
{ name = "fastapi", extras = ["standard"], specifier = ">=0.115.4" },
{ name = "python-mimeparse", specifier = ">=2.0.0" },
{ name = "rdflib", specifier = ">=7.1.1" },
{ name = "uuid7", specifier = ">=0.1.0" },
]
[[package]]
name = "fastapi"
version = "0.115.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "starlette" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/db/5781f19bd30745885e0737ff3fdd4e63e7bc691710f9da691128bb0dc73b/fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349", size = 300737 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/f6/af0d1f58f86002be0cf1e2665cdd6f7a4a71cdc8a7a9438cdc9e3b5375fe/fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", size = 94732 },
]
[package.optional-dependencies]
standard = [
{ name = "email-validator" },
{ name = "fastapi-cli", extra = ["standard"] },
{ name = "httpx" },
{ name = "jinja2" },
{ name = "python-multipart" },
{ name = "uvicorn", extra = ["standard"] },
]
[[package]]
name = "fastapi-cli"
version = "0.0.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typer" },
{ name = "uvicorn", extra = ["standard"] },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/f8/1ad5ce32d029aeb9117e9a5a9b3e314a8477525d60c12a9b7730a3c186ec/fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f", size = 15571 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/24/ea/4b5011012ac925fe2f83b19d0e09cee9d324141ec7bf5e78bb2817f96513/fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46", size = 9489 },
]
[package.optional-dependencies]
standard = [
{ name = "uvicorn", extra = ["standard"] },
]
[[package]]
name = "h11"
version = "0.14.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
]
[[package]]
name = "httpcore"
version = "1.0.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 },
]
[[package]]
name = "httptools"
version = "0.6.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 },
{ url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 },
{ url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 },
{ url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837 },
{ url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 },
{ url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 },
{ url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 },
{ url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 },
{ url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 },
{ url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 },
{ url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 },
{ url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 },
{ url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 },
{ url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 },
]
[[package]]
name = "httpx"
version = "0.27.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "certifi" },
{ name = "httpcore" },
{ name = "idna" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 },
]
[[package]]
name = "idna"
version = "3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
[[package]]
name = "jinja2"
version = "3.1.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 },
]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
]
[[package]]
name = "markupsafe"
version = "3.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 },
{ url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 },
{ url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 },
{ url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 },
{ url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 },
{ url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 },
{ url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 },
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
{ url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
{ url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
{ url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
{ url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 },
{ url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 },
{ url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 },
{ url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 },
{ url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 },
{ url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
{ url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
{ url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 },
{ url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 },
{ url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 },
{ url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 },
{ url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 },
{ url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 },
{ url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 },
{ url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 },
{ url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
]
[[package]]
name = "pydantic"
version = "2.9.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 },
]
[[package]]
name = "pydantic-core"
version = "2.23.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 },
{ url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 },
{ url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 },
{ url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 },
{ url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 },
{ url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 },
{ url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 },
{ url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 },
{ url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 },
{ url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 },
{ url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 },
{ url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 },
{ url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 },
{ url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 },
{ url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 },
{ url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 },
{ url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 },
{ url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 },
{ url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 },
{ url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 },
{ url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 },
{ url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 },
{ url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 },
{ url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 },
]
[[package]]
name = "pygments"
version = "2.18.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 },
]
[[package]]
name = "pyparsing"
version = "3.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8c/d5/e5aeee5387091148a19e1145f63606619cb5f20b83fccb63efae6474e7b2/pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c", size = 920984 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/be/ec/2eb3cd785efd67806c46c13a17339708ddc346cbb684eade7a6e6f79536a/pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", size = 106921 },
]
[[package]]
name = "python-dotenv"
version = "1.0.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
]
[[package]]
name = "python-mimeparse"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/cd/85/c40f2e0b2128905f6c34894be01803c114f2b2efab0e8b4c3dca5e56b999/python_mimeparse-2.0.0.tar.gz", hash = "sha256:5b9a9dcf7aa82465e31bd667f5cb7000604811dce83554f1c8a43693a32cb303", size = 7162 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/65/d9/1093a9d6d22d04d433003c96b9b1d46741b43fee5b11ece5098297737fce/python_mimeparse-2.0.0-py3-none-any.whl", hash = "sha256:574062a06f2e1d416535c8d3b83ccc6ebe95941e74e2c5939fc010a12e37cc09", size = 5576 },
]
[[package]]
name = "python-multipart"
version = "0.0.17"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 },
]
[[package]]
name = "pyyaml"
version = "6.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 },
{ url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 },
{ url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 },
{ url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 },
{ url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 },
{ url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 },
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
]
[[package]]
name = "rdflib"
version = "7.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyparsing" },
]
sdist = { url = "https://files.pythonhosted.org/packages/62/b6/4cee25689c7a3dfafeb481d358e74696fe3a8543da4cb2c1b71c0cb6583d/rdflib-7.1.1.tar.gz", hash = "sha256:164de86bd3564558802ca983d84f6616a4a1a420c7a17a8152f5016076b2913e", size = 4864216 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/7d/9add7b22a4e695c4f3011ed084ecf725e1f03954b9fa071f1766890b4989/rdflib-7.1.1-py3-none-any.whl", hash = "sha256:e590fa9a2c34ba33a667818b5a84be3fb8a4d85868f8038f17912ec84f912a25", size = 562443 },
]
[[package]]
name = "rich"
version = "13.9.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
]
[[package]]
name = "shellingham"
version = "1.5.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
]
[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
[[package]]
name = "starlette"
version = "0.41.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 },
]
[[package]]
name = "typer"
version = "0.12.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "rich" },
{ name = "shellingham" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/58/a79003b91ac2c6890fc5d90145c662fd5771c6f11447f116b63300436bc9/typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722", size = 98953 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a8/2b/886d13e742e514f704c33c4caa7df0f3b89e5a25ef8db02aa9ca3d9535d5/typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", size = 47288 },
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
]
[[package]]
name = "uuid7"
version = "0.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5c/19/7472bd526591e2192926247109dbf78692e709d3e56775792fec877a7720/uuid7-0.1.0.tar.gz", hash = "sha256:8c57aa32ee7456d3cc68c95c4530bc571646defac01895cfc73545449894a63c", size = 14052 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b5/77/8852f89a91453956582a85024d80ad96f30a41fed4c2b3dce0c9f12ecc7e/uuid7-0.1.0-py2.py3-none-any.whl", hash = "sha256:5e259bb63c8cb4aded5927ff41b444a80d0c7124e8a0ced7cf44efa1f5cccf61", size = 7477 },
]
[[package]]
name = "uvicorn"
version = "0.32.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e0/fc/1d785078eefd6945f3e5bab5c076e4230698046231eb0f3747bc5c8fa992/uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e", size = 77564 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/eb/14/78bd0e95dd2444b6caacbca2b730671d4295ccb628ef58b81bee903629df/uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", size = 63723 },
]
[package.optional-dependencies]
standard = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "httptools" },
{ name = "python-dotenv" },
{ name = "pyyaml" },
{ name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
{ name = "watchfiles" },
{ name = "websockets" },
]
[[package]]
name = "uvloop"
version = "0.21.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 },
{ url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 },
{ url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 },
{ url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 },
{ url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 },
{ url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 },
{ url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 },
{ url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 },
{ url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 },
{ url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 },
{ url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 },
{ url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 },
]
[[package]]
name = "watchfiles"
version = "0.24.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 },
{ url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 },
{ url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 },
{ url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 },
{ url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 },
{ url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 },
{ url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 },
{ url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 },
{ url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 },
{ url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 },
{ url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 },
{ url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 },
{ url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 },
{ url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 },
{ url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 },
{ url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 },
{ url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 },
{ url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 },
{ url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 },
{ url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 },
{ url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 },
{ url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 },
{ url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 },
{ url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 },
{ url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 },
]
[[package]]
name = "websockets"
version = "13.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 },
{ url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 },
{ url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 },
{ url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 },
{ url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 },
{ url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 },
{ url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 },
{ url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 },
{ url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 },
{ url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 },
{ url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 },
{ url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 },
{ url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 },
{ url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 },
{ url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 },
{ url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 },
{ url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 },
{ url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 },
{ url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 },
{ url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 },
{ url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 },
{ url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 },
{ url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 },
]

View file

@ -14,8 +14,8 @@
} }
svg { svg {
display: block; display: block;
inline-size: 100%; width: 100%;
block-size: 100%; height: 100%;
background: black; background: black;
} }
</style> </style>

View file

@ -20,15 +20,15 @@
font-family: zii; font-family: zii;
font-size:2em; font-size:2em;
letter-spacing: 0.125em; letter-spacing: 0.125em;
padding-inline-start: 1rem; padding-left: 1rem;
} }
h1 span { h1 span {
display: block; display: block;
} }
img { img {
image-rendering: pixelated; image-rendering: pixelated;
inline-size: 100%; width: 100%;
block-size: 100%; height: 100%;
object-fit: contain; object-fit: contain;
object-position: right; object-position: right;
} }

View file

@ -22,27 +22,27 @@ html {font-family: -apple-system, BlinkMacSystemFont,
"Fira Sans", "Droid Sans", "Helvetica Neue", "Segoe UI", sans-serif} "Fira Sans", "Droid Sans", "Helvetica Neue", "Segoe UI", sans-serif}
/* typography */ /* typography */
header h1 {font-size: clamp(1.5rem, 10vw, 3rem); line-height: 1.333} header h1 {font-size: clamp(1.5rem, 10vw, 3rem); line-height: 1.333}
header p {font-size: clamp(1em, 5vw, 1.5rem); line-height: 1.5; max-inline-size: 32ch} header p {font-size: clamp(1em, 5vw, 1.5rem); line-height: 1.5; max-width: 32ch}
h2 {font-size: 1.5rem; line-height: 1.333; margin-block-end: 1rem; max-inline-size: 35ch} h2 {font-size: 1.5rem; line-height: 1.333; margin-bottom: 1rem; max-width: 35ch}
p {font-size: 1rem; line-height: 1.5} p {font-size: 1rem; line-height: 1.5}
/* layout */ /* layout */
body {margin: auto; min-height: 100vh} body {margin: auto; min-height: 100vh}
section, footer {margin-block-start: 2.5rem} section, footer {margin-top: 2.5rem}
footer {padding-block-end: 1rem; display: flex; justify-content: center} footer {padding-bottom: 1rem; display: flex; justify-content: center}
.container {padding: 0 1rem; height: 100%;} .container {padding: 0 1rem; height: 100%;}
header {position: relative;} header {position: relative;}
header .container {position: absolute; inset-block-end: 0; inline-size: 100%; block-size: fit-content} header .container {position: absolute; bottom: 0; width: 100%; height: fit-content}
header img {inline-size: 100vw; block-size: 100vw; max-inline-size: 100%; max-block-size: 600px; object-fit: cover; object-position: bottom} header img {width: 100vw; height: 100vw; max-width: 100%; max-height: 600px; object-fit: cover; object-position: bottom}
header h1 {grid-row: 2} header h1 {grid-row: 2}
header p {grid-row: 3} header p {grid-row: 3}
dl {display: grid; grid-template-columns: 6.5rem 1fr} dl {display: grid; grid-template-columns: 6.5rem 1fr}
dt {grid-column: 1; font-weight: 700; line-height: 1.5} dt {grid-column: 1; font-weight: 700; line-height: 1.5}
dd {grid-column: 2; line-height: 1.5; display: flex; justify-content: end} dd {grid-column: 2; line-height: 1.5; display: flex; justify-content: end}
dd a {display: block; max-inline-size: max-content} dd a {display: block; max-width: max-content}
dt, dd {margin-block-start: 0.5rem} dt, dd {margin-top: 0.5rem}
dl p {grid-column: span 2; max-inline-size: 18rem} dl p {grid-column: span 2; max-width: 18rem}
.links {display: flex; flex-flow: column; gap: 1rem} .links {display: flex; flex-flow: column; gap: 1rem}
.links a {display: flex; max-inline-size: max-content; gap: 1rem} .links a {display: flex; max-width: max-content; gap: 1rem}
.links span {font-size: 1rem; line-height: 2; display: block} .links span {font-size: 1rem; line-height: 2; display: block}
#gaming .links {flex-flow: row} #gaming .links {flex-flow: row}
#gaming .links span {flex-grow: 1; text-align: right} #gaming .links span {flex-grow: 1; text-align: right}
@ -52,8 +52,8 @@ body:before {
position: fixed; position: fixed;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
inset-inline-start: 0; left: 0;
inset-block-start: 0; top: 0;
background: url(./.assets/images/sunset-square-bg-blue.min.jpg); background: url(./.assets/images/sunset-square-bg-blue.min.jpg);
background-size: cover; background-repeat: no-repeat; background-size: cover; background-repeat: no-repeat;
background-position: center; background-position: center;
@ -70,7 +70,7 @@ img {color: white}
@media (min-width: 30rem) { @media (min-width: 30rem) {
#gaming .container {display: flex; justify-content: space-between} #gaming .container {display: flex; justify-content: space-between}
#gaming .links span {flex-grow: unset} #gaming .links span {flex-grow: unset}
#gaming h2 {margin-block-end: 0} #gaming h2 {margin-bottom: 0}
} }
@media (min-width: 35rem) { @media (min-width: 35rem) {
.container {padding: 0 2rem} .container {padding: 0 2rem}
@ -80,8 +80,8 @@ img {color: white}
body {margin: 0 auto; width: 40rem} body {margin: 0 auto; width: 40rem}
} }
@media (max-height: 30rem) and (min-aspect-ratio: 1) { @media (max-height: 30rem) and (min-aspect-ratio: 1) {
header img {inline-size: 100vw; block-size: 100vh; object-position: center} header img {width: 100vw; height: 100vh; object-position: center}
header .container {inset-block-end: 1rem} header .container {bottom: 1rem}
} }
</style> </style>
<!-- end default styling -------------------------------------------> <!-- end default styling ------------------------------------------->

View file

@ -94,7 +94,7 @@
h2 { h2 {
background-color: var(--color-titlebar); background-color: var(--color-titlebar);
padding: 1rem; padding: 1rem;
margin-inline-start: -1rem; margin-left: -1rem;
border-radius: 0 100rem 100rem 0; border-radius: 0 100rem 100rem 0;
} }

View file

@ -11,7 +11,7 @@
.grey {background: #23f0c7} .grey {background: #23f0c7}
</style> </style>
<style> <style>
#plumeLogo {inline-size: 48px; block-size: 100%; margin: 0 1em} #plumeLogo {width: 48px; height: 100%; margin: 0 1em}
.trwnhFeather path {stroke-width: 4px; fill: #7765e3; stroke: #333} .trwnhFeather path {stroke-width: 4px; fill: #7765e3; stroke: #333}
.trwnhParagraphs path {fill: #7765e3;} .trwnhParagraphs path {fill: #7765e3;}
.trwnhParagraphs {background: transparent} .trwnhParagraphs {background: transparent}

View file

@ -29,7 +29,7 @@
</script> </script>
<style> <style>
article { article {
max-inline-size: 80ch; max-width: 80ch;
} }
</style> </style>
</head> </head>

View file

@ -6,7 +6,7 @@
<title>what is web</title> <title>what is web</title>
<style> <style>
article { article {
max-inline-size: 80ch; max-width: 80ch;
} }
aside { aside {
font-size: 0.8em; font-size: 0.8em;

View file

@ -1,10 +1,8 @@
@import "mixins/prepend-icon";
@import "common/reset"; @import "common/reset";
@import "common/colors"; @import "common/colors";
@import "common/base"; @import "common/base";
@import "common/elements";
@import "common/typography"; @import "common/typography";
@import "common/elements";
@import "features/links"; @import "features/links";
@import "features/syntax-highlighting"; @import "features/syntax-highlighting";
@ -13,28 +11,11 @@
@import "components/table-of-contents"; @import "components/table-of-contents";
@import "components/site-header"; @import "components/site-header";
@import "components/site-footer";
// default layout // default layout
@import "layouts/_default/list"; @import "layouts/_default/list";
@import "components/feed-header";
@import "components/feed-permalink";
@import "components/feed-entries";
@import "components/feed-entry";
@import "components/feed-entry-compact";
@import "components/feed-entry-in-series";
@import "layouts/_default/single"; @import "layouts/_default/single";
@import "components/article";
@import "components/article-header";
@import "components/article-authors";
@import "components/article-published-datetime";
@import "components/in-reply-to-prepend";
@import "components/article-tags";
@import "components/article-permalink";
@import "components/article-syndication-list";
@import "components/article-series-list";
@import "features/content"; @import "features/content";
@import "layouts/_default/_markup/render-heading"; @import "layouts/_default/_markup/render-heading";
@ -42,12 +23,12 @@
@import "layouts/partials/mf2/h-entry"; @import "layouts/partials/mf2/h-entry";
@import "layouts/partials/mf2/h-card"; @import "layouts/partials/mf2/h-card";
@import "layouts/partials/mf2/u-in-reply-to";
@import "components/admonition"; @import "components/admonition";
@import "components/quote-block"; @import "components/quote-block";
@import "components/codeblock"; @import "components/codeblock";
@import "components/alt-formats"; @import "components/series-list";
@import "components/figure-with-blockquote"; @import "components/syndication-list";
@import "features/footnotes"; @import "features/footnotes";

View file

@ -1,5 +1,5 @@
:root { :root {
--site-max-width: 100em; --site-max-width: 120ch;
} }
html { html {
@ -46,17 +46,3 @@ Containers are an immediate child <div>, purely for constraining width.
outline: 1px dashed var(--ui-text); outline: 1px dashed var(--ui-text);
outline-offset: 4px; outline-offset: 4px;
} }
@media (min-width: 400px) {
.container {
padding: 0 2em;
}
}
.nobr {
display: inline-block;
}
cite.short-work {
font-style: normal;
}

View file

@ -15,8 +15,6 @@
--ui-overlay-transparent: hsla(210, 100%, 87.5%, 0.4); --ui-overlay-transparent: hsla(210, 100%, 87.5%, 0.4);
--ui-overlay-text: var(--ui-text); --ui-overlay-text: var(--ui-text);
--ui-overlay-highlight: hsl(210, 100%, 80%); --ui-overlay-highlight: hsl(210, 100%, 80%);
--ui-overlay-deemphasized: hsl(210, 100%, 95%);
--ui-blend: hsla(210, 100%, 87.5%, 75%);
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@ -37,7 +35,5 @@
--ui-overlay-transparent: hsla(210, 100%, 20%, 0.25); --ui-overlay-transparent: hsla(210, 100%, 20%, 0.25);
--ui-overlay-text: var(--ui-text); --ui-overlay-text: var(--ui-text);
--ui-overlay-highlight: hsl(210, 100%, 27.5%); --ui-overlay-highlight: hsl(210, 100%, 27.5%);
--ui-overlay-deemphasized: hsl(210, 100%, 5%);
--ui-blend: hsla(210, 100%, 10%, 75%);
} }
} }

View file

@ -32,6 +32,9 @@ mark {
padding-inline-start: var(--pad-x-highlight); padding-inline-start: var(--pad-x-highlight);
padding-inline-end: var(--pad-x-highlight); padding-inline-end: var(--pad-x-highlight);
} }
/* lists */
ul {list-style: disc;}
ol {list-style: decimal;}
/* tables */ /* tables */
table {text-align: center;} table {text-align: center;}
thead { thead {
@ -45,10 +48,11 @@ th, td {
} }
/* figures */ /* figures */
figure { figure {
margin: 0;
} }
figcaption { figcaption {
padding-block: 1em;
padding-inline: 1em;
} }
/* extra style and flair */ /* extra style and flair */
code { code {

View file

@ -2,7 +2,7 @@ h1 {font-size: 2.027rem}
h2 {font-size: 1.802rem} h2 {font-size: 1.802rem}
h3 {font-size: 1.602rem} h3 {font-size: 1.602rem}
h4 {font-size: 1.424rem} h4 {font-size: 1.424rem}
h5, .subtitle {font-size: 1.266rem} h5 {font-size: 1.266rem}
h6 {font-size: 1.125rem} h6 {font-size: 1.125rem}
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
line-height: 1.2; line-height: 1.2;
@ -10,7 +10,7 @@ h1, h2, h3, h4, h5, h6 {
margin-block-end: 1rem; margin-block-end: 1rem;
font-weight: bold; font-weight: bold;
} }
body {line-height: 2; letter-spacing: -0.022em;} body {line-height: 2;}
pre { pre {
line-height: 1.2; line-height: 1.2;
font-family: monospace; font-family: monospace;
@ -20,12 +20,8 @@ pre {
word-break: break-word; word-break: break-word;
tab-size: 3; tab-size: 3;
} }
/* lists */
ul {list-style-type: disc;}
ol {list-style-type: decimal;}
ul, ol { ul, ol {
padding-inline-start: 0; padding-inline-start: 0;
margin-inline-start: 0;
} }
li { li {
margin-inline-start: 1em; margin-inline-start: 1em;
@ -56,12 +52,9 @@ html {
sup { sup {
position: relative; position: relative;
font-size: var(--script-size); font-size: var(--script-size);
inset-block-start: -0.125em; inset-block-start: -1em;
padding-inline: 0.125em;
} }
sub { sub {
position: relative; position: relative;
font-size: var(--script-size); font-size: var(--script-size);
inset-block-end: -0.125em;
padding-inline: 0.125em;
} }

View file

@ -1,13 +1,32 @@
.admonition { .admonition {
background: var(--ui-overlay-transparent); background: var(--ui-overlay-transparent);
border-inline-start: 0.4em solid var(--ui-overlay); border-inline-start: 0.4em solid var(--ui-overlay);
// border-radius: 1em; border-radius: 1em;
padding-block-start: 1em; padding-block-start: 1em;
padding-block-end: 1em; padding-block-end: 1em;
position: relative; position: relative;
&-header { &-header {
display: contents; display: contents;
} }
&__icon {
position: absolute;
box-sizing: border-box;
background: var(--ui-overlay);
border-radius: 100em;
/* position the icon */
font-size: 3em;
padding: 0.25em;
inset-inline-start: -0.175em;
inset-block-start: -0em;
}
&__title {
font-size: 1em;
font-weight: bold;
padding-inline: 1em;
margin-block-start: -0.5em;
margin-inline-start: 2em;
margin-block-end: 0.5em;
}
&__text { &__text {
padding-inline: 1em; padding-inline: 1em;
> *:first-child { > *:first-child {
@ -17,77 +36,16 @@
margin-block-end: 0; margin-block-end: 0;
} }
} }
/* prepend an icon depending on the type of the admonition */ .info-icon {
&:before { background-color: hsl(210, 50%, 50%);
content: ''; color: white;
display: block;
position: absolute;
box-sizing: border-box;
inline-size: 2.5em;
block-size: 2.5em;
border-radius: 100em;
inset-inline-start: 1em;
inset-block-start: 1em;
background-repeat: no-repeat;
background-position: center;
background-size: 60%;
} }
&__title { .warning-icon {
font-size: 1em; background-color: hsl(50, 50%, 50%);
font-weight: bold; color: black;
padding-inline: 1em;
margin-block-start: 0.25em;
margin-inline-start: 3em;
margin-block-end: 1em;
} }
&[data-type="info"], .danger-icon {
&[data-type="note"], background-color: hsl(0, 50%, 50%);
&[data-type="tip"], color: white;
&[data-type="hint"]
{
// background-color: hsl(210, 50%, 10%);
border-color: hsl(210, 50%, 50%);
&:before {
background-color: hsl(210, 50%, 50%);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjAgMjAiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMTAgMmM0LjQyIDAgOCAzLjU4IDggOHMtMy41OCA4LTggOHMtOC0zLjU4LTgtOHMzLjU4LTggOC04bTEgNGMwLS41NS0uNDUtMS0xLTFzLTEgLjQ1LTEgMXMuNDUgMSAxIDFzMS0uNDUgMS0xbTAgOVY5SDl2NnoiLz48L3N2Zz4=);
}
}
&[data-type="recommended"],
&[data-type="recommendation"],
&[data-type="good"],
&[data-type="suggestion"],
&[data-type="suggested"],
&[data-type="success"]
{
// background-color: hsl(210, 50%, 10%);
border-color: hsl(120, 50%, 50%);
&:before {
background-color: hsl(120, 50%, 50%);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJtOS41NSAxOGwtNS43LTUuN2wxLjQyNS0xLjQyNUw5LjU1IDE1LjE1bDkuMTc1LTkuMTc1TDIwLjE1IDcuNHoiLz48L3N2Zz4=);
}
}
&[data-type="warning"],
&[data-type="caution"],
&[data-type="alert"],
&[data-type="notice"]
{
// background-color: hsl(50, 50%, 10%);
border-color: hsl(50, 75%, 40%);
&:before {
background-color: hsl(50, 75%, 40%);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0yMzYuOCAxODguMDlMMTQ5LjM1IDM2LjIyYTI0Ljc2IDI0Ljc2IDAgMCAwLTQyLjcgMEwxOS4yIDE4OC4wOWEyMy41MSAyMy41MSAwIDAgMCAwIDIzLjcyQTI0LjM1IDI0LjM1IDAgMCAwIDQwLjU1IDIyNGgxNzQuOWEyNC4zNSAyNC4zNSAwIDAgMCAyMS4zMy0xMi4xOWEyMy41MSAyMy41MSAwIDAgMCAuMDItMjMuNzJNMTIwIDEwNGE4IDggMCAwIDEgMTYgMHY0MGE4IDggMCAwIDEtMTYgMFptOCA4OGExMiAxMiAwIDEgMSAxMi0xMmExMiAxMiAwIDAgMS0xMiAxMiIvPjwvc3ZnPg==);
}
}
&[data-type="danger"],
&[data-type="important"],
&[data-type="fail"],
&[data-type="failure"]
{
// background-color: hsl(0, 50%, 10%);
border-color: hsl(0, 50%, 50%);
&:before {
background-color: hsl(0, 50%, 50%);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIzIiBkPSJNMTMuMjUzIDUuOThMMTIgMTMuNWwtMS4yNTMtNy41MmExLjI3IDEuMjcgMCAxIDEgMi41MDYgMCIvPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTkiIHI9IjEiIHN0cm9rZS13aWR0aD0iMiIvPjwvZz48L3N2Zz4=);
}
} }
} }

View file

@ -1,20 +0,0 @@
.alt-formats {
.path, .mediaType {font-family: monospace;}
&-hint {
margin-block-end: 0;
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNOS44IDE0LjVoMS42bC44LTIuM2gzLjY1bC44IDIuM2gxLjU1bC0zLjQtOWgtMS42em0yLjg1LTMuNmwxLjMtMy43NWguMWwxLjMgMy43NXpNOCAxOHEtLjgyNSAwLTEuNDEyLS41ODdUNiAxNlY0cTAtLjgyNS41ODgtMS40MTJUOCAyaDEycS44MjUgMCAxLjQxMy41ODhUMjIgNHYxMnEwIC44MjUtLjU4NyAxLjQxM1QyMCAxOHptLTQgNHEtLjgyNSAwLTEuNDEyLS41ODdUMiAyMFY2aDJ2MTRoMTR2MnoiLz48L3N2Zz4=),
45%,
55%
);
}
.alt-formats-list {
margin-block-start: 0;
list-style: none;
&-item {
margin-block: 0;
margin-inline-start: 2em;
a {}
}
}
}

View file

@ -1,9 +0,0 @@
.article-authors-hint {
display: none;
}
.article-authors {
list-style: none;
}
.article-author {
margin: 0;
}

View file

@ -1,16 +0,0 @@
.article-header {
hr {
display: none;
}
}
.article-title {
margin-block-start: 0;
line-height: 1.15;
letter-spacing: -0.022rem;
}
.article-summary {
font-style: italic;
line-height: 1.15;
letter-spacing: -0.022rem;
margin-block-start: 0.5rem;
}

View file

@ -1,7 +0,0 @@
.article-permalink {
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMyAzdjE4aDE4VjN6bTE1IDE1SDZ2LTFoMTJ6bTAtMkg2di0xaDEyem0wLTRINlY2aDEyeiIvPjwvc3ZnPg==),
50%,
50%
);
}

View file

@ -1,13 +0,0 @@
.article-published-datetime {
.time {
}
.date {
}
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMTIgMkExMCAxMCAwIDAgMCAyIDEyYTEwIDEwIDAgMCAwIDEwIDEwYTEwIDEwIDAgMCAwIDEwLTEwQTEwIDEwIDAgMCAwIDEyIDJtNC4yIDE0LjJMMTEgMTNWN2gxLjV2NS4ybDQuNSAyLjd6Ii8+PC9zdmc+),
52.5%,
47.5%
);
}

View file

@ -1,17 +0,0 @@
.article-syndication-hint {
margin-block-end: 0;
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMTcgMjJxLTEuMjUgMC0yLjEyNS0uODc1VDE0IDE5cTAtLjE1LjA3NS0uN0w3LjA1IDE0LjJxLS40LjM3NS0uOTI1LjU4OFQ1IDE1cS0xLjI1IDAtMi4xMjUtLjg3NVQyIDEydC44NzUtMi4xMjVUNSA5cS42IDAgMS4xMjUuMjEzdC45MjUuNTg3bDcuMDI1LTQuMXEtLjA1LS4xNzUtLjA2Mi0uMzM3VDE0IDVxMC0xLjI1Ljg3NS0yLjEyNVQxNyAydDIuMTI1Ljg3NVQyMCA1dC0uODc1IDIuMTI1VDE3IDhxLS42IDAtMS4xMjUtLjIxM1QxNC45NSA3LjJsLTcuMDI1IDQuMXEuMDUuMTc1LjA2My4zMzhUOCAxMnQtLjAxMi4zNjN0LS4wNjMuMzM3bDcuMDI1IDQuMXEuNC0uMzc1LjkyNS0uNTg3VDE3IDE2cTEuMjUgMCAyLjEyNS44NzVUMjAgMTl0LS44NzUgMi4xMjVUMTcgMjIiLz48L3N2Zz4=),
50%,
50%
);
}
.article-syndication-list {
margin-block-start: 0;
list-style: none;
&-item {
margin-block: 0;
margin-inline-start: 2em;
.u-syndication {}
}
}

View file

@ -1,7 +0,0 @@
.article-tags {
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNNS41IDdBMS41IDEuNSAwIDAgMSA0IDUuNUExLjUgMS41IDAgMCAxIDUuNSA0QTEuNSAxLjUgMCAwIDEgNyA1LjVBMS41IDEuNSAwIDAgMSA1LjUgN20xNS45MSA0LjU4bC05LTlDMTIuMDUgMi4yMiAxMS41NSAyIDExIDJINGMtMS4xMSAwLTIgLjg5LTIgMnY3YzAgLjU1LjIyIDEuMDUuNTkgMS40MWw4Ljk5IDljLjM3LjM2Ljg3LjU5IDEuNDIuNTlzMS4wNS0uMjMgMS40MS0uNTlsNy03Yy4zNy0uMzYuNTktLjg2LjU5LTEuNDFjMC0uNTYtLjIzLTEuMDYtLjU5LTEuNDIiLz48L3N2Zz4=),
55%,
55%
);
}

View file

@ -1,63 +0,0 @@
.article {
&-footer {
hr {
display: none;
}
}
}
.article[has-toc] {
padding-block-end: 4em;
> .table-of-contents {display: none;}
#toc-toggle {
display: none;
&:checked ~ .table-of-contents {
display: block;
position: fixed;
z-index: 10;
inset-block-end: 6em;
block-size: max-content;
inline-size: 80%;
max-inline-size: 20em;
max-block-size: #{m}in(40em, 70vh);
overflow-block: scroll;
inset-inline-end: 1em;
background: var(--ui-overlay);
border-radius: 1em;
@include shadow-low;
padding-inline: 1em;
> .container {
padding: 0;
}
}
}
label[for="toc-toggle"] {
position: fixed;
inset-block-end: 1em;
inset-inline-end: 1em;
z-index: 5;
background: var(--ui-overlay);
padding: 1em;
border-radius: 100em;
inline-size: 6em;
display: flex;
justify-content: center;
@include shadow-low;
}
#toc-toggle ~ label[for="toc-toggle"] {
}
#toc-toggle:checked ~ label[for="toc-toggle"] {
}
#toc-toggle__label-hide {
display: none;
}
#toc-toggle:checked ~ #toc-toggle__label-hide {
display: flex;
}
#toc-toggle:checked ~ #toc-toggle__label-show {
display: none;
}
}

View file

@ -1,15 +0,0 @@
.feed-entries {
inline-size: 100%;
&-list {
list-style: none;
padding-inline-start: 0;
margin-block: 0;
&-item {
margin-inline-start: 0;
margin-block: 2em;
&:first-child {
margin-block-start: 0;
}
}
}
}

View file

@ -1,27 +0,0 @@
.feed-entry-compact {
border-left: 0.25em solid var(--ui-overlay);
padding-left: 1em;
border-top: 0.25em solid var(--ui-overlay);
padding-top: 1em;
&__header {
}
&__title {
font-size: 1rem;
margin: 0;
line-height: 2;
}
&__summary {
grid-area: summary;
}
&__footer {
}
&__date {
margin: 0;
line-height: 1;
&:after {
content: ': '
}
}
}

View file

@ -1,28 +0,0 @@
.feed-entry-in-series {
background: var(--ui-overlay);
padding: 1em;
&__header {}
&__part {
margin: 0;
display: inline-block;
font-variant: small-caps;
}
&__title {
margin: 0;
display: grid;
place-items: start;
margin-block-end: 0.5em;
a {
display: grid;
}
}
&__summary {
font-size: 1rem
}
&__date {
margin: 0;
}
&__readmore {
margin-block-end: 0;
}
}

View file

@ -1,17 +0,0 @@
.feed-entry {
&__header {
}
&__title {
margin-block-start: 0;
}
&__summary {
}
&__footer {
}
&__date {
}
}

View file

@ -1,32 +0,0 @@
.feed-header {
hr {display: none;}
.container {
inline-size: 100%;
}
}
.feed-title {
margin-block-start: 0;
line-height: 1.15;
letter-spacing: -0.022rem;
grid-area: title;
}
.feed-authors-hint {
display: none;
}
.feed-authors {
list-style: none;
}
.feed-author {
margin: 0;
}
.feed-summary {
font-style: italic;
line-height: 1.15;
letter-spacing: -0.022rem;
margin-block-start: 0.5rem;
grid-area: summary;
}
.feed-content {}
.feed-permalink {
.u-url {font-family: monospace;}
}

View file

@ -1,83 +0,0 @@
figure:has(blockquote) {
margin-block: 1rem;
margin-inline: 0;
box-sizing: border-box;
max-width: max-content;
blockquote {
max-inline-size: 100%;
line-height: 1.66;
letter-spacing: -0.022em;
font-size: 1.266rem;
font-family: serif;
margin: 0;
padding: 1rem;
> p:first-child {
margin-block-start: 0;
}
> p:last-child {
margin-block-end: 0;
}
}
figcaption {
font-size: 0.889rem;
}
/* float a lil quotey before the quote */
position: relative;
blockquote:before {
content: '';
position: absolute;
font-size: 3rem;
inset-block-start: -0.5rem;
// inset-inline-start: 0.75rem;
}
blockquote {
padding-block-start: 2em;
}
/* fixes for no-style option */
blockquote {
margin-inline-start: -1rem;
}
&:has(figcaption) blockquote {
padding-block-end: 0rem;
}
/* basic style */
// border-block-start: 1px solid currentColor;
// border-inline-start: 1px solid currentColor;
// figcaption {
// padding-inline: 1rem;
// padding-block-end: 1rem;
// }
/* framing style */
// background: var(--ui-overlay);
// border: 0.5rem solid var(--ui-overlay);
// blockquote:not(:has(div)) {
// background: var(--ui-background);
// }
// figcaption {
// border-block-start: 1px solid var(--ui-overlay);
// background: var(--ui-overlay);
// color: var(--ui-overlay-text);
// padding: 1rem;
// }
}

View file

@ -1,3 +0,0 @@
figure:has(img) {
}

View file

@ -1,7 +0,0 @@
.in-reply-to-prepend {
@include prepend-icon(
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMTAgOVY1bC03IDdsNyA3di00LjFjNSAwIDguNSAxLjYgMTEgNS4xYy0xLTUtNC0xMC0xMS0xMSIvPjwvc3ZnPg==),
50%,
45%
);
}

View file

@ -1,47 +1,74 @@
.quote-block { // structure .quote-block {
padding: 1em;
box-sizing: border-box; box-sizing: border-box;
background: var(--ui-overlay-transparent);
&__header { &__header {
display: grid;
} }
&__attribution { // either an author="" or card="" &__attribution {
margin: 0; margin: 0;
display: inline-flex; display: inline-flex;
} }
&__card { // avatar and display name &__card {
display: inline-grid; display: inline-grid;
place-items: center; place-items: center;
} }
&__author { // markdown text &__author {
display: inline-grid; display: inline-grid;
grid-template-columns: auto 1fr;
place-items: center; place-items: center;
a { a {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
} }
&__postpend { // " wrote:" goes after either card or author &__prepend {
margin-block: 0;
}
&__postpend {
display: inline-grid; display: inline-grid;
align-items: center; align-items: center;
white-space: pre; white-space: pre;
} }
&__prepend { // when there is no attribution, "quote:"
margin-block: 0;
display: inline-grid;
grid-template-columns: auto 1fr;
place-items: center start;
}
&__content { &__content {
blockquote { blockquote {
margin: 0; margin: 0;
> *:first-child { > *:first-child {
margin-block-start: 0; margin-block-start: 0;
} }
> *:last-child { > *:last-child {
margin-block-end: 0; margin-block-end: 0;
} }
} }
position: relative;
// &:before {
// content: '';
// mask: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxLjE5ZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMTY2NCAxNDA4Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTc2OCA4MzJ2Mzg0cTAgODAtNTYgMTM2dC0xMzYgNTZIMTkycS04MCAwLTEzNi01NlQwIDEyMTZWNTEycTAtMTA0IDQwLjUtMTk4LjVUMTUwIDE1MFQzMTMuNSA0MC41VDUxMiAwaDY0cTI2IDAgNDUgMTl0MTkgNDV2MTI4cTAgMjYtMTkgNDV0LTQ1IDE5aC02NHEtMTA2IDAtMTgxIDc1dC03NSAxODF2MzJxMCA0MCAyOCA2OHQ2OCAyOGgyMjRxODAgMCAxMzYgNTZ0NTYgMTM2bTg5NiAwdjM4NHEwIDgwLTU2IDEzNnQtMTM2IDU2aC0zODRxLTgwIDAtMTM2LTU2dC01Ni0xMzZWNTEycTAtMTA0IDQwLjUtMTk4LjVUMTA0NiAxNTB0MTYzLjUtMTA5LjVUMTQwOCAwaDY0cTI2IDAgNDUgMTl0MTkgNDV2MTI4cTAgMjYtMTkgNDV0LTQ1IDE5aC02NHEtMTA2IDAtMTgxIDc1dC03NSAxODF2MzJxMCA0MCAyOCA2OHQ2OCAyOGgyMjRxODAgMCAxMzYgNTZ0NTYgMTM2Ii8+PC9zdmc+);
// background-color: currentColor;
// mask-repeat: no-repeat;
// position: absolute;
// inset-inline-start: -0.5em;
// inset-block-start: -0em;
// display: block;
// inline-size: 100%;
// block-size: 100%;
// pointer-events: none;
// opacity: 0.5;
// }
// &:after {
// content: '';
// background-color: currentColor;
// mask: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxLjE5ZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMTY2NCAxNDA4Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTc2OCAxOTJ2NzA0cTAgMTA0LTQwLjUgMTk4LjVUNjE4IDEyNTh0LTE2My41IDEwOS41VDI1NiAxNDA4aC02NHEtMjYgMC00NS0xOXQtMTktNDV2LTEyOHEwLTI2IDE5LTQ1dDQ1LTE5aDY0cTEwNiAwIDE4MS03NXQ3NS0xODF2LTMycTAtNDAtMjgtNjh0LTY4LTI4SDE5MnEtODAgMC0xMzYtNTZUMCA1NzZWMTkycTAtODAgNTYtMTM2VDE5MiAwaDM4NHE4MCAwIDEzNiA1NnQ1NiAxMzZtODk2IDB2NzA0cTAgMTA0LTQwLjUgMTk4LjVUMTUxNCAxMjU4dC0xNjMuNSAxMDkuNVQxMTUyIDE0MDhoLTY0cS0yNiAwLTQ1LTE5dC0xOS00NXYtMTI4cTAtMjYgMTktNDV0NDUtMTloNjRxMTA2IDAgMTgxLTc1dDc1LTE4MXYtMzJxMC00MC0yOC02OHQtNjgtMjhoLTIyNHEtODAgMC0xMzYtNTZ0LTU2LTEzNlYxOTJxMC04MCA1Ni0xMzZ0MTM2LTU2aDM4NHE4MCAwIDEzNiA1NnQ1NiAxMzYiLz48L3N2Zz4=);
// mask-repeat: no-repeat;
// position: absolute;
// display: block;
// inline-size: 100%;
// block-size: 100%;
// inset-inline-end: 0em;
// inset-block-end: 0em;
// mask-position: bottom right;
// pointer-events: none;
// opacity: 0.5;
// }
} }
&__footer { &__footer {
&:before { &:before {
@ -49,34 +76,3 @@
} }
} }
} }
.quote-block {
&__header, &__content, &__footer {
padding-inline: 1em;
background: var(--ui-overlay-transparent);
}
&__header {
padding-block-start: 1em;
}
&__header:has(&__card) {
padding-block-end: 1em;
}
&__content, &__footer {
padding-block-end: 1em;
}
&__author, &__prepend {
font-weight: bold;
// position: relative;
// &:before {
// content: '';
// display: inline;
// width: 3em;
// height: 3em;
// background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMTIwMCAxMjAwIj48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTYwMCAxMjAwYzMzMS4zNzEgMCA2MDAtMjY4LjYyOSA2MDAtNjAwUzkzMS4zNzEgMCA2MDAgMFMwIDI2OC42MjkgMCA2MDBzMjY4LjYyOSA2MDAgNjAwIDYwMG00NS45MjMtMjgyLjQyMkw2MjAuMTQyIDc5OC44NWM3NS41NDEtMTYuNzIxIDE0NS4wMDUtMzguNDY4IDEzOS4zOC0xMjIuODI1aC04OC43N1YzNjAuMDU3aDI2Ny40MDd2Mjk1LjMxNGMtLjA5NSAyMzQuNjkxLTE3Mi40MDEgMjUzLjc4Ni0yOTIuMjM2IDI2Mi4yMDdtLTM1OC4yMjggMEwyNjEuODQxIDc5OC44NWM3NS41NDEtMTYuNzIxIDE0NS4wMDUtMzguNDY4IDEzOS4zOC0xMjIuODI1aC04OC43N1YzNjAuMDU3aDI2Ny40MDd2Mjk1LjMxNGMtLjA5NCAyMzQuNjkxLTE3Mi4zMjggMjUzLjc4Ni0yOTIuMTYzIDI2Mi4yMDciLz48L3N2Zz4=);
// background-size: 75%;
// background-repeat: no-repeat;
// background-position: center;
// margin-right: 0.5em;
// }
}
}

View file

@ -6,13 +6,12 @@
} }
.series-list { .series-list {
list-style: none; list-style: none;
padding-inline-start: 0em; padding-inline-start: 1em;
.current-post { .current-post {
font-weight: bold; font-weight: bold;
} }
.series-post { .series-post {
margin-block: 0.5em; margin-block: 0.5em;
margin-inline-start: 0;
&__part { &__part {
margin-inline-end: 0.5em; margin-inline-end: 0.5em;
} }

View file

@ -1,31 +0,0 @@
.site-footer {
hr {
display: none;
}
.on-this-site {
h2 {
font-size: 1.383rem;
margin: 0;
}
h3 {
font-size: 1.296rem;
margin: 0;
}
ul {
list-style: none;
margin: 0;
display: flex;
flex-flow: row wrap;
gap: 0em 1em;
}
li {
margin: 0;
}
}
.on-this-site-sections {
}
.on-this-site-taxonomies {
}
}

View file

@ -1,86 +1,12 @@
.site-header { .site-header {
hr {
display: none;
}
.container { .container {
}
.please-wait-warmly {
background: var(--ui-overlay);
padding: 1em;
display: grid;
grid-template-columns: auto 1fr auto;
place-items: center;
gap: 1em;
line-height: 1.15;
letter-spacing: -0.022em;
&:before, &:after {
content: '';
display: inline-block;
width: 3em;
height: 3em;
background-color: hsl(210, 100%, 40%);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJtMTguOSAyMWwtNS40NzUtNS40NzVsMi4xLTIuMUwyMSAxOC45ek01LjEgMjFMMyAxOC45TDkuOSAxMmwtMS43LTEuN2wtLjcuN2wtMS4yNzUtMS4yNzV2Mi4wNWwtLjcuN0wyLjUgOS40NWwuNy0uN2gyLjA1TDQgNy41bDMuNTUtMy41NXEuNS0uNSAxLjA3NS0uNzI1VDkuOCAzdDEuMTc1LjIyNXQxLjA3NS43MjVsLTIuMyAyLjNMMTEgNy41bC0uNy43TDEyIDkuOWwyLjI1LTIuMjVxLS4xLS4yNzUtLjE2Mi0uNTc1dC0uMDYzLS42cTAtMS40NzUgMS4wMTMtMi40ODh0Mi40ODctMS4wMTJxLjM3NSAwIC43MTMuMDc1dC42ODcuMjI1TDE2LjQ1IDUuNzVsMS44IDEuOGwyLjQ3NS0yLjQ3NXEuMTc1LjM1LjIzOC42ODd0LjA2Mi43MTNxMCAxLjQ3NS0xLjAxMiAyLjQ4OHQtMi40ODggMS4wMTJxLS4zIDAtLjYtLjA1dC0uNTc1LS4xNzV6Ii8+PC9zdmc+);
background-size: 75%;
background-repeat: no-repeat;
background-position: center;
border-radius: 100em;
}
&:before {
grid-column: 1;
}
> * {
grid-column: 2;
}
&:after {
grid-column: 3;
}
}
.site-nav {
display: flex;
flex-flow: row wrap;
gap: 0.5em;
} }
.site-masthead { .site-masthead {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
display: inline-grid;
grid-template-columns: auto 1fr;
gap: 0.5em;
}
.site-icon {
block-size: 3rem;
inline-size: 3rem;
border-radius: 100em;
justify-self: center;
}
.site-masthead__text {
display: flex;
flex-flow: column;
} }
.site-title { .site-title {
font-size: 1.5rem;
font-weight: 900;
line-height: 2rem;
display: inline-grid;
}
.site-tagline {
line-height: 1rem;
}
.main-menu {
flex-grow: 1;
margin: 0;
list-style: none;
text-align: end;
&-item {
margin: 0;
height: 100%;
display: inline-grid;
place-items: center;
.menu-link {
display: inline-grid;
padding-inline: 0.5em;
}
}
} }
} }

View file

@ -0,0 +1,10 @@
.syndication-hint {
margin-block-end: 0;
}
.syndication-list {
margin-block-start: 0;
&-item {
margin-block: 0;
.u-syndication {}
}
}

View file

@ -27,30 +27,3 @@
margin-inline-start: 1em; margin-inline-start: 1em;
} }
} }
// the shortcode version can't be overridden for some reason...
#TableOfContents:not(.table-of-contents) {
ul, ol {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin-block: 0.5em;
margin-inline: 0;
line-height: 1.5;
}
a {
display: inline;
}
li > ul, li > ol { /* indent subheadings */
margin-inline-start: 1em;
}
}
// hide toc shortcode if page-wide toc is enabled
*[has-toc] {
#TableOfContents:not(.table-of-contents) {
display: none;
}
}

View file

@ -35,20 +35,14 @@ h5 {counter-reset: h6}
font-size: 1rem; font-size: 1rem;
} }
:is(.table-of-contents, #TableOfContents) :is(ol, ul) { .table-of-contents :is(ol, ul) {
/* /*
each list gets a new counter each list gets a new counter
*/ */
counter-reset: item; counter-reset: item;
margin-inline-start: 0; margin-inline-start: 0;
} }
:is(.table-of-contents, #TableOfContents) :is(ol, ul) :is(ol, ul) { .table-of-contents li:before {
/*
nested lists shouldn't be indented
*/
margin-inline-start: 0;
}
:is(.table-of-contents, #TableOfContents) li:before {
/* /*
the counter is added as a pseudo-element, the counter is added as a pseudo-element,
and nested counters are joined by a dot and nested counters are joined by a dot

View file

@ -7,8 +7,6 @@
content: "] "; content: "] ";
} }
} }
.footnote-backref {
}
.footnotes { .footnotes {
hr { hr {
display: flex; display: flex;
@ -45,10 +43,3 @@
inline-size: calc(100% - 12ch); inline-size: calc(100% - 12ch);
} }
} }
sup[id^="fnref:"] {
display: contents;
a {
margin-inline-end: 0.125em;
margin-inline-start: 0.375em;
}
}

View file

@ -5,9 +5,9 @@ body {
} }
.back-to-top { .back-to-top {
position: absolute;
inset-block-end: 1em; inset-block-end: 1em;
inset-inline-start: 1em; inset-inline-start: -12em;
transition: 0.25s all ease-in; transition: 0.25s all ease-in;
background: var(--ui-overlay); background: var(--ui-overlay);
color: var(--ui-overlay-text) !important; color: var(--ui-overlay-text) !important;
@ -20,7 +20,8 @@ body {
.skip-to-items { .skip-to-items {
position: absolute; position: absolute;
inset-block-start: -10em; inset-block-start: -5em;
inset-inline-start: 1em;
transition: all 0.25s ease-in; transition: all 0.25s ease-in;
background: var(--ui-overlay); background: var(--ui-overlay);
color: var(--ui-overlay-text) !important; color: var(--ui-overlay-text) !important;
@ -31,9 +32,9 @@ body {
} }
} }
.skip-metadata { .skip-syndication {
position: absolute; position: absolute;
inset-block-start: -10em; inset-block-start: -5em;
inset-inline-start: 1em; inset-inline-start: 1em;
transition: 0.25s all ease-in; transition: 0.25s all ease-in;
background: var(--ui-overlay); background: var(--ui-overlay);
@ -44,6 +45,6 @@ body {
inset-block-start: 1em; inset-block-start: 1em;
} }
&:before { &:before {
content: "Skip further metadata"; content: "Skip syndication information";
} }
} }

View file

@ -1,14 +1,24 @@
.rendered-heading { .rendered-heading {
display: grid;
grid-template-columns: 1fr auto;
gap: 0.5em;
&:is(h2) { &:is(h2) {
border-block-end: 1px solid var(--ui-overlay); border-block-end: 1px solid var(--ui-text-muted);
padding-block-end: 1rem; padding-block-end: 1rem;
} }
&__text { &__text {
grid-column: 1;
} }
&__anchor-link { &__anchor-link {
grid-column: 2;
line-height: 1em;
margin-block-start: 0.15em;
display: grid;
place-items: center;
align-self: start;
&:before { &:before {
content: "§ link"; content: "[link]";
display: inline-block;
font-size: 1rem; font-size: 1rem;
} }
} }

View file

@ -1,2 +1,58 @@
.layout-_default-list { .layout-_default-list {
.list-header {
hr {display: none;}
.container {
max-inline-size: 80ch;
margin-inline: auto;
}
}
.list-title {
margin-block-start: 0;
font-size: 2.025rem;
line-height: 1.15;
letter-spacing: -0.022rem;
grid-area: title;
}
.list-author {}
.list-summary {
font-style: italic;
font-size: 1.266rem;
line-height: 1.15;
letter-spacing: -0.022rem;
margin-block-start: 0.5rem;
grid-area: summary;
}
.list-content {}
.list-permalink {
.u-url {font-family: monospace;}
}
.list-alt-formats {
.path {font-family: monospace;}
p {
margin-block-end: 0;
}
.alt-formats-list {
margin-block-start: 0;
&-item {
margin-block: 0;
a {}
}
}
}
.list-pages {
max-inline-size: 80ch;
margin-inline: auto;
.pages-list {
list-style: none;
padding-inline-start: 0;
&-item {
margin-inline-start: 0;
}
}
}
@media (min-width: 400px) {
.container {
padding: 0 2em;
}
}
} }

View file

@ -1,73 +1,198 @@
.layout-_default-single {
.page-header {
hr {display: none;}
.container {
max-inline-size: 80ch;
margin-inline: auto;
}
}
.page-title {
margin-block-start: 0;
font-size: 2.025rem;
line-height: 1.15;
letter-spacing: -0.022rem;
grid-area: title;
}
.page-summary {
font-style: italic;
font-size: 1.266rem;
line-height: 1.15;
letter-spacing: -0.022rem;
margin-block-start: 0.5rem;
grid-area: summary;
}
.page-author {
grid-area: author;
margin-block: 0;
}
.page-date {
grid-area: date;
margin-block-end: 0;
.date {display: inline-block;}
}
.page-inreplyto {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.5em;
align-items: center;
.reply-icon {
background: var(--ui-overlay);
display: inline-block;
inline-size: 1em;
block-size: 1em;
padding: 0.25em;
border-radius: 100em;
}
}
.page-permalink {
margin-block-end: 0;
align-self: end;
.u-url {font-family: monospace;}
}
.page-syndication {
}
.page-series {
hr {display: none;}
// background: var(--ui-overlay);
// color: var(--ui-overlay-text);
.container {
max-inline-size: 80ch;
margin-inline: auto;
}
}
.page-content {
inline-size: 100%;
max-inline-size: 80ch;
margin-inline: auto;
}
.page-footer {
hr {display: none;}
inline-size: 100%;
max-inline-size: 80ch;
margin-inline: auto;
}
.page[has-toc] {
padding-block-end: 4em;
}
.page > .table-of-contents {
display: none;
}
#toc-toggle {
display: none;
&:checked ~ .table-of-contents {
display: block;
position: fixed;
z-index: 10;
inset-block-end: 6em;
block-size: max-content;
inline-size: 80%;
max-inline-size: 20em;
max-block-size: #{m}in(40em, 70vh);
overflow-block: scroll;
inset-inline-end: 1em;
background: var(--ui-overlay);
border-radius: 1em;
@include shadow-low;
padding-inline: 1em;
> .container {
padding: 0;
}
}
}
label[for="toc-toggle"] {
position: fixed;
inset-block-end: 1em;
inset-inline-end: 1em;
z-index: 5;
background: var(--ui-overlay);
padding: 1em;
border-radius: 100em;
inline-size: 6em;
display: flex;
justify-content: center;
@include shadow-low;
}
#toc-toggle ~ label[for="toc-toggle"] {
}
#toc-toggle:checked ~ label[for="toc-toggle"] {
// .page[has-toc] { }
// padding-block-end: 4em; #toc-toggle__label-hide {
// } display: none;
// .page > .table-of-contents { }
// display: none; #toc-toggle:checked ~ #toc-toggle__label-hide {
// } display: flex;
}
// @media (min-width: 400px) { #toc-toggle:checked ~ #toc-toggle__label-show {
// .container { display: none;
// padding: 0 2em; }
// } @media (min-width: 400px) {
// } .container {
// @media (min-width: 60rem) { padding: 0 2em;
// label[for="toc-toggle"] { }
// display: none; }
// } @media (min-width: 60rem) {
// .page[has-toc] { label[for="toc-toggle"] {
// inline-size: 100%; display: none;
// max-inline-size: var(--site-max-width); }
// margin-inline: auto; .container {padding: 0;}
// display: grid; .page[has-toc] {
// grid-template-columns: minmax(37em, 1fr) minmax(17em, 20em); display: grid;
// grid-template-rows: auto auto auto; grid-template-columns: 1fr minmax(37em, 80ch) minmax(17em, 20em) 1fr;
// gap: 2em; grid-template-rows: auto auto auto;
// padding-block-end: unset; gap: 2em;
// .page-header { padding-block-end: unset;
// grid-column: 1 / span 2; .page-header {
// grid-row: 1; grid-column: 1 / span 4;
// } grid-row: 1;
// .table-of-contents { display: grid;
// display: block; grid-template-columns: 1fr minmax(37em, 80ch) minmax(17em, 20em) 1fr;
// grid-column: 2; gap: 2em;
// grid-row: 2; .container {
// position: sticky; max-width: unset;
// inset-block-start: 2em; grid-column: 2 / span 2;
// align-self: start; }
// justify-self: start; }
// max-width: unset; .table-of-contents {
// border-inline-start: thin solid var(--ui-overlay); display: block;
// padding-inline: 2em; grid-column: 3;
// max-height: 90vh; grid-row: 2 / span 2;
// overflow-y: auto; position: sticky;
// scrollbar-color: var(--ui-text) var(--ui-overlay); inset-block-start: 2em;
// &::-webkit-scrollbar-thumb { align-self: start;
// background-color: var(--ui-text) justify-self: start;
// } max-width: unset;
// &::-webkit-scrollbar-track { border-inline-start: thin solid var(--ui-overlay);
// background-color: var(--ui-overlay) padding-inline: 2em;
// } max-height: 90vh;
// } overflow-y: auto;
// .page-content { scrollbar-color: var(--ui-text) var(--ui-overlay);
// grid-column: 1; &::-webkit-scrollbar-thumb {
// grid-row: 2; background-color: var(--ui-text)
// max-width: unset; }
// padding-block-start: 0.5rem; &::-webkit-scrollbar-track {
// padding-block-end: 0; background-color: var(--ui-overlay)
// .toc { }
// display: none; }
// } .page-content {
// } grid-column: 2;
// .page-footer { grid-row: 2;
// grid-column: 1; max-width: unset;
// grid-row: 3; padding-block-start: 0.5rem;
// max-width: unset; padding-block-end: 0;
// #footnotes h2 {margin-block-start: 0;} .toc {
// padding-block: 0; display: none;
// } }
// } }
// } .page-footer {
// } grid-column: 2;
grid-row: 3;
max-width: unset;
#footnotes h2 {margin-block-start: 0;}
padding-block: 0;
}
}
}
}

View file

@ -1,4 +1,4 @@
.feed-permalink { .in-reply-to-prepend {
display: grid; display: grid;
place-items: start start; place-items: start start;
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
@ -10,14 +10,13 @@
content: ''; content: '';
display: inline-block; display: inline-block;
background: var(--ui-overlay); background: var(--ui-overlay);
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNNSAyMXEtLjgyNSAwLTEuNDEyLS41ODdUMyAxOXQuNTg4LTEuNDEyVDUgMTd0MS40MTMuNTg4VDcgMTl0LS41ODcgMS40MTNUNSAyMW0xMiAwcTAtMi45MjUtMS4xLTUuNDYydC0zLTQuNDM4dC00LjQzNy0zVDMgN1Y0cTMuNTUgMCA2LjYyNSAxLjMyNXQ1LjQgMy42NXQzLjY1IDUuNFQyMCAyMXptLTYgMHEwLTEuNjc1LS42MjUtMy4xMTNUOC42NSAxNS4zNXQtMi41MzctMS43MjVUMyAxM3YtM3EyLjMgMCA0LjI4OC44NjN0My40ODcgMi4zNjJ0Mi4zNjMgMy40ODhUMTQgMjF6Ii8+PC9zdmc+); background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNMTAgOVY1bC03IDdsNyA3di00LjFjNSAwIDguNSAxLjYgMTEgNS4xYy0xLTUtNC0xMC0xMS0xMSIvPjwvc3ZnPg==);
width: 1em; width: 1em;
height: 1em; height: 1em;
padding: 0.25em; padding: 0.25em;
border-radius: 100em; border-radius: 100em;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position-x: 60%; background-position: center;
background-position-y: 40%;
margin-inline-end: 0.5em; margin-inline-end: 0.5em;
} }
} }

View file

@ -13,14 +13,12 @@
} }
} }
.section-header {
border-block-end: 1px solid var(--ui-text-muted);
padding-block-end: 0.5em;
}
.section-title { .section-title {
font-size: 2em; font-size: 2em;
border-block-end: 1px solid var(--ui-text-muted);
padding-block-end: 0.5em;
margin-block-start: 0; margin-block-start: 0;
margin-block-end: 0; margin-block-end: 1em;
} }
.subsections-title, .subsections-title,
.subpages-title { .subpages-title {

View file

@ -1,28 +0,0 @@
@mixin prepend-icon($icon, $how_far_right, $how_far_down) {
display: grid;
place-items: start start;
grid-template-columns: auto 1fr;
> * {
place-self: center start;
line-height: 1.5em;
}
&:before, &:after {
content: '';
display: inline-block;
block-size: 1em;
inline-size: 1em;
padding: 0.25em;
border-radius: 100em;
margin-inline-end: 0.5em;
}
&:before {
background: var(--ui-overlay);
}
&:after {
position: absolute;
background: var(--ui-overlay-text);
mask-image: $icon;
mask-repeat: no-repeat;
mask-position: $how_far_right $how_far_down;
}
}

View file

@ -23,14 +23,14 @@ src = "opengraph.jpg"
The FTC is suing AT&T over its mobile data policies, particularly throttling "unlimited" customers. [AT&T filed a motion to dismiss this suit](https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/), saying that since AT&T is a common carrier, they fall under the jurisdiction of the FCC instead. The FTC is suing AT&T over its mobile data policies, particularly throttling "unlimited" customers. [AT&T filed a motion to dismiss this suit](https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/), saying that since AT&T is a common carrier, they fall under the jurisdiction of the FCC instead.
<figure> <figure>
<img src="ftc.jpg" alt="Per an Ars Technica headline, January 8, 2015: AT&T defends unlimited data throttling, says the FTC can't stop it." /> <img src="ftc.jpg" alt="Ars Technica headline, January 8, 2015: AT&T defends unlimited data throttling, says the FTC can't stop it" />
<figcaption>"You have no power here. Only the FCC can stop us."</figcaption> <figcaption>"You have no power here. Only the FCC can stop us."</figcaption>
</figure> </figure>
Except just a few days later, [AT&T tells the FCC](https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/) that mobile data doesn't fall under common carrier rules, and cannot be regulated without Title II. Except just a few days later, [AT&T tells the FCC](https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/) that mobile data doesn't fall under common carrier rules, and cannot be regulated without Title II.
<figure> <figure>
<img src="fcc.jpg" alt="Per an Ars Technica headline, January 9, 2015: AT&T tells FCC it can't treat mobile data as a common carrier service." /> <img src="fcc.jpg" alt="Ars Technica headline, January 9, 2015: AT&T tells FCC it can't treat mobile data as a common carrier service." />
<figcaption>"You can't stop us. You don't have that power."</figcaption> <figcaption>"You can't stop us. You don't have that power."</figcaption>
</figure> </figure>

View file

@ -1,9 +1,9 @@
+++ +++
title = "What makes a unified messaging client perfect?" title = "What makes a unified messaging client perfect?"
summary = "A rant in which I focus on what I like and hate about messaging apps, the characteristics I would implement if I were designing the perfect unified mobile messenger, and which current offerings are the closest to perfect." summary = "A rant in which I focus on what I like and hate about messaging apps, the characteristics I would implement if I were designing the perfect unified mobile messenger, and which current offerings are the closest to perfect."
date = 2014-08-08T12:00:00-05:00 date = 2014-08-08T12:00:00-06:00
tags = ["unified messaging", "communication"] tags = []
streams = [] categories = []
[[params.syndication]] [[params.syndication]]
name = "Medium" name = "Medium"
url = "https://medium.com/trwnh/what-makes-a-unified-messaging-client-perfect-322a83e3aa64" url = "https://medium.com/trwnh/what-makes-a-unified-messaging-client-perfect-322a83e3aa64"

View file

@ -56,7 +56,7 @@ nomadic identity is literally just doing this process yourself beforehand by set
--- ---
i forget who it was that said ["a single timeline is unsustainable" (aaron parecki?)](https://github.com/aaronpk/nautilus#:~:text=a%20single%20timeline%20is%20unsustainable) but i'm feeling more like the real cardinal sin is publishing to a single profile. i don't mind *reading* everything in a single view, although making lists certainly helps. it's the *publishing* that annoys me. i almost *never* want to send a post to *all* of my followers. and this goes doubly for replies. i often want to reply within a specific context and only *optionally* tell my followers about it. i forget who it was that said "a single timeline is unsustainable" (aaron parecki?) but i'm feeling more like the real cardinal sin is publishing to a single profile. i don't mind *reading* everything in a single view, although making lists certainly helps. it's the *publishing* that annoys me. i almost *never* want to send a post to *all* of my followers. and this goes doubly for replies. i often want to reply within a specific context and only *optionally* tell my followers about it.
"one account per feed" is a goddamn travesty. an account should be able to have multiple profiles, and a profile should be able to have multiple feeds, and you should be able to follow individual feeds instead of being forced to follow an entire profile. "one account per feed" is a goddamn travesty. an account should be able to have multiple profiles, and a profile should be able to have multiple feeds, and you should be able to follow individual feeds instead of being forced to follow an entire profile.

View file

@ -1,86 +1,4 @@
+++ +++
title = "trwnh.com" title = "~a"
summary = "trwnh.com is the personal site of a" summary = "i have approximate knowledge of many things. perpetual student. (nb/ace/they)"
+++ +++
<section id="a" class="h-card vcard"
resource="#a"
prefix="
as: https://www.w3.org/ns/activitystreams#
foaf: http://xmlns.com/foaf/0.1/
schema: http://schema.org/
"
typeof="as:Person schema:Person">
## who am i?
hi i'm <span class="p-nickname p-name nickname fn" property="as:name schema:name">a</span>. <span class="p-note note" property="as:summary schema:description">perpetual student. (<span class="p-gender-identity">nb</span>/ace/<span class="p-pronouns">they</span>)</span>
### general stuff
you can probably find me around the web with the username "<span class="p-name p-nickname fn nickname" property="">trwnh</span>". it comes from my fleshform's legal name, "<span class="p-name fn" property="as:name schema:name"><span class="p-given-name given-name" property="schema:givenName">abdullah</span> <span class="p-family-name family-name" property="schema:familyName">tarawneh</span></span>"; just take the vowels out of the family name. 2014 they was so hipster. although nowadays "i" mostly just go by "a". historically i've had a really tough time with identity, so this is the best we're gonna get i guess.
<aside><small>(sidenote: i am apparently not the only person to arrive at these five consonants in a row. in particular, trwnh on twitter is not me; someone claimed my username after i deleted twitter in 2018. not that i really care about twitter anymore. depending on how things go in the near-mid future, everyone else might not care either.)</small></aside>
### concert/music/band stuff
i've used the names "<span class="p-nickname nickname" property="foaf:nick">obvious_humor</span>"/"<span class="p-nickname nickname">obvioushumor</span>" for my vaguely music/band fandom stuff, and "<span class="p-nickname nickname">birdsounds</span>" for more creative stuff like my concert photography. both names are references to lyrics by <a href="https://circasurvive.com">Circa Survive</a>, one of my favorite bands.
<figure>
<blockquote style="position: relative;">
<!-- <div style="background-image: url(https://i.scdn.co/image/ab67616d0000b27331a0cd45d16d3945d33913f9); background-blend-mode: soft-light; background-size: cover; background-position: center; position: absolute; width: 100%; height: 100%; left: 0; top: 0; opacity: 0.5; filter: blur(0.25rem); z-index: -1; background-color: var(--ui-blend);"></div> -->
Make your move, obvious humor<br/>
Desperate and respiratory plight<br/>
Always on, dressed to impress<br/>
I'll be the last one to find out why<br/>
Time takes its toll on us (this changes everything)<br/>
And I'd be a liar if I denied you at all<br/>
Oh, now that I know<br/>
This changes everything<br/>
I've been trading ideas with intriguing men, and I<br/>
I perceive an honest solution to all of your pride<br/>
[...]<br/>
I'm going home, but my own way<br/>
Going home on my own<br/>
I'm going home, but my own way<br/>
Going home on my own
</blockquote>
<figcaption>
<a href="https://circasurvive.bandcamp.com/track/the-great-golden-baby">
Circa Survive, "<cite class="short-work">The Great Golden Baby</cite>" -- Juturna (2005)
</a>
</figcaption>
</figure>
<figure>
<blockquote style="position: relative;">
<!-- <div style="background-image: url(https://upload.wikimedia.org/wikipedia/en/c/c2/Violent_Waves_cover.jpg); background-blend-mode: soft-light; background-size: cover; background-position: center; position: absolute; width: 100%; height: 100%; left: 0; top: 0; opacity: 0.5; filter: blur(0.25rem); z-index: -1; background-color: var(--ui-blend);"></div> -->
And it remains the only meaningful mistake<br/>
But you won't let go, you don't know how to<br/>
And every morning I begin my dreams when I'm awake<br/>
Empty bird sounds are reminders<br/>
You're not awake at all
</blockquote>
<figcaption>
<a href="https://circasurvive.bandcamp.com/track/bird-sounds">
Circa Survive, "<cite class="short-work">Bird Sounds</cite>" -- Violent Waves (2012)
</a>
</figcaption>
</figure>
### gameing
most of my "gamer" stuff is under the name triggerofsol. the name came from boktai; in the first boktai game "boktai: the sun is in your hand", if you 100% s-rank and get all items you get "the highest title of the delegate of Sol the solar will -- Trigger of Sol". idk the boktai games are kinda quirky and left an impact on me during my formative years. vampires, norse mythology, magitek, post-apocalyptic absurdism, lotta good stuff in those games.
<figure>
<blockquote>
<p>"So you're the Trigger of Sol? How embarrassing..."</p>
</blockquote>
<figcaption>Sunflower Girl Zazie, in response to Solar Boy Django losing his Solar Gun "Gun del Sol" at the start of <cite>Boktai 2</cite> and being unable to defeat a low-level skeleton</figcaption>
</figure>
</section>

View file

@ -1,6 +1,3 @@
+++
layout = "raw"
+++
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>

View file

@ -1,3 +0,0 @@
+++
title = "wiki"
+++

View file

@ -1,11 +0,0 @@
## in theory
https://github.com/w3c/activitystreams/issues/179#issuecomment-119305076
> `as:Announce` is intended to provide separation between one particular activity and the act of announcing that activity to the world. For instance, previously in AS1, we used the "post" verb to identify the dual action of creating and publishing an object. In AS2, we could represent the same actions using separate `as:Create` and `as:Announce` actions.
https://github.com/w3c/activitystreams/issues/196#issuecomment-127697366
> The use case for Announce is to make the intent to notify explicit. For instance, a system may keep track of events such as Arrive, but not actually notify anyone that the event occurred. The Announce allows the notification activity to be performed separately from the thing being Announced.
> The semantics of Announce are simply: Call attention to this thing...

View file

@ -1,3 +0,0 @@
+++
summary = "things that need clarification. could be improved by a rewrite."
+++

View file

@ -1,15 +0,0 @@
i personally see attachment as a way to append sidecar things, similar to how in email you would say "i have attached..." or "see attached for..."
i see tag as a way to generically list a bunch of related things, similar to how you might say "see also..."
attachment is "included" in the object, while the tag is not; it is just a "reference". but it's a reference without a relation.
attachment is a kind of "here's some stuff i'm including with my object because you might/probably need to do something with it". in that sense, it's similar to instrument on an Activity, but less specific (and also available to non-Activity objects). you attach something as (fundamentally) "part of" the current object.
tag is a kind of "these things may be considered relevant so i'm "tagging" a reference to them". in that sense, it's similar to context on an Object, but far less specific (and without the purpose or meaning imparted by context). you tag something as (fundamentally) "related to" the current object.
things that (are intended to) go in attachment are usually some kind of media, but there's no universal processing rules for what to do when you encounter something with an attachment. i think hubzilla used to treat attachment as "show this thing below the content" at some point? so before FEP-e232 they would just put a Note in attachment. this is kind of like attaching an email as a file to some other email. note that this isn't the same semantically as "quoting", but it relies on display-specific implementation logic to serve a similar purpose.
things that (are intended to) go in tag are usually some kind of taxonomy. there's no universal processing rules here either, but the expectation is that you can use them taxonomically to link to other related objects. for example, i might tag an Image with a Person, as a way of saying that the Person is related to the Image. i might filter some set of objects for all objects that include that have a tag of that Person.
see also [tag-for-actual-taxonomy]({{< relref "tag-for-actual-taxonomy" >}})

View file

@ -1 +0,0 @@
random thought: one of the things that AS1 had that got dropped in AS2 is the difference between "Post" and "Create". i'm thinking something similar could be used to avoid triggering the side effects of Create

View file

@ -1,16 +0,0 @@
+++
title = "Site design and metamodel"
summary = "Decisions I've made while building this website."
updated = 2024-11-16
toc = true
+++
## Distinction between "personal website" and "person"
Early in the development cycle of this website, I initially made no real distinction between myself and my site. For most intents and purposes, I *was* trwnh.com -- and with that, certain design decisions fell into place:
### Why I removed the site header, and why I later added it back.
I wanted no site header or site footer at first. This was partly due to not knowing what to put in there (making them be empty and therefore unnecessary), and partly due to wanting the focus to be entirely on the content itself, which was the main subject of the page.
My thinking around this changed when I started to toy around with and consider the possibility that, even though this is a personal site, I might want to identify or refer to the site separately from myself. In some ways, this makes the site less "personal", or at least, it feels that way. It feels like drawing that distinction makes the website feel more "generic", like it could be repurposed for something else that wasn't me or about me, and it would mostly continue to work just fine.

View file

@ -1,651 +0,0 @@
+++
title = "Sample of HTML elements"
summary = "Use this page to test out CSS styling."
toc = true
+++
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
## Inline elements
![](https://plus.unsplash.com/premium_photo-1729704233180-96d843bba002?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D)
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
This is *emphasized*, and this is **strong**. This is both ***emphasized and strong***.
Goldmark extras: ~~del~~ ++ins++ ==mark== Some~sub~ Some^super^ ==x~i~^n^==
And again with HTML: <del>Deleted</del><ins>Inserted</ins> text. This is <mark>highlighted</mark> text. x<sub>i</sub><sup>n</sup> is the ith element of x, raised to the nth power. Or I suppose <var>x</var> should be a variable, like <var>x</var><sub>i</sub><sup>n</sup> -- or is that <var>x<sub>i</sub></var><sup>n</sup>, because <var>x<sub>i</sub></var> is a variable? Or is the whole thing a variable, like <var>x<sub>i</sub><sup>n</sup></var>? Or is each individual element a variable, like <var>x</var><sub><var>i</var></sub><sup><var>n</var></sup> perhaps? Perhaps there are no wrong answers here...
The volume of a box is <var>l</var> × <var>w</var> × <var>h</var>, where <var>l</var> represents the length, <var>w</var> the width and <var>h</var> the height of the box.
<abbr title="HyperText Markup Language">HTML</abbr> (HyperText Markup Language) and <abbr>CSS</abbr> (Cascading Style Sheets)
<dfn><abbr title="HyperText Markup Language">HTML</abbr></dfn> is a markup language used to create the semantics and structure of a web page.
A <dfn>specification</dfn> (<abbr>spec</abbr>) is a document that outlines in detail how a technology is intended to function.
Press <kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd> to open the menu.
Press <kbd><kbd>CTRL</kbd> + <kbd>ALT</kbd> + <kbd>Delete</kbd></kbd> to open the menu.
You may see sample output from a computer program telling you <samp>Please do not restart your computer...</samp>
<p>
When the process is complete, the utility will output the text
<samp>Scan complete. Found <em>N</em> results.</samp> You can then proceed to
the next step.
</p>
I am going to <b>bring attention to</b> this bit of <i>idiomatic text</i> using some archaic yet repurposed tags. This is an <u>unarticulated annotation</u>, to be used to markup anything that is annotated without further explanation, like a <u title="spelling">speling</u> mistake.
<i>Homo sapiens</i> is the scientific name for human beings. <s>This text is no longer relevant, but it is not being semantically deleted.</s>
According to <cite>A Hitchhiker's Guide to the Galaxy</cite>, I have some data. <q>The ultimate answer to life, the universe, and everything is <data value=42>fourty-two</data>.</q> This work was published on <time datetime="1979-10-12">October 12, 1979</time>.
Are you ready for some ruby elements? <ruby> 明日 <rp>(</rp><rt>Ashita</rt><rp>)</rp> </ruby> is one word. <ruby>
<rp>(</rp><rt>Kan</rt><rp>)</rp><rp>(</rp><rt>ji</rt><rp>)</rp>
</ruby> is another word.
A few more esoteric ones, like "small print", which is basically either legalese or an inline equivalent to `<aside>` sectioning. <small>WARNING: The following is a fan-based parody of a fan-based parody. All properties are properties of their owner. Please support my official release from prison.</small> So yeah, buy now, buy early, buy today! <small>I am not responsible for anything that happens after this point, and I am not your mother.</small>
You may<br />
create a bunch of<br />
line breaks,<br />
but<br />
the real magic is in creating word breaks. For example, the unbroken word <dfn>pneumonoultramicroscopicsilicovolcanoconiosis</dfn> can be broken up like pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis. Depending on where pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis occurs, you can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis in multiple different spots. You can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis after the "pneumono", or you can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis after the "ultra", or you can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis after the "microscopic", or you can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis after the "silico", or you can break up the word pneumono<wbr />ultra<wbr />microscopic<wbr />silico<wbr />volcano<wbr />coniosis after the "volcano". How's <span id="test">ses&shy;qui&shy;pe&shy;dal&shy;ian&shy;ism</span>? Compare to <span id="test2">ses<wbr />qui<wbr />pe<wbr />dal<wbr />ian<wbr />ism</span>
### are we math yet?
<p>
The infinite sum
<math style="math-style: normal">
<mrow>
<munderover>
<mo></mo>
<mrow>
<mi>n</mi>
<mo>=</mo>
<mn>1</mn>
</mrow>
<mrow>
<mo>+</mo>
<mn></mn>
</mrow>
</munderover>
<mfrac>
<mn>1</mn>
<msup>
<mi>n</mi>
<mn>2</mn>
</msup>
</mfrac>
</mrow>
</math>
is equal to the real number
<math style="math-style: normal">
<mfrac>
<msup>
<mi>π</mi>
<mn>2</mn>
</msup>
<mn>6</mn>
</mfrac>
</math>.
</p>
## Block elements
### holy shit it's block-level math
<math display="block">
<mrow>
<mi>x</mi>
<mo>=</mo>
<mfrac>
<mrow>
<mrow>
<mo></mo>
<mi>b</mi>
</mrow>
<mo>±</mo>
<msqrt>
<mrow>
<msup>
<mi>b</mi>
<mn>2</mn>
</msup>
<mo></mo>
<mrow>
<mn>4</mn>
<mo></mo>
<mi>a</mi>
<mo></mo>
<mi>c</mi>
</mrow>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>2</mn>
<mo></mo>
<mi>a</mi>
</mrow>
</mfrac>
</mrow>
</math>
### Preformatted text block
Sample code function:
<pre>
<code>
function NavigatorExample() {
var txt;
txt = "Browser CodeName: " + navigator.appCodeName + "; ";
txt+= "Browser Name: " + navigator.appName + "; ";
txt+= "Browser Version: " + navigator.appVersion + "; ";
txt+= "Cookies Enabled: " + navigator.cookieEnabled + "; ";
txt+= "Platform: " + navigator.platform + "; ";
txt+= "User-agent header: " + navigator.userAgent + "; ";
console.log("NavigatorExample", txt);
}
</code>
</pre>
Sample terminal output:
<pre>
<samp><span class="prompt">a@trwnh.com:~$</span> <kbd>md5 -s "Hello world"</kbd>
MD5 ("Hello world") = 3e25960a79dbc69b674cd4ec67a72c62
<span class="prompt">a@trwnh.com:~$</span> <span class="cursor"></span></samp></pre>
### hr separator
---
<hr />
### Blockquotes
<blockquote>
This is a blockquote without any block elements inside it.
</blockquote>
<blockquote>
<p>This is an uncited block quote.</p>
</blockquote>
<blockquote cite="https://www.lipsum.com/">
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.</p>
</blockquote>
### Figures
<figure>
<img src="https://plus.unsplash.com/premium_photo-1729704233180-96d843bba002?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</figure>
<figure>
<img src="https://plus.unsplash.com/premium_photo-1729704233180-96d843bba002?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
<figcaption>A figure that is captioned</figcaption>
</figure>
<figure>
<figcaption>Get browser details using <code>navigator</code>.</figcaption>
<pre>
function NavigatorExample() {
var txt;
txt = "Browser CodeName: " + navigator.appCodeName + "; ";
txt+= "Browser Name: " + navigator.appName + "; ";
txt+= "Browser Version: " + navigator.appVersion + "; ";
txt+= "Cookies Enabled: " + navigator.cookieEnabled + "; ";
txt+= "Platform: " + navigator.platform + "; ";
txt+= "User-agent header: " + navigator.userAgent + "; ";
console.log("NavigatorExample", txt);
}
</pre>
</figure>
<figure>
<figcaption><b>Edsger Dijkstra:</b></figcaption>
<blockquote>
If debugging is the process of removing software bugs, then programming must
be the process of putting them in.
</blockquote>
</figure>
<figure>
<p>
Bid me discourse, I will enchant thine ear, Or like a fairy trip upon the
green, Or, like a nymph, with long dishevelled hair, Dance on the sands, and
yet no footing seen: Love is a spirit all compact of fire, Not gross to
sink, but light, and will aspire.
</p>
<figcaption><cite>Venus and Adonis</cite>, by William Shakespeare</figcaption>
</figure>
<figure>
<figcaption>Listen to the T-Rex:</figcaption>
<audio controls src="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3">
<p>This is fallback for browsers that don't support the audio tag. <a href="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3">Download</a></p>
</audio>
</figure>
### Tables
TODO: probably more variety here...
- html tables.
- a table shortcode?
- tables with captions.
- colgroup and col to highlight column groups
- table styling? especially styling per-table
| Subject | Predicate | Object |
| - | - | - |
| `<alice>` | `<name>` | "Alice" |
| `<bob>` | `<name>` | "Bob" |
| `<alice>` | `<knows>` | `<bob>` |
| This | is | a | super | wide | table | that | will | certainly | stretch | outside | the | boundaries | of | the | content |
| - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
| - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
<table>
<caption>
Superheros and sidekicks
</caption>
<colgroup>
<col />
<col span="2" class="batman" />
<col span="2" class="flash" />
</colgroup>
<tr>
<td></td>
<th scope="col">Batman</th>
<th scope="col">Robin</th>
<th scope="col">The Flash</th>
<th scope="col">Kid Flash</th>
</tr>
<tr>
<th scope="row">Skill</th>
<td>Smarts, strong</td>
<td>Dex, acrobat</td>
<td>Super speed</td>
<td>Super speed</td>
</tr>
<style>
.batman {
background-color: #272902;
}
.flash {
background-color: #331824;
}
</style>
</table>
<table>
<caption>
Personal weekly activities
</caption>
<colgroup span="5" class="weekdays"></colgroup>
<colgroup span="2" class="weekend"></colgroup>
<tr>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
<th>Sun</th>
</tr>
<tr>
<td>Clean room</td>
<td>Football training</td>
<td>Dance Course</td>
<td>History Class</td>
<td>Buy drinks</td>
<td>Study hour</td>
<td>Free time</td>
</tr>
<tr>
<td>Yoga</td>
<td>Chess Club</td>
<td>Meet friends</td>
<td>Gymnastics</td>
<td>Birthday party</td>
<td>Fishing trip</td>
<td>Free time</td>
</tr>
<style>
.weekdays {
background-color: #2729f2;
}
.weekend {
background-color: #333384;
}
</style>
</table>
### Ordered list
1. First item
2. Second item
3. Third item
<!---->
1. First item
1. Sub-item 1.1
2. Sub-item 1.2
3. Sub-item 1.3
2. Second item
3. Third item
### Unordered list
- List item
- Another item
- Yet another item
<!---->
- List item
- Sub-item
- Sub-sub-item
- Another sub-item
- Another sub-sub-item
- Sub-sub-sub-item?
- 4 levels deep
- 5 deep
- 6 deep
- 7 deep
- 4 deep again
- 5 deep
- Another item
- Yet another item
<ul>
<li>
<p>A list item with a paragraph inside it.</p>
</li>
<li>
<img src="https://plus.unsplash.com/premium_photo-1729704233180-96d843bba002?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
</li>
<li>
<figure>
<img src="https://plus.unsplash.com/premium_photo-1729704233180-96d843bba002?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" />
<figcaption>A figure that is captioned</figcaption>
</figure>
</li>
</ul>
menu is ul but semantically for buttons? interactive items?
<menu>
<li><button>Do something</button></li>
<li><button>Do something else</button></li>
</menu>
### Definition list
Term
: Definition
Term 2
: Definition 2
<!---->
New term
: Definition 1
New term 2
: Definition 2
### Image area maps
<map name="infographic">
<area
shape="poly"
coords="129,0,260,95,129,138"
href="https://developer.mozilla.org/docs/Web/HTTP"
target="_blank"
alt="HTTP" />
<area
shape="poly"
coords="260,96,209,249,130,138"
href="https://developer.mozilla.org/docs/Web/HTML"
target="_blank"
alt="HTML" />
<area
shape="poly"
coords="209,249,49,249,130,139"
href="https://developer.mozilla.org/docs/Web/JavaScript"
target="_blank"
alt="JavaScript" />
<area
shape="poly"
coords="48,249,0,96,129,138"
href="https://developer.mozilla.org/docs/Web/API"
target="_blank"
alt="Web APIs" />
<area
shape="poly"
coords="0,95,128,0,128,137"
href="https://developer.mozilla.org/docs/Web/CSS"
target="_blank"
alt="CSS" />
</map>
<img usemap="#infographic" src="https://interactive-examples.mdn.mozilla.net/media/examples/mdn-info.png" alt="MDN infographic" width=260 height=249 />
### Audio and video and picture
<audio controls loop>
<source src="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3" type="audio/mp3" />
<p>This is fallback for browsers that don't support the audio tag. <a href="https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3">Download</a></p>
</audio>
<video crossorigin controls src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/friday.mp4">
<track default kind="captions" label="Closed Captions" srclang="en" src="https://interactive-examples.mdn.mozilla.net/media/examples/friday.vtt" />
Download the
<a href="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/friday.mp4">MP4</a>
video, and
<a href="https://interactive-examples.mdn.mozilla.net/media/examples/friday.vtt">subtitles</a>.
</video>
<picture>
<source srcset="https://interactive-examples.mdn.mozilla.net/media/cc0-images/surfer-240-200.jpg" media="(orientation: portrait)" />
<img src="https://interactive-examples.mdn.mozilla.net/media/cc0-images/painted-hand-298-332.jpg" alt="" />
</picture>
<object type="application/pdf" data="https://interactive-examples.mdn.mozilla.net/media/examples/In-CC0.pdf" width="100%" height="800"></object>
<object type="image/avif" data="https://media.wafrn.net/1730151075339_e8cefd934f27a072176300c8391669d81fb9e171.avif">
this is a fallback
</object>
## Components
### Admonitions
>[!tip]
> This is a basic `tip`, `hint`, `note`, `info`.
>[!suggestion]
> This is a basic `recommended`, `recommendation`, `good`, `suggestion`, `suggested`, `success`.
>[!warning]
> This is a basic `warning`, `caution`, `alert`, `notice`.
>[!danger]
> This is a basic `danger`, `important`, `fail`, `failure`.
### Quote blocks
> Default quote with no extra attributes
> Quote with no author/card, but with a cite
{cite="https://example.com"}
> Quote with author as plain text
{author="Someone"}
> Quote with author as plain text, plus a cite
{author="Someone" cite="https://example.com"}
> Quote with author who is linked
{author="[Someone with a link](https://example.com)"}
> Quote with author who is linked, as well as a cite
{author="[Someone with a link](https://example.com)" cite="https://example.com"}
> Quote with h-card
{card="trwnh.com/a"}
> Quote with h-card and a cite
{card="trwnh.com/a" cite="https://example.com"}
>> This is a nested quote.
>
> This is some other text.
>> This is a nested quote.
> {card="trwnh.com/a"}
>
> This is some other text.
{card="trwnh.com/a"}
>> This is a nested quote.
> {cite="https://example.com"}
>
> This is some other text.
{cite="https://example.com"}
>> This is a nested quote.
> {card="trwnh.com/a" cite="https://example.com"}
>
> This is some other text.
{card="trwnh.com/a" cite="https://example.com"}
>> Something that was said...
> {card="trwnh.com/a" cite="https://example.com"}
>
> My first response.
>
>> Something else that was said...
> {card="trwnh.com/a" cite="https://example.com"}
>
> My second response.
{card="trwnh.com/a" cite="https://example.com"}
### Code blocks
```
# basic code block, no attributes
for thing in group:
do_something()
```
```diff
# code block with lang=diff
for thing in group:
- do_something()
+ do_something_else()
```
```py
# code block with lang=py
for thing in group:
do_something()
```
```py{hl_lines=3}
# code block with lang=py and hl_lines=3
for thing in group:
do_something()
```
```py{hl_lines=3,lineNos=false}
# code block with lang=py and hl_lines=3 and lineNos=false
for thing in group:
do_something()
```
```py{hl_lines=3,anchorLineNos=true}
# code block with lang=py and hl_lines=3 and lineNos=false
for thing in group:
do_something()
```
```py{hl_lines=3,anchorLineNos=true}
# code block with lang=py and hl_lines=3 and lineNos=false
for thing in group:
do_something()
```
```py{hl_lines=3,anchorLineNos=true,lineNoStart=9998}
# code block starting at line 9998
for thing in group:
do_something()
```
```py{hl_lines=3,lineNoStart=9998}
# code block starting at line 9998
for thing in group:
do_something()
```
```py{hl_lines=3,lineNoStart=9998}
# code block starting at line 9998
for thing in group:
do_something()
```
```py{hl_lines=3,lineNoStart=9998,title="A code block with a title"}
# code block with a title
for thing in group:
do_something()
```
```py{hl_lines=3,lineNoStart=9998,caption="A code block with a caption"}
# code block with a caption
for thing in group:
do_something()
```
```py{hl_lines=3,lineNoStart=9998,title="codeblock.py",caption="A code block with a caption"}
# code block with a title and a caption
for thing in group:
do_something()
```
## Footnotes
I am going to add a footnote here[^1] where I will go off on a long tangent later.
[^1]: Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.

View file

@ -4,8 +4,6 @@ name = "~a | monologues"
summary = "assorted musings. mostly a compilation of times i replied to myself on social media or in chat. what you see here is minimally curated and lightly formatted. it might disappear at any time or be upgraded to a proper or formal writing at some point." summary = "assorted musings. mostly a compilation of times i replied to myself on social media or in chat. what you see here is minimally curated and lightly formatted. it might disappear at any time or be upgraded to a proper or formal writing at some point."
[pagination] [pagination]
pagerSize = 100 pagerSize = 100
[params]
compactEntries = true
+++ +++
[[rejected outtakes]](misc) [[rejected outtakes]](misc)

View file

@ -1,92 +0,0 @@
+++
title = "microsyntaxes in fedi were probably a mistake"
summary = "i am... *moderately worried* that we might be doubling down on a fundamentally flawed abstraction here [...] in effect, by specifying fallback behavior and representations, we are actually **making it harder for your average consumer to understand** [...] a whole swathe of other functionality that relies on them processing the `content` in such a way that transforms it."
date = 2024-11-08T10:48:00-06:00
streams = []
tags = []
source = "https://github.com/mastodon/draft-feps/pull/3#discussion_r1834717926"
+++
> the `name` and federated `content` do not match
they actually do, but only in the plaintextified version of `content`! this is more accurately a mismatch between the fact that posts are routinely authored as plaintext and then federated as html.
there is also a deeper "root cause" to this issue: microsyntaxes in activitypub are usually treated as optional. that is to say, instead of requiring something like this:
```yaml
content: "Thanks @sally for your hard work! :thanks: #givingthanks RE: https://post.example"
mediaType: text/plain
tag:
- type: Mention
name: "@sally"
href: https://sally.example
- type: Image
name: ":thanks:"
url:
- width: 20
height: 20
mediaType: image/png
href: https://emojo.example/thanks
- type: Hashtag
name: "#givingthanks"
href: https://social.example/tagged/givingthanks
- type: Link
name: "RE: https://post.example"
href: https://post.example
preview:
- type: Note
attributedTo: https://sally.example
content: "I did a bunch of hard work"
```
we instead end up in a situation where the microsyntax is "preprocessed" for you and the output is directly html instead. which creates issues for finding where in the html `content` the microsyntax occurred. the closest thing to an algorithm we have currently is to find a child html `element` whose `element.innerText` (in a javascript sense) exactly matches the `tag[].name`.
there might be a need to separately specify better handling of microsyntaxes similarly to bluesky's "rich text facets" or other similar systems.
> ActivityStreams talks about microsyntaxes a bit, but in a non-normative section, and failing to define a formal link between the tag metadata and the pre-processed microsyntax: https://www.w3.org/TR/activitystreams-vocabulary/#microsyntaxes
right, so i'm wondering if `tag` is actually appropriate here or if maybe it deserves its own property or if something else entirely.
the problem we have currently is that things like `Mention` tags don't actually make sense in most cases. i know that the concept of "mentions" is used heavily in the UX of something like mastodon, but on a semantic level the more appropriate properties are the addressing properties like `to` or `cc` or so on. this is even brought up in the non-normative section about ["mentions, tags, and other microsyntaxes"](https://www.w3.org/TR/activitystreams-vocabulary/#microsyntaxes), which concludes that consumers SHOULD NOT be required to parse microsyntaxes, but instead publishers SHOULD use semantic terms like those provided by AS2-Vocab... which makes it more confusing that AS2-Vocab then went on to define `Mention` as representing the microsyntax of an `@` mention.
basically, the assumed "correct" thing is not to do addressing by `tag[*].type == Mention`, but to do addressing by `to`/`cc`/`audience`/`bto`/`bcc`. the use of a `tag` of type `Mention` is described as "indicate a mention without an associated notification".
put another way, the semantic purpose of `tag` is NOT to markup microsyntaxes, it is to markup associative references. imagine for example tagging a Person directly, as example 105 does:
```json
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Image",
"summary": "Picture of Sally",
"url": "http://example.org/sally.jpg",
"tag": [
{
"type": "Person",
"id": "http://sally.example.org",
"name": "Sally"
}
]
}
```
in plain english, "this Image is related to Sally". we might get clever and parse `Sally` in the `summary` and inject a hyperlink to `https://sally.example.org`, but this is not required.
---
for the issue of "quote tags" where the "quote" is part of the content, we are not really saying that "this Note is related to this Link", but rather we are saying "this facet of `content` (as indicated by `name`?) should be marked up as a `Link` with a `preview`." specifically, the `preview` might be an Object that is a "post". but this is only one way of doing it.
i am... *moderately worried* that we might be doubling down on a fundamentally flawed abstraction here.
i think we should give more consideration to what the expected behavior of producers and consumers might be here. for example, might we say that producers are expected to mark up a "quote" in such a way that the consumer doesn't have to parse the `content` for microsyntaxes? because i think we might be overloading `tag` in a way that is detrimental to future uses that are more "proper" to what it's supposed to mean.
to give a more practical example, for the consumer, the "quote" feature breaks down into one of two cases:
1. they don't understand quotes. in this case, the "quote" might be included by the producer as part of the content so that they aren't forced to understand it.
2. they understand quotes. in this case, the "quote" might still be included as part of the `content` so that consumers that don't understand "quotes" can still see the "quote".
do you see the problem here? in effect, by specifying fallback behavior and representations, we are actually **making it harder for your average consumer to understand** not just "quotes", but also a whole swathe of other functionality that relies on them processing the `content` in such a way that transforms it. a similar problem occurred for a while many years ago in mastodon, when a link to every `attachment` was included in the `content` of a status. rather than implementing consumer logic to strip these links, mastodon instead stopped producing these links. the end result is that anyone who sees a status only by its `content` *has no idea that the status includes media*. perhaps over time this expectation may have shifted such that `attachment` is seen as a "baseline" property; instead of something that simply enriches the `content`, it is now *required in order to understand the content*.
when applied to the "quote" feature, this means that at an ecosystem level, we either have to decide that quotes are part of the content (and should be possibly removed by consumers somehow), or that quotes are *not* part of the content but are still *required in order to understand the content*.
are we prepared to say one way or another whether the processing of "quotes" should be required or not, in the same way that in ~2018 we made that same decision for `attachment`?

View file

@ -1,89 +0,0 @@
+++
title = "json-ld makes it easy to do bad json"
summary = "the real problem is not the ld, it's that it allows you to keep doing bad json. the context mapping is a wonderful tool for indirection, which is good when you want to take ambiguous structure and make it unambiguous [...] but if you're working at the plain-json level then you are at the mercy of whoever designed the json api/structure/schema in the first place. you have to deal with all the ambiguity inherent to the bad json [...] to be consistent with the *compacted* form means that you have to be as indirect as the context mapping tells you to be"
date = 2024-10-13T13:20:00-05:00
source = "https://mastodon.social/@trwnh/113301496365344814"
+++
thinkin bout the jsonld hate again and i think the real problem is not the ld, it's that it allows you to keep doing bad json. the context mapping is a wonderful tool for indirection, which is good when you want to take ambiguous structure and make it unambiguous (through expansion), but if you're working at the plain-json level then you are at the mercy of whoever designed the json api/structure/schema in the first place. you have to deal with all the ambiguity inherent to the bad json.
in a sense, the as2 requirement to be consistent with the *compacted* form means that you have to be as indirect as the context mapping tells you to be. if the w3.org/ns/activitystreams context did some wack shit then you would have to unwrap all the resulting wack behavior. and type:id is the biggest kludge ever because it makes it ambiguous whether anything is a literal value or an actual object.
here's an example from an earlier post
> compare this
>
> ```
> {
> "to": [{"id": "some-actor"}]
> }
> ```
>
> with this
>
> ```
> {
> "to": "some-actor"
> }
> ```
>
> yes the second one looks cleaner but it actually is very messy when you try to do anything with it
>
> if you were required to do the first one, then implementations would have a LOT less to worry about
{cite="https://mastodon.social/@trwnh/113266766055627285" card="mastodon.social/@trwnh"}
simply *dropping* type:id from the context mapping of every single term would have changed the compacted output to use a json hashmap every time you refer to an object, and each object can have a single key `id` in it at minimum.
i bet if this was the case, then the complaints about "jsonld" would *sharply* drop. it would just be a fancy namespace at that point, and people don't complain about aliasing/includes/imports as much.
this is something that can't be fixed about as2 as a profile or media format unless you make a new context document and force people to be consistent with that new context mapping, which would have to limit itself to simple term definitions. (none of the fancy stuff.)
the thing is, humans can deal with ambiguity. machines can't. as2 is overly optimized for human readability, to the point that it creates a lot of ambiguity for machines.
the proper use of context mappings is to transform ambiguous json into unambiguous json(ld). not to force everyone to use ambiguous json in exactly the same way that you use it.
this is also made worse by the fact that the as2 vocab is sometimes defined in a way that is so "bad" that it is *impossible* to express using a single term! case in point: take as:closed. it can be both an object (Object or Link), or a literal (datetime or boolean). how do you model that cleanly?
if you were doing this "right", then you would end up needing a second term `closedBy` to represent cases where as:closed refers to an object, instead of `closed` which has a literal value.
a similar thing happens with as:items. we actually need two terms: `items` which refers to the default container of an unordered set, and `orderedItems` which tacks on container:list to the context mapping's term definition.
this is not the fault of jsonld, it's the fault of overly broad schemas/"bad json".
a little more explicitness upfront would have saved everyone a lot of trouble, and it's sad that as2 got finalized in the state that it did. the vocabulary is generally decent in the concepts and building blocks it identifies, but they just don't connect in the way that you'd expect or even understand.
---
> [...]
i made a shitpost that as2 should have used hal+json instead https://mastodon.social/@trwnh/113266744971942546
honestly we don't need to use hal+json specifically but we should definitely take inspiration from it in what we want our compacted jsonld to look like.
[...]
you could simplify a lot of this with jsonld as well, for example eliding out the set/list stuff. but the more "context" you add/require, the harder it is to undo that. i'm pretty sure that when people say they hate jsonld what they mean is that they hate that this inherent complexity is hidden from you by the context mapping
there's probably a midway point or compromise
[...]
the problem is that AS2 is just weird in so many ways due to that underspecification and also what i refer to as the connections between building blocks -- things like the Invite activity being a special case where the as:object is not the actual object of that activity, you're not inviting a party, you're inviting *someone* to that party. that's just bad semantics at the modeling level.
[...]
all json really needs is a way to signal that something is an object and not a literal. we have a way of doing that: make the object into a json object! this means actor:someone is not enough anymore, you need actor:{id:someone}
similarly the way you signal that something can have multiple values is not to just say "everything can have multiple values", it's to make it an array. but then you need to specify whether the array is ordered or unordered. which you can do with objects
so instead of
{"items": "something"}
you would need to be explicit and say
{"items": {
"list": [{"id": "something"}]
}}
this differs very slightly from json-ld expanded form in that a) you can use simple term definitions in an optional context mapping to provide simple namespacing lookup, and b) your entrypoint is not always an implicit graph, it's allowed to be an object, and if you want to refer to a graph then you can use a graph object instead

View file

@ -1,36 +0,0 @@
+++
title = "revisiting micropub"
summary = "i can't make any sense of the micropub data model. the more i think about it the more confused i get. now, the api itself seems to do a lot of things generally well, but big-picture idk [...] there seem to be a lot of behaviors that the server is possibly or expected to carry out, but it's never entirely clear what those behaviors are because the underlying microformats are so freeform [...] it's unclear what value implementing my own micropub server is supposed to get me"
date = 2024-10-18T09:32:00-05:00
source = "https://mastodon.social/@trwnh/113331744143221451"
+++
i always kinda vaguely thought micropub was okay but rereading it just now with far more experience than the last time i read it (years ago), i am realizing it's actually quite hairy and it's not immediately clear what the data model even is supposed to be. there's a reliance on microformats of course but it seems to be almost linked-data-lite with a resource management aspect because the examples have you create an h-card for a venue, then doing a checkin referencing that location... what???
at least in activitypub the data model generally assumes that your AP server will be carrying out side effects for certain activities, so you can do CRUD and collection management using the AS2 vocab, and it's mostly coherent from a surface level. it's not terribly hard to imagine a CMS built on top of AP. but i can't make any sense of the micropub data model. the more i think about it the more confused i get. now, the api itself seems to do a lot of things generally well, but big-picture idk...
my main criticism here is that there seem to be a lot of behaviors that the server is possibly or expected to carry out, but it's never entirely clear what those behaviors are because the underlying microformats are so freeform and there's a lot of stuff that's auxiliary -- syndicating to other platforms, for example. i'm not personally interested in much if any of that stuff, so it's unclear what value implementing my own micropub server is supposed to get me.
so i'm wondering if the course of action might be to just develop an api that's even more basic (inb4 nanopub)
of course before i actually get to that point, i need to figure out a data model that makes sense first. it's possible that whatever i come up with can be mostly transformed or serialized into other existing data models but so far i'm not finding any that feel appropriate -- AS2 could be contorted to fit but i don't think it actually works well for this bc it overly relies on types...
...and one of the things that i've come to realize while working on my website recently is that types actually do not matter, for the most part. the data model of the web is resource-based, but in most cases you don't actually care what type those resources are. it probably matters more if you're trying to build an overlay network or linked data set, but if you're not doing that, then it's kinda pointless to spend so much time boxing yourself into that additional data model.
---
> micropub _is_ ok
i get html and microformats but i see no value in micropub for my use case, because it's bringing in a lot of assumptions that i don't feel like adopting. this post was made because i initially thought micropub could fit my use case when i was looking at it years ago. in rereading the micropub spec, i must conclude that it does not actually fit my use case.
this doesn't actually have anything to do with LD or AP, which also do not fit my use case. at least, not this one.
---
> yeah micropub and microsub are both super-lacking in a lot of ways
i really want to collect a list of user stories and use cases that have been neglected by existing protocols and find a way to address them in whatever i end up doing.
i'm not opposed to urls as references but i think that you ideally want relative urls, and then you resolve them against a variable base (which gets you portability and location-independence as long as your data model is locked in and doesn't change)
part of why i'm engaging in this renewed push of updating my website is because i want to hammer out the data model that makes sense for me, and hopefully it makes sense for other people too.

View file

@ -1,18 +0,0 @@
+++
title = "\"social media\" is a failed model invented by capitalists"
summary = "here on the World Wide Web you have two threats: capitalist enclosure, and toxic community [...] at least you have the self-determination to make your own community with your valued friends if the current one gets too bad. with the former, you have no escape"
date = 2023-03-10T07:20:00-06:00
source = "https://mastodon.social/@trwnh/109999188302928268"
+++
forums weren't that bad actually
here on the World Wide Web you have two threats: capitalist enclosure, and toxic community. and honestly the latter is probably less bad, because at least you have the self-determination to make your own community with your valued friends if the current one gets too bad. with the former, you have no escape.
in short, "social media" is a failed model invented by capitalists. what we need is a "social web". focus on people, not "content".
want to entertain yourself? that's fine, there can be media hubs and curators for that. but your communications and your media consumption should be separate.
> [...]
not really, current fedi is broken in a similar way to social media, because it tries to copy social media instead of leaning into the Web. instead of focusing on the purity of the model and data, then having different presentations on top of that. look how we don't even have a proper "thread" or "conversation". we place undue importance on replies for grouping. instead of treating the reply tree as a structure *within* the conversation, we treat it *as* the conversation. and more

View file

@ -1,8 +0,0 @@
+++
title = "the future of the social web is in storage and identity protocols"
summary = "the current situation of everyone fighting over the ghost of activitypub is a convenient distraction to stop anyone from declaring themselves the canonical interpretation. it also presents an opportunity to regroup and refocus on the social web"
date = 2024-10-19T11:10:03-05:00
source = "private"
+++
actually the thing i worry about is that i distinctly see a future in which it stops being the Mastodon Protocol and instead becomes the Threads Protocol. all it would really take is for meta to launch a developer portal for federating with threads, and for them to formally define all this implicit undefined stuff. the current situation of everyone fighting over the ghost of activitypub is a convenient distraction to stop anyone from declaring themselves the canonical interpretation. it also presents an opportunity to regroup and refocus on the social web, if the necessary work is done to bridge the gaps and fill in the holes. whether that ends up being activitypub or something on top of activitypub or something else entirely is kinda irrelevant. i think the key going forward is actually gonna be the storage and identity protocols, not the transport protocol (we have more than enough of those). something like solid or atproto is needed to provide "personal data storage", and something like did `service` is needed to provide a stable base against which you can resolve relative references. this should mitigate the problems of link rot and services going down -- not completely solve them, but make them a lot less likely to happen.

View file

@ -1,10 +0,0 @@
+++
title = "everyone wants to be the new twitter"
summary = "twitter never had that many users in the grand scheme of things, but it was a cultural mainstay to the point that everyone and their cat is trying to recreate it [...] let it die."
date = 2024-10-19T08:55:39-05:00
source = "private"
+++
its honestly weird when you stop and think about how twitter never had that many users in the grand scheme of things, but it was a cultural mainstay to the point that everyone and their cat is trying to recreate it
let it die. the moment is over. we gotta move past it.

View file

@ -1,52 +0,0 @@
+++
title = "date ranges on contact info (address, phone, email)"
summary = "Addresses are not owned. They are leased [...] People move houses all the time, so their address changes. In the same way, people change digital addresses like phone numbers [...] \"X was using this phone number between 2011-01-01 and 2015-06-01.\" For messaging archives you can now reliably dereference a phone number to a contact name, without having to worry about who has the phone number *now*."
date = 2019-08-20T02:09:00-05:00
source = "https://mastodon.social/@trwnh/102648053339382526"
tags = ["wrong"]
+++
why has no one thought of attaching a date range to when certain contacts held certain phone numbers or email addresses or physical addresses or whatever
it would solve the issue of reconstructing history
wanna have a thread of all your messages with a person whomst has changed phone numbers but you know someone else has the number now? well Now You Can
---
> checking my understanding is of your post: so uh like I can say "Eugen rochko had (420)666-6969 between x and u dates" so I would remember that if I went back to look?
yeah exactly
on a ui level it would allow a user to say "show me all the messages i've ever had with eugen", but combining threads from different phone numbers
or if applied to the fediverse "show me my mentions from this contact, bearing in mind that they migrated 20 times"
it's more useful with a nickname/petname/addressbook system that largely hasn't been implemented yet bc everyone just uses webfinger for user@domain addressing that they expect never to change
put another way: what if instead of owning an address, you leased that address, and your lease had a start date and potential end date
tenancy is not and should not be treated as permanent
---
## refinement
Addresses are not owned. They are leased.
Compare to physical street addresses. People move houses all the time, so their address changes. In the same way, people change digital addresses like phone numbers. This makes it hell to reconstruct a conversation later based on your current contact listings. Do you keep that old number attached to that contact forever, even if you know they're not using it anymore? That's awkward because you wouldnt message that number anymore, it'd be a stranger.
The real issue is reuse of addresses. We don't really have to worry about date ranges of email addresses because email providers generally don't reassign usernames. But it might be nice to still be able to mark an email as implicitly "inactive". So what do we do about all this?
Assign date ranges to contact addressing methods.
Start date, end date. "X was using this phone number between 2011-01-01 and 2015-06-01." For messaging archives you can now reliably dereference a phone number to a contact name, without having to worry about who has the phone number *now*.
- Assign date ranges of when an address was used
- Mark certain method(s) as primary
- Display name is better than forcing people to use first/last. Allow optional markup of name parts, but name should be single text entry field and separate from other metadata like given/family/middle/etc.
- Arbitrary key-value pairs for misc info that isn't necessarily structured. But structure helps wherever possible.
Prior art:
- vcard. UGH.
- Monica. a great improvement but still kinda limited

View file

@ -1,20 +0,0 @@
+++
title = "\"incognito mode\" or \"private browsing\" should be called \"amnesia mode\""
summary = "it's always been a misnomer. it's not private. it's not hiding your identity or fingerprint in any way. it's just a session without any of your usual cookies, and it clears itself after closing."
date = 2024-01-16T15:24:00-06:00
source = "https://mastodon.social/@trwnh/111767734805138077"
+++
why's it called "incognito mode" or "private browsing mode"? it's always been a misnomer. it's not private. it's not hiding your identity or fingerprint in any way. it's just a session without any of your usual cookies, and it clears itself after closing. it should be called "amnesia mode".
i guess i'd also accept "ephemeral session" but that probably sounds too technical for most normal people
---
> I think it made more sense when people shared computers and accounts. It's private from the other people who use that same browser. But yeah, it could use a better name. I think 'amnesia' and 'ephemeral' both capture the idea that records will be forgotten; bu they don't quite capture that it also doesn't use existing cookies etc. (Particularly for ephemeral.) Even 'incognito' does better there, because it doesn't use your current login cookies for websites. So I'm not sure.
i see "amnesia" in the sense of like... you start with no memory, and then at the end, you forget everything that happened. kind of like that movie, Memento
---
> at some point we were working on a browser [...] which referred to "incognito" tabs as "amnesiac"

View file

@ -2,7 +2,6 @@
title = "fully responsive web design" title = "fully responsive web design"
summary = "my pipe dream is to redesign my website to be fully responsive -- not across mere pixel widths, but by aspect ratio and overall size" summary = "my pipe dream is to redesign my website to be fully responsive -- not across mere pixel widths, but by aspect ratio and overall size"
date = 2018-04-22T10:42:00-05:00 date = 2018-04-22T10:42:00-05:00
updated = 2024-11-11T05:58:10-06:00
source = "https://mastodon.social/@trwnh/99903847448978099" source = "https://mastodon.social/@trwnh/99903847448978099"
+++ +++
@ -11,35 +10,3 @@ my pipe dream is to redesign my website to be fully responsive -- not across mer
does anyone consider what their website looks like when it's fullscreened across one of those samsung 3840x1080 monitors? probably not, and why would you? does anyone consider what their website looks like when it's fullscreened across one of those samsung 3840x1080 monitors? probably not, and why would you?
but i do but i do
---
## refinement
let's say the base case is when the aspect ratio is square
you can set width-based breakpoints as usual, but logically extend your approach to multiple different media query sets
- one height-based breakpoint for when there is less than some minimum required height? ("too small" mode)
- one for when there is less than a square aspect ratio (landscape mode)
- one for everything beyond that (portrait mode)
so you might have for example assuming liberal use of breakpoints:
- min-width 320, min-height 320
- min-width 400, min-height 320
- min-width 400, min-height 400
- min-width 480, min-height 320
- min-width 480, min-height 480
- min-width 600, min-height 320
- min-width 600, min-height 600
- min-width 800
- min-width 960
- min-width 1150
- min-width 1320
- min-width 1560
- ...
notice we stopped taking height into account past a certain point, because we are assuming the page content is flowing vertically and will overflow the viewport in the vertical direction. if we were designing a site that flowed horizontally then we would continue in the height axis (and perhaps cap off the width queries at some point instead).
for more extreme widths it becomes more interesting to consider those horizontal flows although it should be recognized that this is niche.

View file

@ -1,19 +0,0 @@
+++
title = "thinkin bout dropping RSS (and some thoughts about jf2)"
summary = "there are a lot of versions of RSS and they all suck [...] most feed readers anyone cares about seem to accept Atom equally as well [...] tangentially, jf2 seems like a decent format as any, but one thing i find confusing is [...]"
date = 2024-10-18T09:32:00-05:00
source = "https://mastodon.social/@trwnh/113331744143221451"
+++
thinkin bout dropping RSS from my website's alternate output formats
- there are a lot of versions of RSS and they all suck (and none of them are even a Real Standard, there isn't even a consistent media type, it could be served as xml, rss+xml, or even rdf+xml???)
- most feed readers anyone cares about seem to accept Atom equally as well as RSS variants (so why bother with RSS at all? it's basically a legacy format)
so basically i'm looking at currently outputting atom, jsonfeed, jf2, as2?
i'm honestly not sure about outputting jf2 either, since you can just parse the html... but it would be an ahead-of-time optimization and it's basically "free" because i'm using a static generator (hugo specfically). so i don't have a reason to remove it, do i?
tangentially, jf2 seems like a decent format as any, but one thing i find confusing is that it seems to be linked-data-lite with the way that references work... which is actually pretty awkward because you can never tell when some property's value is a string literal or if it's a reference. and then the spec tells you that you SHOULD be fetching that data and parsing it from the authoritative origin anyway? so what's the point of including references if you're just encouraged to ignore them???
interestingly there is some attempt at jsonld compat with jf2, there's a context document at https://www.w3.org/ns/jf2 which you can implicitly inject into any jf2 document. which you can't easily identify because there is no jf2 media type btw, only jf2feed+json which is a restricted profile for feeds only. also the context document is wrong -- none of the properties which can be or are "references" are identified as such with type:id. so it's at best a "starting point" and nothing more.

View file

@ -1,9 +0,0 @@
+++
title = "what if joey won battle city"
summary = "i feel like joey should have won against marik, taken ra [...] gets ambushed [...] yugi challenges marik, which plays out exactly as it did in canon [...] yugi now has all three god cards, faces off against joey in the finals [...] yugi offers joey his pick out of the god cards, and joey picks red-eyes instead. kaiba ends up the saltiest mfer ever [...]"
date = 2024-10-26T11:56:00-05:00
source = "https://www.youtube.com/watch?v=k_HxTHXpXAY&lc=UgwC33VLY9kScSHAdkt4AaABAg"
tags = ["yugioh", "joey wheeler"]
+++
i feel like joey should have won against marik, taken ra, then during the yugi vs kaiba semifinals a weakened joey gets ambushed by marik who just straight-up steals ra back. yugi wins vs kaiba only to find out joey is in the hospital, so the finals can't proceed. in the meantime yugi challenges marik, which plays out exactly as it did in canon. yugi now has all three god cards, faces off against joey in the finals, and loses. yugi offers joey his pick out of the god cards and joey picks red-eyes instead. kaiba ends up the saltiest mfer ever because his tournament ended in his rival getting all the god cards, and the title of "king of games" goes to joey of all people. he flies away to build kaibaland, everyone else goes off to millennium world

View file

@ -1,5 +1,5 @@
+++ +++
date = 2024-10-18T02:34:41-05:00 date = 2024-10-17T08:49:47-05:00
[[params.inReplyTo]] [[params.inReplyTo]]
name = "The Challenge of ActivityPub Data Portability" name = "The Challenge of ActivityPub Data Portability"
url = "https://bengo.is/blogging/2024-10-03-the-challenge-of-activitypub-data-portability/" url = "https://bengo.is/blogging/2024-10-03-the-challenge-of-activitypub-data-portability/"

View file

@ -1,111 +0,0 @@
+++
date = 2024-10-23T23:01:00-05:00
tags = []
draft = true
summary = "> JsonLD is not the optimal solution to ActivityPubs problem [...] Why? Because parsing it is hell.\n\nThe problem here is with AS2, not with JSON-LD. The majority of AS2 properties can be a string, a reference, an object, or an array of any of these. AS2 forces everyone to handle every possibility, instead of being explicit and serializing objects as actual JSON objects. Consider the following scenario where you want to display someone's avatar -- a pretty basic task. Here's what you have to deal with:"
[[params.inReplyTo]]
name = "post #131 of \"Desired changes for a future revision of ActivityPub and ActivityStreams\""
url = "https://socialhub.activitypub.rocks/t/desired-changes-for-a-future-revision-of-activitypub-and-activitystreams/4534/131"
[[params.syndication]]
name = "Original post on SocialHub"
url = "https://socialhub.activitypub.rocks/t/desired-changes-for-a-future-revision-of-activitypub-and-activitystreams/4534/133"
+++
> JsonLD is not the optimal solution to ActivityPubs problem [...] Why? Because parsing it is hell.
{cite="https://socialhub.activitypub.rocks/t/desired-changes-for-a-future-revision-of-activitypub-and-activitystreams/4534/131" card="socialhub.activitypub.rocks/Laxystem"}
The problem here is with AS2, not with JSON-LD. The majority of AS2 properties can be a string, a reference, an object, or an array of any of these. AS2 forces everyone to handle every possibility, instead of being explicit and serializing objects as actual JSON objects.
Consider the following scenario where you want to display someone's avatar -- a pretty basic task. Here's what you have to deal with:
```json
{
"icon": "https://something.example/icon" // is this a Link node, or an Image object, or a URI to the resource?
}
```
```json
{
"icon": {
"type": "Link",
"name": "Avatar"
"href": "https://something.example/icon",
"width": 400,
"height": 400,
"mediaType": "image/png"
}
}
```
```json
{
"icon": [
{
"type": "Link",
"name": "Avatar, full size"
"href": "https://something.example/icon",
"width": 400,
"height": 400,
"mediaType": "image/png"
},
{
"type": "Link",
"name": "Avatar, profile size"
"href": "https://something.example/icon?resize=120",
"width": 120,
"height": 120,
"mediaType": "image/png"
},
{
"type": "Link",
"name": "Avatar, timeline size"
"href": "https://something.example/icon?resize=48",
"width": 48,
"height": 48,
"mediaType": "image/png"
}
]
}
```
```json
{
"icon": {
"id": "https://something.example/icon"
"type": "Image",
"name": "My avatar",
"summary": "Image description goes here",
"url": "https://something.example/icon.png"
}
}
```
```json
{
"icon": {
"id": "https://something.example/icon"
"type": "Image",
"name": "My avatar",
"summary": "Image description goes here",
"url": [
"https://something.example/some-uri", // is this a direct resource URI or a Link?
{
"href": "https://something.example/icon.jpg" // no mediaType, so you have to guess based on file extension
},
{
"href": "https://something.example/icon.png" // no mediaType, so you have to guess based on file extension
},
{
"href": "https://something.example/icon.avif" // no mediaType, so you have to guess based on file extension
},
{
"href": "https://something.example/icon.jxl" // no mediaType, so you have to guess based on file extension
}
]
}
}
```
All of these are generally valid by AS2. So the consumer now has to be able to parse multiple representations instead of just one. And even after parsing, you still have to figure out what to do with the information that you parsed!
If anything, JSON-LD can *simplify* things, by allowing you to effectively "normalize" the data beforehand, so that you have less possibilities to deal with. Everything becomes an array of JSON objects. You still have problems because of AS2 (for example, knowing if any given `@id` is a resource, Link, or Image), but you eliminate a lot of potential cases. Your logic doesn't need to handle bare strings or singular objects anymore; you only need to loop over the array and pluck whichever JSON object matches your criteria. Which, again, your complications beyond this point are the fault of AS2.

View file

@ -1,6 +1,6 @@
+++ +++
date = 2024-09-30T17:41:00-05:00 date = 2024-09-30T17:41:00-05:00
tags = [] tags = ["capitalism", "social", "capital", "mastodon", "utility", "analysis"]
draft = true draft = true
[[params.inReplyTo]] [[params.inReplyTo]]
name = "post #36 of \"SocialWebFoundation - what do people think?\"" name = "post #36 of \"SocialWebFoundation - what do people think?\""

View file

@ -1,4 +0,0 @@
+++
title = "series"
summary = "content pages that follow up on each other"
+++

View file

@ -1,39 +0,0 @@
{{ $data := .Site.Data.tags }}
{{ $ctx := . }}
{{ range $data }}
{{ $id := .id }}
{{ $title := .name }}
{{ $summary := .summary }}
{{ $aliases := .alsoKnownAs }}
{{ $page := dict
"title" $title
"summary" $summary
"params" (dict "tag_aliases" $aliases "tag_name" $id)
"path" .id
"kind" "term"
}}
{{/* TODO: kind=term causes a "term is empty" error */}}
{{ $.Store.Set (urlize $id) true }}{{/* mark this tag as already having a page */}}
{{ $.AddPage $page }}
{{ range $aliases }}
{{ $conflict := $.Store.Get . }}
{{ if $conflict }}
{{/* we don't want to call AddPage for a tag that already has a page */}}
{{ else }}
{{ $page := dict
"params" (dict "tag_canonical" $id "tag_name" .)
"path" .
"kind" "term"
}}
{{/* TODO: kind=term causes a "term is empty" error */}}
{{ $.Store.Set (urlize .) true }}{{/* mark this tag as already having a page */}}
{{ $.AddPage $page }}
{{ end }}
{{ end }}
{{ end }}

View file

@ -1,4 +0,0 @@
+++
title = "tags"
summary = "terms and keywords that are related to a page."
+++

View file

@ -0,0 +1,5 @@
+++
layout = "page"
+++
test

View file

@ -2,7 +2,6 @@
title = "Disambiguating various interpretations of a \"quote\" feature" title = "Disambiguating various interpretations of a \"quote\" feature"
summary = "Broadly speaking, there are [...] Quote replies (reply with adjacent contextual preview) [...] Quote tags (rich quotes embedded in content) [...] [and] Quote boosts (reshare with comment)" summary = "Broadly speaking, there are [...] Quote replies (reply with adjacent contextual preview) [...] Quote tags (rich quotes embedded in content) [...] [and] Quote boosts (reshare with comment)"
date = 2023-07-18T21:17:00-05:00 date = 2023-07-18T21:17:00-05:00
updated = 2024-11-13T11:27:12-06:00
toc = true toc = true
autonumbering = false autonumbering = false
streams = ["all"] streams = ["all"]
@ -43,19 +42,6 @@ It is possible to add `content` to your `Announce` activity; a generic presentat
[^announce-as-forwarding]: Some software implementations *do not* use `Announce` as a reshare activity, and instead use it for other purposes outside of a publishing context, such as wrapping and forwarding someone else's activity. The intended specified mechanism for doing this is inbox forwarding. [^announce-as-forwarding]: Some software implementations *do not* use `Announce` as a reshare activity, and instead use it for other purposes outside of a publishing context, such as wrapping and forwarding someone else's activity. The intended specified mechanism for doing this is inbox forwarding.
### The quote activity
Instead of an `Announce` with `content`, we can define a new Activity type `Quote` that can be used similarly, but has different semantics. Whereas an `Announce` is defined like so:
> Indicates that the `actor` is calling the `target` 's attention the `object`.
So instead of "calling for attention", the `Quote` activity would instead be defined semantically as:
Quote
: Indicates that the `actor` is quoting the `object` verbatim in its entirety.
The "quote activity" might also instead be named something else to avoid potential conflicts with other shorthand terms. Something like `Cite` could also work. Alternatively, other disambiguated senses of the word may be represented in the noun form as a `Quotation` or `Citation`.
## Comparison and analysis ## Comparison and analysis
### Quote replies (reply with adjacent contextual preview) ### Quote replies (reply with adjacent contextual preview)
@ -73,9 +59,3 @@ The "quote activity" might also instead be named something else to avoid potenti
- (~) Might be semantically appropriate, if the "sharing" aspect of the "quote post" is what you intended. - (~) Might be semantically appropriate, if the "sharing" aspect of the "quote post" is what you intended.
- (-) Falls back to a normal boost, without displaying the added content at all. - (-) Falls back to a normal boost, without displaying the added content at all.
### Quote activities (new extension Activity type)
- (~) No fallback. This could be either good or bad, depending on if you want a fallback or if you want the semantics to be respected.
- (+) With the existence of a `quotes` collection (even if the `items` might be private), we can use its IRI as the `target` of an `Add` which acts as a stamp of inclusion in a parallel way to how one might signal an Add into the `likes`, `shares`, `replies`, `context`, etc collections.
- (+) In theory supports one or multiple `object` references, but even if you limit the cardinality to 1, this at least "frees up" the `inReplyTo` property for cases where you might reply to one post while quoting a different post. It also remains possible to `Quote` an `object` while also declaring that your `Quote` is `inReplyTo` the same `object`.

View file

@ -1,16 +0,0 @@
+++
title = "how to handle networking in a social web"
summary = "you should be able to make a new social app without starting over on network effects. the key is in consenting to people messaging you, but separately being able to signal interest in specific subsets of messages."
date = 2024-11-10T03:56:12-06:00
toc = true
draft = true
streams = ["all"]
tags = []
+++
## problem statement
You want to manage your network of contacts separately from all other apps -- this is the "bsky problem" where the data for apps is tied up in records which are stored in repos that are validated against schemas and namespaced to lexicons.
When starting a new networked app (anything where messages or publishing might be involved), you want to be able to bootstrap off of your existing network of contacts and followers.

View file

@ -1,42 +0,0 @@
+++
title = "social web foundations: defining posts, contexts, and audiences"
summary = "looking at prior art and synthesizing a data model that makes sense as the foundation for a protocol"
date = 2024-10-20T03:58:55-05:00
toc = true
autonumbering = false
draft = true
streams = ["all"]
tags = ["activitypub", "activity streams", "as2", "fedi", "indieweb", "social web", "social networking", "social media", "social communication", "social"]
+++
## Things vs References
At the base of the data model, you either have a *thing*, or a *reference to a thing*. The distinction between the thing vs. the reference is important because the reference might have its own properties, separately from the thing.
### Prior art
#### Microformats 2
Initially, the Indieweb and Microformats community started out with a much narrower scope for their building blocks:
- <cite class="h-cite">[h-entry](http://microformats.org/wiki/h-entry)</cite> started out as a way to represent "datestamped or episodic content", but has since evolved to represent any content piece in general.
- <cite class="h-cite">[h-cite](http://microformats.org/wiki/h-cite)</cite> started out as a way to represent "citations or references to online publications", but has since evolved to represent any reference in general.
#### Activity Streams 2.0
<cite class="h-cite">[Activity Streams 2.0](https://www.w3.org/TR/activitystreams-core/)</cite> defines two base classes from which everything else inherits:
- Object, which represents any object ("thing")
- Link, which represents a web link ("reference")
## Posts
A "post" is a *thing* that generally has content.
## Context and Audience
For any "post", the most important bit about it (after the content itself) is to be able to understand why the post was made, and who it was made for.
## Stores and Transports
## Identity

View file

@ -0,0 +1,13 @@
data flows into the application from "stores", and flows out via "transports"
### stores
IMAP
AP C2S GET?
XMPP C2S???
### transports
SMTP
XMPP
AP C2S POST?

View file

@ -0,0 +1,7 @@
+++
title = "Search within /wiki"
type = "_default"
layout = "search"
_build.list="never"
slug = "search"
+++

Some files were not shown because too many files have changed in this diff Show more