urls: remove the hyperlink dependency
- ID
ba24dec- date
2026-03-31 18:36:21+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
644f388- message
urls: remove the `hyperlink` dependency- changed files
9 files, 961 additions, 49 deletions
Changed files
CHANGELOG.md (3842) → CHANGELOG.md (3899)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8a2d42..a76306d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG
+## v31 - 2026-03-31
+
+Remove the `hyperlink` dependency.
+
## v30 - 2026-03-30
Add a `chives.fetch` package which has some helper functions for making HTTP requests using the standard library.
dev_requirements.txt (2306) → dev_requirements.txt (2282)
diff --git a/dev_requirements.txt b/dev_requirements.txt
index a377f40..1c06d56 100644
--- a/dev_requirements.txt
+++ b/dev_requirements.txt
@@ -1,8 +1,8 @@
# This file was autogenerated by uv via the following command:
-# uv pip compile dev_requirements.in --output-file=dev_requirements.txt --exclude-newer=P7D
+# uv pip compile dev_requirements.in --output-file=dev_requirements.txt --exclude-newer=P7D --exclude-newer-package alexwlchan-chives=false
-e file:.
# via -r dev_requirements.in
-build==1.4.2
+build==1.4.0
# via -r dev_requirements.in
certifi==2026.2.25
# via
@@ -16,14 +16,10 @@ docutils==0.22.4
# via readme-renderer
greenlet==3.3.2
# via playwright
-hyperlink==21.0.0
- # via alexwlchan-chives
id==1.6.1
# via twine
idna==3.11
- # via
- # hyperlink
- # requests
+ # via requests
iniconfig==2.3.0
# via pytest
jaraco-classes==3.4.0
@@ -48,7 +44,7 @@ mypy==1.19.1
# via -r dev_requirements.in
mypy-extensions==1.1.0
# via mypy
-nh3==0.3.4
+nh3==0.3.3
# via readme-renderer
packaging==26.0
# via
@@ -67,7 +63,7 @@ pluggy==1.6.0
# pytest-cov
pyee==13.0.1
# via playwright
-pygments==2.20.0
+pygments==2.19.2
# via
# pytest
# readme-renderer
@@ -89,7 +85,7 @@ rapidfuzz==3.14.3
# via alexwlchan-chives
readme-renderer==44.0
# via twine
-requests==2.33.0
+requests==2.32.5
# via
# requests-toolbelt
# twine
@@ -99,7 +95,7 @@ rfc3986==2.0.0
# via twine
rich==14.3.3
# via twine
-ruff==0.15.8
+ruff==0.15.7
# via -r dev_requirements.in
smartypants==2.0.2
# via alexwlchan-chives
pyproject.toml (1340) → pyproject.toml (1327)
diff --git a/pyproject.toml b/pyproject.toml
index d5c3a39..6a9a9b6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,7 +28,7 @@ fetch = ["certifi"]
media = ["Pillow"]
static_site_tests = ["playwright", "pytest", "rapidfuzz"]
text = ["smartypants"]
-urls = ["certifi", "hyperlink"]
+urls = ["certifi"]
[project.urls]
"Homepage" = "https://github.com/alexwlchan/chives"
src/chives/__init__.py (391) → src/chives/__init__.py (391)
diff --git a/src/chives/__init__.py b/src/chives/__init__.py
index d69250d..0271393 100644
--- a/src/chives/__init__.py
+++ b/src/chives/__init__.py
@@ -11,4 +11,4 @@ I share across multiple sites.
"""
-__version__ = "30"
+__version__ = "31"
src/chives/fetch.py (2487) → src/chives/fetch.py (3260)
diff --git a/src/chives/fetch.py b/src/chives/fetch.py
index 1091898..6ea6613 100644
--- a/src/chives/fetch.py
+++ b/src/chives/fetch.py
@@ -34,6 +34,7 @@ def _build_request(
def fetch_url(
url: str,
+ *,
params: dict[str, str] | None = None,
headers: dict[str, str] | None = None,
) -> bytes:
@@ -81,6 +82,7 @@ def _guess_image_format(content_type: str | None) -> ImageFormat:
def fetch_image(
url: str,
+ *,
params: dict[str, str] | None = None,
headers: dict[str, str] | None = None,
) -> tuple[bytes, ImageFormat]:
@@ -101,3 +103,29 @@ def fetch_image(
assert isinstance(img_data, bytes), type(img_data)
return img_data, img_format
+
+
+# def download_image(
+# url: str,
+# out_prefix: Path,
+# *,
+# params: dict[str, str] | None = None,
+# headers: dict[str, str] | None = None,
+# ) -> Path:
+# """
+# Download an image from the given URL to the target path, and return
+# the path of the downloaded file.
+#
+# Add the appropriate file extension, based on the image's Content-Type.
+#
+# Throws a FileExistsError if you try to overwrite an existing file.
+# """
+# im_data, im_format = fetch_image(url, params=params, headers=headers)
+# out_path = out_prefix.with_suffix("." + im_format)
+#
+# out_path.parent.mkdir(exist_ok=True, parents=True)
+#
+# with open(out_path, "xb") as out_file:
+# out_file.write(im_data)
+#
+# return out_path
src/chives/urls.py (3908) → src/chives/urls.py (4636)
diff --git a/src/chives/urls.py b/src/chives/urls.py
index ecdec90..917a2a1 100644
--- a/src/chives/urls.py
+++ b/src/chives/urls.py
@@ -7,10 +7,13 @@ import ssl
from ssl import SSLCertVerificationError
import urllib.error
from urllib.error import HTTPError
+from urllib.parse import SplitResult, parse_qs, urlencode, urlsplit
import urllib.request
import certifi
+from chives.fetch import fetch_url
+
__all__ = [
"clean_youtube_url",
@@ -26,16 +29,24 @@ def clean_youtube_url(url: str) -> str:
Remove any query parameters from a YouTube URL that I don't
want to include.
"""
- import hyperlink
+ u = urlsplit(url)
- u = hyperlink.parse(url)
+ query = parse_qs(u.query)
+ for param in ("list", "index", "start_radio", "t"):
+ try:
+ del query[param]
+ except KeyError:
+ pass
- u = u.remove("list")
- u = u.remove("index")
- u = u.remove("start_radio")
- u = u.remove("t")
+ updated_u = SplitResult(
+ scheme=u.scheme,
+ netloc=u.netloc,
+ path=u.path,
+ query=urlencode(query, doseq=True),
+ fragment=u.fragment,
+ )
- return str(u)
+ return updated_u.geturl()
def is_mastodon_host(hostname: str) -> bool:
@@ -108,26 +119,35 @@ def parse_mastodon_post_url(url: str) -> tuple[str, str, str]:
Parse a Mastodon post URL into its component parts:
server, account, post ID.
"""
- import hyperlink
-
- u = hyperlink.parse(url)
+ u = urlsplit(url)
+ path = u.path.strip("/").split("/")
- if len(u.path) != 2:
+ if len(path) != 2:
raise ValueError("Cannot parse Mastodon URL!")
- if not u.path[0].startswith("@"):
+ if not path[0].startswith("@"):
raise ValueError("Cannot find `acct` in Mastodon URL!")
- if not re.fullmatch(r"^[0-9]+$", u.path[1]):
+ if not re.fullmatch(r"^[0-9]+$", path[1]):
raise ValueError("Mastodon post ID is not numeric!")
- if u.host == "social.alexwlchan.net":
- _, acct, server = u.path[0].split("@")
- else:
- server = u.host
- acct = u.path[0].replace("@", "")
+ if u.netloc == "social.alexwlchan.net" and path[0] != "@alex":
+ _, acct, server = path[0].split("@")
+ html = fetch_url(url).decode("utf8")
+ if m := re.search(
+ f'<a rel="noopener" href="https://{server}/@{acct}/(?P<post_id>[0-9]+)">',
+ html,
+ ):
+ post_id = m.group("post_id")
+ return server, acct, post_id
+ else:
+ raise ValueError("Cannot parse Mastodon URL!")
- return server, acct, u.path[1]
+ server = u.netloc
+ acct = path[0].replace("@", "")
+ post_id = path[1]
+
+ return server, acct, post_id
def parse_tumblr_post_url(url: str) -> tuple[str, str]:
@@ -136,17 +156,17 @@ def parse_tumblr_post_url(url: str) -> tuple[str, str]:
Returns a tuple (blog_identifier, post ID).
"""
- import hyperlink
-
- u = hyperlink.parse(url)
+ u = urlsplit(url)
+ path = u.path.strip("/").split("/")
- if u.host == "www.tumblr.com":
- return u.path[0], u.path[1]
+ if u.netloc == "www.tumblr.com" and len(path) >= 2:
+ return path[0], path[1]
- if u.host.endswith(".tumblr.com") and len(u.path) >= 3 and u.path[0] == "post":
- return u.host.replace(".tumblr.com", ""), u.path[1]
+ elif u.netloc.endswith(".tumblr.com") and len(path) >= 3 and path[0] == "post":
+ return u.netloc.replace(".tumblr.com", ""), path[1]
- raise ValueError("Cannot parse Tumblr URL!") # pragma: no cover
+ else:
+ raise ValueError("Cannot parse Tumblr URL!")
def is_url_safe(path: str | Path) -> bool:
tests/fixtures/cassettes/test_parse_mastodon_post_url[alexwlchan_redirect].yml (0) → tests/fixtures/cassettes/test_parse_mastodon_post_url[alexwlchan_redirect].yml (19330)
diff --git a/tests/fixtures/cassettes/test_parse_mastodon_post_url[alexwlchan_redirect].yml b/tests/fixtures/cassettes/test_parse_mastodon_post_url[alexwlchan_redirect].yml
new file mode 100644
index 0000000..40337da
--- /dev/null
+++ b/tests/fixtures/cassettes/test_parse_mastodon_post_url[alexwlchan_redirect].yml
@@ -0,0 +1,394 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Connection:
+ - close
+ Host:
+ - social.alexwlchan.net
+ User-Agent:
+ - Python-urllib/3.13
+ method: GET
+ uri: https://social.alexwlchan.net/@chris__martin@functional.cafe/113369395383537892
+ response:
+ body:
+ string: ''
+ headers:
+ Connection:
+ - close
+ Content-Length:
+ - '0'
+ Content-Type:
+ - text/html; charset=utf-8
+ Date:
+ - Tue, 31 Mar 2026 18:03:51 GMT
+ Strict-Transport-Security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ cache-control:
+ - max-age=15, public, stale-while-revalidate=30, stale-if-error=86400
+ content-security-policy:
+ - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
+ ''self'' https://social.alexwlchan.net; img-src ''self'' data: blob: https://social.alexwlchan.net
+ https://cdn.masto.host; media-src ''self'' data: https://social.alexwlchan.net
+ https://cdn.masto.host; manifest-src ''self'' https://social.alexwlchan.net;
+ form-action ''self''; child-src ''self'' blob: https://social.alexwlchan.net;
+ worker-src ''self'' blob: https://social.alexwlchan.net; connect-src ''self''
+ data: blob: https://social.alexwlchan.net https://cdn.masto.host wss://social.alexwlchan.net;
+ script-src ''self'' https://social.alexwlchan.net ''wasm-unsafe-eval''; frame-src
+ ''self'' https:; style-src ''self'' https://social.alexwlchan.net ''nonce-cQwMe/TwveNo3k0uKX6qqw=='''
+ location:
+ - https://social.alexwlchan.net/redirect/statuses/113369395383537892
+ referrer-policy:
+ - same-origin
+ server:
+ - Mastodon
+ strict-transport-security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ vary:
+ - Accept, Accept-Language, Cookie
+ x-content-type-options:
+ - nosniff
+ x-frame-options:
+ - DENY
+ x-request-id:
+ - 03255e3e-39bd-4db2-b42a-82773860cf6b
+ x-runtime:
+ - '0.004837'
+ x-xss-protection:
+ - '0'
+ status:
+ code: 302
+ message: Found
+- request:
+ body: null
+ headers:
+ Connection:
+ - close
+ Host:
+ - social.alexwlchan.net
+ User-Agent:
+ - Python-urllib/3.13
+ method: GET
+ uri: https://social.alexwlchan.net/redirect/statuses/113369395383537892
+ response:
+ body:
+ string: '<!DOCTYPE html>
+
+ <html lang=''en''>
+
+ <head>
+
+ <meta charset=''utf-8''>
+
+ <meta content=''width=device-width, initial-scale=1, viewport-fit=cover''
+ name=''viewport''>
+
+ <link href=''https://cdn.masto.host'' rel=''dns-prefetch''>
+
+ <link href=''/packs/assets/favicon-16x16-74JBPGmr.png'' rel=''icon'' sizes=''16x16''
+ type=''image/png''>
+
+ <link href=''/packs/assets/favicon-32x32-CiQz7Niw.png'' rel=''icon'' sizes=''32x32''
+ type=''image/png''>
+
+ <link href=''/packs/assets/favicon-48x48-DMnduFKh.png'' rel=''icon'' sizes=''48x48''
+ type=''image/png''>
+
+ <link href=''/packs/assets/apple-touch-icon-57x57-BsPGHSez.png'' rel=''apple-touch-icon''
+ sizes=''57x57''>
+
+ <link href=''/packs/assets/apple-touch-icon-60x60-CQE7yLDO.png'' rel=''apple-touch-icon''
+ sizes=''60x60''>
+
+ <link href=''/packs/assets/android-chrome-72x72-9LRpA3QN.png'' rel=''apple-touch-icon''
+ sizes=''72x72''>
+
+ <link href=''/packs/assets/apple-touch-icon-76x76-BPRp9FS0.png'' rel=''apple-touch-icon''
+ sizes=''76x76''>
+
+ <link href=''/packs/assets/apple-touch-icon-114x114-Ch7jwTNh.png'' rel=''apple-touch-icon''
+ sizes=''114x114''>
+
+ <link href=''/packs/assets/apple-touch-icon-120x120-W9xwzzUZ.png'' rel=''apple-touch-icon''
+ sizes=''120x120''>
+
+ <link href=''/packs/assets/android-chrome-144x144-D-ewI-KZ.png'' rel=''apple-touch-icon''
+ sizes=''144x144''>
+
+ <link href=''/packs/assets/apple-touch-icon-152x152-s3oy-zRw.png'' rel=''apple-touch-icon''
+ sizes=''152x152''>
+
+ <link href=''/packs/assets/apple-touch-icon-167x167-DdVi4pJj.png'' rel=''apple-touch-icon''
+ sizes=''167x167''>
+
+ <link href=''/packs/assets/apple-touch-icon-180x180-DSCV_HvQ.png'' rel=''apple-touch-icon''
+ sizes=''180x180''>
+
+ <link href=''/packs/assets/apple-touch-icon-1024x1024-B3Tu3EqI.png'' rel=''apple-touch-icon''
+ sizes=''1024x1024''>
+
+ <link color=''#6364FF'' href=''/packs/assets/logo-symbol-icon-BQIzGafT.svg''
+ rel=''mask-icon''>
+
+ <link href=''/manifest'' rel=''manifest''>
+
+ <meta name="theme-color" content="#ffffff">
+
+ <meta content=''yes'' name=''mobile-web-app-capable''>
+
+ <title>social.alexwlchan.net</title>
+
+ <link rel="stylesheet" crossorigin="anonymous" href="/packs/assets/themes/mastodon-light-DkB3I3Q9.css"
+ integrity="sha384-t/LLx5uEVzKBCSsE4nMTXhbp9DMNTFBO9BY1OiIdKmo8rzwDRIJQeQvX2O/ZNp9O"
+ media="all" />
+
+
+
+ <script src="/packs/assets/polyfills-n1cdkYYu.js" crossorigin="anonymous"
+ type="module" integrity="sha384-cGLFI/4fnUkANJ6Iw0wYFfZE5cgqZlY+HagD4kcmy5z394ZDeu/w5+yIJ36mn0Td"></script>
+
+ <link rel="stylesheet" crossorigin="anonymous" href="/packs/assets/inert-BcT9Trv6.css"
+ integrity="sha384-3QhUaYdsaIWdZ6XozPhzMlN6z+GCcEG6AKW7NHAKsQfUxZuHG0j9yB5wH74CZvr3"
+ media="all" id="inert-style" />
+
+ <script src="/packs/assets/common-RWWoVJPl.js" crossorigin="anonymous" integrity="sha384-+Wt/5KVwGGqjnjpiJKyx/Yd9lLw0zWWFHLtfEGkG4yZ13nmpY5QIUgIKigPUdjhb"
+ type="module"></script><link rel="modulepreload" href="/packs/rails-ujs.esm-CN860jmo.js"
+ as="script" crossorigin="anonymous" integrity="sha384-yfMcx4r1NT8A/QAvn8/IcudEulhHckN3BJDtRsA8L5afESHAbxpDaYWzQrkImLdA">
+
+ <link rel="modulepreload" href="/packs/intl/en-CggNCcBL.js" as="script" crossorigin="anonymous"
+ integrity="sha384-bNup4UloZwLL+zDQ2wlYfZ0VdWSabyd8e3CwKMdVYVMjcblvc9HLK4UbL45SBZdS">
+
+ <meta name="csrf-param" content="authenticity_token" />
+
+ <meta name="csrf-token" content="T7Umi0RGk7M7Zi98F3zGnicqsYXsv9INn1k3kXG2g3moLZXqfmnlThJtHFtoyi_Nk3PbnQlU_os9ZIWOOR2tgA"
+ />
+
+ <meta content=''F6uuLAgWoV2BnDIE+bhLsA=='' name=''style-nonce'' nonce=''F6uuLAgWoV2BnDIE+bhLsA==''
+ property=''csp-nonce''>
+
+ <link rel="stylesheet" href="https://social.alexwlchan.net/css/custom-e3b0c442.css"
+ media="all" />
+
+ <meta content=''noindex, noarchive'' name=''robots''>
+
+ <link href=''https://functional.cafe/@chris__martin/113369395366414375'' rel=''canonical''>
+
+
+ </head>
+
+ <body class=''app-body theme-mastodon-light custom-scrollbars no-reduce-motion''>
+
+ <div class=''redirect''>
+
+ <div class=''redirect__logo''>
+
+ <a href="/"><img alt="Mastodon" class="logo logo--icon" src="/packs/assets/logo-DXQkHAe5.svg"
+ /></a>
+
+ </div>
+
+ <div class=''redirect__message''>
+
+ <h1>You are leaving alexwlchan.net.</h1>
+
+ <p>If you trust this link, click it to continue.</p>
+
+ <p><a rel="noopener" href="https://functional.cafe/@chris__martin/113369395366414375">https://functional.cafe/@chris__martin/113369395366414375</a></p>
+
+ </div>
+
+ </div>
+
+
+ <div aria-hidden=''true'' class=''logo-resources'' inert tabindex=''-1''>
+
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="79" height="79" viewBox="0 0 79 75"><symbol id="logo-symbol-icon"><path
+ d="M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3
+ 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1
+ 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9
+ 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3
+ 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9
+ 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1
+ 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7
+ 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0
+ 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9
+ 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8
+ 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z" fill="currentColor"></path></symbol><use
+ xlink:href="#logo-symbol-icon"></use></svg>
+
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="261" height="66" viewBox="0 0 261 66" fill="none">
+
+ <symbol id="logo-symbol-wordmark"><path d="M60.7539 14.4034C59.8143 7.41942
+ 53.7273 1.91557 46.5117 0.849066C45.2943 0.668854 40.6819 0.0130005 29.9973
+ 0.0130005H29.9175C19.2299 0.0130005 16.937 0.668854 15.7196 0.849066C8.70488
+ 1.88602 2.29885 6.83152 0.744617 13.8982C-0.00294988 17.3784 -0.0827298 21.2367
+ 0.0561464 24.7759C0.254119 29.8514 0.292531 34.918 0.753482 39.9728C1.07215
+ 43.3305 1.62806 46.6614 2.41704 49.9406C3.89445 55.9969 9.87499 61.0369 15.7344
+ 63.0931C22.0077 65.2374 28.7542 65.5934 35.2184 64.1212C35.9295 63.9558 36.6318
+ 63.7638 37.3252 63.5451C38.8971 63.0459 40.738 62.4875 42.0913 61.5067C42.1099
+ 61.4929 42.1251 61.4751 42.1358 61.4547C42.1466 61.4342 42.1526 61.4116 42.1534
+ 61.3885V56.4903C42.153 56.4687 42.1479 56.4475 42.1383 56.4281C42.1287 56.4088
+ 42.1149 56.3918 42.0979 56.3785C42.0809 56.3652 42.0611 56.3559 42.04 56.3512C42.019
+ 56.3465 41.9971 56.3466 41.9761 56.3514C37.8345 57.3406 33.5905 57.8364 29.3324
+ 57.8286C22.0045 57.8286 20.0336 54.3514 19.4693 52.9038C19.0156 51.6527 18.7275
+ 50.3476 18.6124 49.0218C18.6112 48.9996 18.6153 48.9773 18.6243 48.9569C18.6333
+ 48.9366 18.647 48.9186 18.6643 48.9045C18.6816 48.8904 18.7019 48.8805 18.7237
+ 48.8758C18.7455 48.871 18.7681 48.8715 18.7897 48.8771C22.8622 49.8595 27.037
+ 50.3553 31.2265 50.3542C32.234 50.3542 33.2387 50.3542 34.2463 50.3276C38.4598
+ 50.2094 42.9009 49.9938 47.0465 49.1843C47.1499 49.1636 47.2534 49.1459 47.342
+ 49.1193C53.881 47.8637 60.1038 43.9227 60.7362 33.9431C60.7598 33.5502 60.8189
+ 29.8278 60.8189 29.4201C60.8218 28.0345 61.2651 19.5911 60.7539 14.4034Z"
+ fill="url(#paint0_linear_89_11)"></path>
+
+ <path d="M12.3442 18.3034C12.3442 16.2668 13.9777 14.6194 15.997 14.6194C18.0163
+ 14.6194 19.6497 16.2668 19.6497 18.3034C19.6497 20.34 18.0163 21.9874 15.997
+ 21.9874C13.9777 21.9874 12.3442 20.34 12.3442 18.3034Z" fill="currentColor"></path>
+
+ <path d="M66.1484 21.4685V38.3839H59.4988V21.9744C59.4988 18.5109 58.0583
+ 16.7597 55.1643 16.7597C51.9746 16.7597 50.3668 18.8482 50.3668 22.9603V31.9499H43.7687V22.9603C43.7687
+ 18.8352 42.1738 16.7597 38.9712 16.7597C36.0901 16.7597 34.6367 18.5109 34.6367
+ 21.9744V38.3839H28V21.4685C28 18.018 28.8746 15.268 30.6238 13.2314C32.4374
+ 11.1948 34.8039 10.157 37.7365 10.157C41.132 10.157 43.7172 11.4802 45.415
+ 14.1135L47.0742 16.9154L48.7334 14.1135C50.4311 11.4802 53.0035 10.157 56.4119
+ 10.157C59.3444 10.157 61.711 11.1948 63.5246 13.2314C65.2738 15.268 66.1484
+ 18.005 66.1484 21.4685ZM89.0297 29.8743C90.4059 28.4085 91.0619 26.5795 91.0619
+ 24.3613C91.0619 22.1431 90.4059 20.3011 89.0297 18.9001C87.7049 17.4343 86.0329
+ 16.7338 84.0007 16.7338C81.9685 16.7338 80.2965 17.4343 78.9717 18.9001C77.6469
+ 20.3011 76.991 22.1431 76.991 24.3613C76.991 26.5795 77.6469 28.4215 78.9717
+ 29.8743C80.2965 31.2753 81.9685 31.9888 84.0007 31.9888C86.0329 31.9888 87.7049
+ 31.2883 89.0297 29.8743ZM91.0619 10.8316H97.6086V37.891H91.0619V34.6999C89.0811
+ 37.3462 86.3416 38.6563 82.7788 38.6563C79.2161 38.6563 76.4765 37.3073 74.0456
+ 34.5442C71.6533 31.7812 70.4443 28.3696 70.4443 24.3743C70.4443 20.3789 71.6661
+ 17.0192 74.0456 14.2561C76.4893 11.4931 79.3833 10.0922 82.7788 10.0922C86.1744
+ 10.0922 89.0811 11.3894 91.0619 14.0356V10.8445V10.8316ZM119.654 23.8683C121.583
+ 25.3342 122.548 27.3837 122.496 29.9781C122.496 32.7411 121.532 34.9075 119.551
+ 36.4122C117.57 37.878 115.178 38.6304 112.284 38.6304C107.049 38.6304 103.499
+ 36.4641 101.621 32.1963L107.306 28.7847C108.065 31.1067 109.737 32.3001 112.284
+ 32.3001C114.625 32.3001 115.782 31.5477 115.782 29.9781C115.782 28.8366 114.265
+ 27.8118 111.165 27.0075C109.995 26.6833 109.03 26.359 108.271 26.0865C107.204
+ 25.6585 106.29 25.1655 105.532 24.5688C103.654 23.103 102.689 21.1572 102.689
+ 18.6666C102.689 16.0203 103.602 13.9059 105.429 12.3882C107.306 10.8186 109.596
+ 10.0662 112.335 10.0662C116.709 10.0662 119.898 11.9601 121.982 15.7998L116.4
+ 19.0428C115.59 17.2008 114.213 16.2798 112.335 16.2798C110.355 16.2798 109.39
+ 17.0321 109.39 18.498C109.39 19.6395 110.908 20.6643 114.008 21.4685C116.4
+ 22.0134 118.278 22.8176 119.641 23.8554L119.654 23.8683ZM140.477 17.538H134.741V28.7977C134.741
+ 30.1468 135.255 30.964 136.22 31.3402C136.927 31.6126 138.355 31.6645 140.49
+ 31.5607V37.891C136.079 38.4358 132.876 37.9948 130.998 36.5419C129.12 35.1409
+ 128.207 32.5336 128.207 28.8106V17.538H123.795V10.8316H128.207V5.37038L134.754
+ 3.25595V10.8316H140.49V17.538H140.477ZM161.352 29.7187C162.677 28.3177 163.333
+ 26.5276 163.333 24.3613C163.333 22.195 162.677 20.4178 161.352 19.0039C160.027
+ 17.6029 158.407 16.8894 156.426 16.8894C154.445 16.8894 152.825 17.5899 151.5
+ 19.0039C150.227 20.4697 149.571 22.2469 149.571 24.3613C149.571 26.4757 150.227
+ 28.2529 151.5 29.7187C152.825 31.1196 154.445 31.8331 156.426 31.8331C158.407
+ 31.8331 160.027 31.1326 161.352 29.7187ZM146.883 34.5313C144.297 31.7682 143.024
+ 28.4215 143.024 24.3613C143.024 20.3011 144.297 17.0062 146.883 14.2432C149.468
+ 11.4802 152.67 10.0792 156.426 10.0792C160.182 10.0792 163.384 11.4802 165.97
+ 14.2432C168.555 17.0062 169.88 20.4178 169.88 24.3613C169.88 28.3047 168.555
+ 31.7682 165.97 34.5313C163.384 37.2943 160.233 38.6434 156.426 38.6434C152.619
+ 38.6434 149.468 37.2943 146.883 34.5313ZM191.771 29.8743C193.095 28.4085 193.751
+ 26.5795 193.751 24.3613C193.751 22.1431 193.095 20.3011 191.771 18.9001C190.446
+ 17.4343 188.774 16.7338 186.742 16.7338C184.709 16.7338 183.037 17.4343 181.661
+ 18.9001C180.336 20.3011 179.68 22.1431 179.68 24.3613C179.68 26.5795 180.336
+ 28.4215 181.661 29.8743C183.037 31.2753 184.761 31.9888 186.742 31.9888C188.722
+ 31.9888 190.446 31.2883 191.771 29.8743ZM193.751 0H200.298V37.891H193.751V34.6999C191.822
+ 37.3462 189.082 38.6563 185.52 38.6563C181.957 38.6563 179.179 37.3073 176.735
+ 34.5442C174.343 31.7812 173.134 28.3696 173.134 24.3743C173.134 20.3789 174.356
+ 17.0192 176.735 14.2561C179.166 11.4931 182.111 10.0922 185.52 10.0922C188.928
+ 10.0922 191.822 11.3894 193.751 14.0356V0.0129719V0ZM223.308 29.7057C224.633
+ 28.3047 225.289 26.5146 225.289 24.3483C225.289 22.182 224.633 20.4048 223.308
+ 18.9909C221.983 17.5899 220.363 16.8765 218.382 16.8765C216.401 16.8765 214.78
+ 17.577 213.456 18.9909C212.182 20.4567 211.526 22.2339 211.526 24.3483C211.526
+ 26.4627 212.182 28.2399 213.456 29.7057C214.78 31.1067 216.401 31.8201 218.382
+ 31.8201C220.363 31.8201 221.983 31.1196 223.308 29.7057ZM208.838 34.5183C206.253
+ 31.7553 204.98 28.4085 204.98 24.3483C204.98 20.2881 206.253 16.9932 208.838
+ 14.2302C211.424 11.4672 214.626 10.0662 218.382 10.0662C222.137 10.0662 225.34
+ 11.4672 227.925 14.2302C230.511 16.9932 231.835 20.4048 231.835 24.3483C231.835
+ 28.2918 230.511 31.7553 227.925 34.5183C225.34 37.2813 222.189 38.6304 218.382
+ 38.6304C214.575 38.6304 211.424 37.2813 208.838 34.5183ZM260.17 21.261V37.878H253.623V22.1301C253.623
+ 20.34 253.173 18.9909 252.247 17.9661C251.385 17.0451 250.164 16.5651 248.594
+ 16.5651C244.89 16.5651 243.012 18.7833 243.012 23.2716V37.878H236.466V10.8316H243.012V13.867C244.581
+ 11.3245 247.077 10.0792 250.575 10.0792C253.366 10.0792 255.656 11.0521 257.431
+ 13.0498C259.257 15.0474 260.17 17.7586 260.17 21.274" fill="currentColor"></path>
+
+ <defs>
+
+ <linearGradient id="paint0_linear_89_11" x1="30.5" y1="0.0130005" x2="30.5"
+ y2="65.013" gradientUnits="userSpaceOnUse">
+
+ <stop stop-color="#6364FF"></stop>
+
+ <stop offset="1" stop-color="#563ACC"></stop>
+
+ </linearGradient>
+
+ </defs></symbol><use xlink:href="#logo-symbol-wordmark"></use>
+
+ </svg>
+
+ </div>
+
+ </body>
+
+ </html>
+
+ '
+ headers:
+ Connection:
+ - close
+ Content-Length:
+ - '12844'
+ Content-Type:
+ - text/html; charset=utf-8
+ Date:
+ - Tue, 31 Mar 2026 18:03:51 GMT
+ Strict-Transport-Security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ Vary:
+ - Accept-Encoding
+ - Accept-Language
+ cache-control:
+ - private, no-store
+ content-security-policy:
+ - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
+ ''self'' https://social.alexwlchan.net; img-src ''self'' data: blob: https://social.alexwlchan.net
+ https://cdn.masto.host; media-src ''self'' data: https://social.alexwlchan.net
+ https://cdn.masto.host; manifest-src ''self'' https://social.alexwlchan.net;
+ form-action ''self''; child-src ''self'' blob: https://social.alexwlchan.net;
+ worker-src ''self'' blob: https://social.alexwlchan.net; connect-src ''self''
+ data: blob: https://social.alexwlchan.net https://cdn.masto.host wss://social.alexwlchan.net;
+ script-src ''self'' https://social.alexwlchan.net ''wasm-unsafe-eval''; frame-src
+ ''self'' https:; style-src ''self'' https://social.alexwlchan.net ''nonce-F6uuLAgWoV2BnDIE+bhLsA=='''
+ etag:
+ - W/"34a62b8616c9adc16d65d7ef329e5be7"
+ referrer-policy:
+ - same-origin
+ server:
+ - Mastodon
+ set-cookie:
+ - _mastodon_session=wNtd7l9vuy3JLcOguT9sGC8UFLC6gss39Hn4d7sX6v4%2F4Cn6wPCB5W4NsPO0Mn%2FDb8ZugtLRcVMP3dgLvDMwlufUiRXrXfVFiZm%2Bv1phhfSCF2hIXP5Jkt9%2B4nC2gU63Gi7WzFDYM%2BHjzxS%2FhjrcJkZ2hB7JpQMm1%2FJvvNBv%2BGGkAT%2Fn4DCsyH%2BE9HyVDFdm2lff9tEVyrUtJXYc3zlZhImzuDwZHWnFzFc6zvTKQwR6kIQwFD2YTysAK6B7mhGWAwkPhdPxSn77NQSgzOX8e8bdaY2Jbe5IcQ%3D%3D--BFK7dhaBLUUNfMRe--r0AbQUqEVM6kRxpyFIRlkA%3D%3D;
+ path=/; httponly; samesite=lax; secure
+ strict-transport-security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ vary:
+ - Accept-Encoding
+ - Accept-Language
+ x-content-type-options:
+ - nosniff
+ x-frame-options:
+ - DENY
+ x-request-id:
+ - f292b7e5-970d-4be4-8a22-34f1842a8252
+ x-runtime:
+ - '0.010231'
+ x-xss-protection:
+ - '0'
+ status:
+ code: 200
+ message: OK
+version: 1
tests/fixtures/cassettes/test_parse_mastodon_post_url_errors[alexwlchan_does_not_exist].yml (0) → tests/fixtures/cassettes/test_parse_mastodon_post_url_errors[alexwlchan_does_not_exist].yml (45447)
diff --git a/tests/fixtures/cassettes/test_parse_mastodon_post_url_errors[alexwlchan_does_not_exist].yml b/tests/fixtures/cassettes/test_parse_mastodon_post_url_errors[alexwlchan_does_not_exist].yml
new file mode 100644
index 0000000..4810430
--- /dev/null
+++ b/tests/fixtures/cassettes/test_parse_mastodon_post_url_errors[alexwlchan_does_not_exist].yml
@@ -0,0 +1,425 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Connection:
+ - close
+ Host:
+ - social.alexwlchan.net
+ User-Agent:
+ - Python-urllib/3.13
+ method: GET
+ uri: https://social.alexwlchan.net/@does@not.exist/123
+ response:
+ body:
+ string: "<!DOCTYPE html>\n<html lang='en'>\n<head>\n<meta charset='utf-8'>\n<meta
+ content='width=device-width, initial-scale=1, viewport-fit=cover' name='viewport'>\n<link
+ href='https://cdn.masto.host' rel='dns-prefetch'>\n<link href='/packs/assets/favicon-16x16-74JBPGmr.png'
+ rel='icon' sizes='16x16' type='image/png'>\n<link href='/packs/assets/favicon-32x32-CiQz7Niw.png'
+ rel='icon' sizes='32x32' type='image/png'>\n<link href='/packs/assets/favicon-48x48-DMnduFKh.png'
+ rel='icon' sizes='48x48' type='image/png'>\n<link href='/packs/assets/apple-touch-icon-57x57-BsPGHSez.png'
+ rel='apple-touch-icon' sizes='57x57'>\n<link href='/packs/assets/apple-touch-icon-60x60-CQE7yLDO.png'
+ rel='apple-touch-icon' sizes='60x60'>\n<link href='/packs/assets/android-chrome-72x72-9LRpA3QN.png'
+ rel='apple-touch-icon' sizes='72x72'>\n<link href='/packs/assets/apple-touch-icon-76x76-BPRp9FS0.png'
+ rel='apple-touch-icon' sizes='76x76'>\n<link href='/packs/assets/apple-touch-icon-114x114-Ch7jwTNh.png'
+ rel='apple-touch-icon' sizes='114x114'>\n<link href='/packs/assets/apple-touch-icon-120x120-W9xwzzUZ.png'
+ rel='apple-touch-icon' sizes='120x120'>\n<link href='/packs/assets/android-chrome-144x144-D-ewI-KZ.png'
+ rel='apple-touch-icon' sizes='144x144'>\n<link href='/packs/assets/apple-touch-icon-152x152-s3oy-zRw.png'
+ rel='apple-touch-icon' sizes='152x152'>\n<link href='/packs/assets/apple-touch-icon-167x167-DdVi4pJj.png'
+ rel='apple-touch-icon' sizes='167x167'>\n<link href='/packs/assets/apple-touch-icon-180x180-DSCV_HvQ.png'
+ rel='apple-touch-icon' sizes='180x180'>\n<link href='/packs/assets/apple-touch-icon-1024x1024-B3Tu3EqI.png'
+ rel='apple-touch-icon' sizes='1024x1024'>\n<link color='#6364FF' href='/packs/assets/logo-symbol-icon-BQIzGafT.svg'
+ rel='mask-icon'>\n<link href='/manifest' rel='manifest'>\n<meta name=\"theme-color\"
+ content=\"#ffffff\">\n<meta content='yes' name='mobile-web-app-capable'>\n<title>social.alexwlchan.net</title>\n<link
+ rel=\"stylesheet\" crossorigin=\"anonymous\" href=\"/packs/assets/themes/mastodon-light-DkB3I3Q9.css\"
+ integrity=\"sha384-t/LLx5uEVzKBCSsE4nMTXhbp9DMNTFBO9BY1OiIdKmo8rzwDRIJQeQvX2O/ZNp9O\"
+ media=\"all\" />\n\n\n<script src=\"/packs/assets/polyfills-n1cdkYYu.js\"
+ crossorigin=\"anonymous\" type=\"module\" integrity=\"sha384-cGLFI/4fnUkANJ6Iw0wYFfZE5cgqZlY+HagD4kcmy5z394ZDeu/w5+yIJ36mn0Td\"></script>\n<link
+ rel=\"stylesheet\" crossorigin=\"anonymous\" href=\"/packs/assets/inert-BcT9Trv6.css\"
+ integrity=\"sha384-3QhUaYdsaIWdZ6XozPhzMlN6z+GCcEG6AKW7NHAKsQfUxZuHG0j9yB5wH74CZvr3\"
+ media=\"all\" id=\"inert-style\" />\n<script src=\"/packs/assets/common-RWWoVJPl.js\"
+ crossorigin=\"anonymous\" integrity=\"sha384-+Wt/5KVwGGqjnjpiJKyx/Yd9lLw0zWWFHLtfEGkG4yZ13nmpY5QIUgIKigPUdjhb\"
+ type=\"module\"></script><link rel=\"modulepreload\" href=\"/packs/rails-ujs.esm-CN860jmo.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-yfMcx4r1NT8A/QAvn8/IcudEulhHckN3BJDtRsA8L5afESHAbxpDaYWzQrkImLdA\">\n<link
+ rel=\"modulepreload\" href=\"/packs/intl/en-CggNCcBL.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-bNup4UloZwLL+zDQ2wlYfZ0VdWSabyd8e3CwKMdVYVMjcblvc9HLK4UbL45SBZdS\">\n\n<meta
+ content='XkCHQQX3C3RpkX/PbOM/9Q==' name='style-nonce' nonce='XkCHQQX3C3RpkX/PbOM/9Q=='
+ property='csp-nonce'>\n<link rel=\"stylesheet\" href=\"https://social.alexwlchan.net/css/custom-e3b0c442.css\"
+ media=\"all\" />\n<meta content='noindex' name='robots'>\n<meta content='Alex
+ Chan's personal Mastodon server (hosted by Masto.host)' name='description'>\n<meta
+ content=\"Mastodon hosted on alexwlchan.net\" property=\"og:site_name\">\n<meta
+ content=\"https://social.alexwlchan.net/@does@not.exist\" property=\"og:url\">\n<meta
+ content=\"website\" property=\"og:type\">\n<meta content=\"social.alexwlchan.net\"
+ property=\"og:title\">\n<meta content=\"Alex Chan's personal Mastodon
+ server (hosted by Masto.host)\" property=\"og:description\">\n<meta content=\"https://cdn.masto.host/socialalexwlchannet/site_uploads/files/000/000/001/@1x/fe9788af7158d5b1.png\"
+ property=\"og:image\">\n<meta content=\"4608\" property=\"og:image:width\">\n<meta
+ content=\"3456\" property=\"og:image:height\">\n<meta content=\"summary_large_image\"
+ property=\"twitter:card\">\n\n<meta content='BKNFht7Hik2tM7AAvgXr-i1Fb_XB1p14VTV6ZpyeLWk0EZAJK9LlidLUuRT5vCAkoM0Mfgk8eCZMXdRziLmC0B0='
+ name='applicationServerKey'>\n<script id=\"initial-state\" type=\"application/json\">{\"meta\":{\"access_token\":null,\"activity_api_enabled\":false,\"admin\":null,\"domain\":\"alexwlchan.net\",\"limited_federation_mode\":false,\"locale\":\"en\",\"mascot\":null,\"profile_directory\":false,\"registrations_open\":false,\"repository\":\"mastodon/mastodon\",\"search_enabled\":false,\"single_user_mode\":false,\"source_url\":\"https://github.com/mastodon/mastodon\",\"sso_redirect\":null,\"status_page_url\":null,\"streaming_api_base_url\":\"wss://social.alexwlchan.net\",\"title\":\"social.alexwlchan.net\",\"landing_page\":\"about\",\"trends_enabled\":false,\"version\":\"4.5.8\",\"terms_of_service_enabled\":false,\"local_live_feed_access\":\"public\",\"remote_live_feed_access\":\"public\",\"local_topic_feed_access\":\"public\",\"remote_topic_feed_access\":\"public\",\"auto_play_gif\":null,\"display_media\":null,\"reduce_motion\":null,\"use_blurhash\":null},\"compose\":{\"text\":\"\"},\"accounts\":{},\"media_attachments\":{\"accept_content_types\":[\".jpg\",\".jpeg\",\".png\",\".gif\",\".webp\",\".heic\",\".heif\",\".avif\",\".webm\",\".mp4\",\".m4v\",\".mov\",\".ogg\",\".oga\",\".mp3\",\".wav\",\".flac\",\".opus\",\".aac\",\".m4a\",\".3gp\",\".wma\",\"image/jpeg\",\"image/png\",\"image/gif\",\"image/heic\",\"image/heif\",\"image/webp\",\"image/avif\",\"video/webm\",\"video/mp4\",\"video/quicktime\",\"video/ogg\",\"audio/wave\",\"audio/wav\",\"audio/x-wav\",\"audio/x-pn-wave\",\"audio/vnd.wave\",\"audio/ogg\",\"audio/vorbis\",\"audio/mpeg\",\"audio/mp3\",\"audio/webm\",\"audio/flac\",\"audio/aac\",\"audio/m4a\",\"audio/x-m4a\",\"audio/mp4\",\"audio/3gpp\",\"video/x-ms-asf\"]},\"settings\":{},\"languages\":[[\"aa\",\"Afar\",\"Afaraf\"],[\"ab\",\"Abkhaz\",\"\u0430\u04A7\u0441\u0443\u0430
+ \u0431\u044B\u0437\u0448\u04D9\u0430\"],[\"ae\",\"Avestan\",\"avesta\"],[\"af\",\"Afrikaans\",\"Afrikaans\"],[\"ak\",\"Akan\",\"Akan\"],[\"am\",\"Amharic\",\"\u12A0\u121B\u122D\u129B\"],[\"an\",\"Aragonese\",\"aragon\xE9s\"],[\"ar\",\"Arabic\",\"\u0627\u0644\u0644\u063A\u0629
+ \u0627\u0644\u0639\u0631\u0628\u064A\u0629\"],[\"as\",\"Assamese\",\"\u0985\u09B8\u09AE\u09C0\u09AF\u09BC\u09BE\"],[\"av\",\"Avaric\",\"\u0430\u0432\u0430\u0440
+ \u043C\u0430\u0446\u04C0\"],[\"ay\",\"Aymara\",\"aymar aru\"],[\"az\",\"Azerbaijani\",\"az\u0259rbaycan
+ dili\"],[\"ba\",\"Bashkir\",\"\u0431\u0430\u0448\u04A1\u043E\u0440\u0442 \u0442\u0435\u043B\u0435\"],[\"be\",\"Belarusian\",\"\u0431\u0435\u043B\u0430\u0440\u0443\u0441\u043A\u0430\u044F
+ \u043C\u043E\u0432\u0430\"],[\"bg\",\"Bulgarian\",\"\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438
+ \u0435\u0437\u0438\u043A\"],[\"bh\",\"Bihari\",\"\u092D\u094B\u091C\u092A\u0941\u0930\u0940\"],[\"bi\",\"Bislama\",\"Bislama\"],[\"bm\",\"Bambara\",\"bamanankan\"],[\"bn\",\"Bengali\",\"\u09AC\u09BE\u0982\u09B2\u09BE\"],[\"bo\",\"Tibetan\",\"\u0F56\u0F7C\u0F51\u0F0B\u0F61\u0F72\u0F42\"],[\"br\",\"Breton\",\"brezhoneg\"],[\"bs\",\"Bosnian\",\"bosanski
+ jezik\"],[\"ca\",\"Catalan\",\"Catal\xE0\"],[\"ce\",\"Chechen\",\"\u043D\u043E\u0445\u0447\u0438\u0439\u043D
+ \u043C\u043E\u0442\u0442\"],[\"ch\",\"Chamorro\",\"Chamoru\"],[\"co\",\"Corsican\",\"corsu\"],[\"cr\",\"Cree\",\"\u14C0\u1426\u1403\u152D\u140D\u140F\u1423\"],[\"cs\",\"Czech\",\"\u010De\u0161tina\"],[\"cu\",\"Old
+ Church Slavonic\",\"\u0469\u0437\u044B\u043A\u044A \u0441\u043B\u043E\u0432\u0463\u043D\u044C\u0441\u043A\u044A\"],[\"cv\",\"Chuvash\",\"\u0447\u04D1\u0432\u0430\u0448
+ \u0447\u04D7\u043B\u0445\u0438\"],[\"cy\",\"Welsh\",\"Cymraeg\"],[\"da\",\"Danish\",\"dansk\"],[\"de\",\"German\",\"Deutsch\"],[\"dv\",\"Divehi\",\"Dhivehi\"],[\"dz\",\"Dzongkha\",\"\u0F62\u0FAB\u0F7C\u0F44\u0F0B\u0F41\"],[\"ee\",\"Ewe\",\"E\u028Begbe\"],[\"el\",\"Greek\",\"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC\"],[\"en\",\"English\",\"English\"],[\"eo\",\"Esperanto\",\"Esperanto\"],[\"es\",\"Spanish\",\"Espa\xF1ol\"],[\"et\",\"Estonian\",\"eesti\"],[\"eu\",\"Basque\",\"euskara\"],[\"fa\",\"Persian\",\"\u0641\u0627\u0631\u0633\u06CC\"],[\"ff\",\"Fula\",\"Fulfulde\"],[\"fi\",\"Finnish\",\"suomi\"],[\"fj\",\"Fijian\",\"Vakaviti\"],[\"fo\",\"Faroese\",\"f\xF8royskt\"],[\"fr\",\"French\",\"Fran\xE7ais\"],[\"fy\",\"Western
+ Frisian\",\"Frysk\"],[\"ga\",\"Irish\",\"Gaeilge\"],[\"gd\",\"Scottish Gaelic\",\"G\xE0idhlig\"],[\"gl\",\"Galician\",\"galego\"],[\"gu\",\"Gujarati\",\"\u0A97\u0AC1\u0A9C\u0AB0\u0ABE\u0AA4\u0AC0\"],[\"gv\",\"Manx\",\"Gaelg\"],[\"ha\",\"Hausa\",\"\u0647\u064E\u0648\u064F\u0633\u064E\"],[\"he\",\"Hebrew\",\"\u05E2\u05D1\u05E8\u05D9\u05EA\"],[\"hi\",\"Hindi\",\"\u0939\u093F\u0928\u094D\u0926\u0940\"],[\"ho\",\"Hiri
+ Motu\",\"Hiri Motu\"],[\"hr\",\"Croatian\",\"Hrvatski\"],[\"ht\",\"Haitian\",\"Krey\xF2l
+ ayisyen\"],[\"hu\",\"Hungarian\",\"magyar\"],[\"hy\",\"Armenian\",\"\u0540\u0561\u0575\u0565\u0580\u0565\u0576\"],[\"hz\",\"Herero\",\"Otjiherero\"],[\"ia\",\"Interlingua\",\"Interlingua\"],[\"id\",\"Indonesian\",\"Bahasa
+ Indonesia\"],[\"ie\",\"Interlingue\",\"Interlingue\"],[\"ig\",\"Igbo\",\"As\u1EE5s\u1EE5
+ Igbo\"],[\"ii\",\"Nuosu\",\"\uA188\uA320\uA4BF Nuosuhxop\"],[\"ik\",\"Inupiaq\",\"I\xF1upiaq\"],[\"io\",\"Ido\",\"Ido\"],[\"is\",\"Icelandic\",\"\xCDslenska\"],[\"it\",\"Italian\",\"Italiano\"],[\"iu\",\"Inuktitut\",\"\u1403\u14C4\u1483\u144E\u1450\u1466\"],[\"ja\",\"Japanese\",\"\u65E5\u672C\u8A9E\"],[\"jv\",\"Javanese\",\"basa
+ Jawa\"],[\"ka\",\"Georgian\",\"\u10E5\u10D0\u10E0\u10D7\u10E3\u10DA\u10D8\"],[\"kg\",\"Kongo\",\"Kikongo\"],[\"ki\",\"Kikuyu\",\"G\u0129k\u0169y\u0169\"],[\"kj\",\"Kwanyama\",\"Kuanyama\"],[\"kk\",\"Kazakh\",\"\u049B\u0430\u0437\u0430\u049B
+ \u0442\u0456\u043B\u0456\"],[\"kl\",\"Kalaallisut\",\"kalaallisut\"],[\"km\",\"Khmer\",\"\u1781\u17C1\u1798\u179A\u1797\u17B6\u179F\u17B6\"],[\"kn\",\"Kannada\",\"\u0C95\u0CA8\u0CCD\u0CA8\u0CA1\"],[\"ko\",\"Korean\",\"\uD55C\uAD6D\uC5B4\"],[\"kr\",\"Kanuri\",\"Kanuri\"],[\"ks\",\"Kashmiri\",\"\u0915\u0936\u094D\u092E\u0940\u0930\u0940\"],[\"ku\",\"Kurmanji
+ (Kurdish)\",\"Kurmanc\xEE\"],[\"kv\",\"Komi\",\"\u043A\u043E\u043C\u0438 \u043A\u044B\u0432\"],[\"kw\",\"Cornish\",\"Kernewek\"],[\"ky\",\"Kyrgyz\",\"\u041A\u044B\u0440\u0433\u044B\u0437\u0447\u0430\"],[\"la\",\"Latin\",\"latine\"],[\"lb\",\"Luxembourgish\",\"L\xEBtzebuergesch\"],[\"lg\",\"Ganda\",\"Luganda\"],[\"li\",\"Limburgish\",\"Limburgs\"],[\"ln\",\"Lingala\",\"Ling\xE1la\"],[\"lo\",\"Lao\",\"\u0EA5\u0EB2\u0EA7\"],[\"lt\",\"Lithuanian\",\"lietuvi\u0173
+ kalba\"],[\"lu\",\"Luba-Katanga\",\"Tshiluba\"],[\"lv\",\"Latvian\",\"latvie\u0161u
+ valoda\"],[\"mg\",\"Malagasy\",\"fiteny malagasy\"],[\"mh\",\"Marshallese\",\"Kajin
+ M\u0327aje\u013C\"],[\"mi\",\"M\u0101ori\",\"te reo M\u0101ori\"],[\"mk\",\"Macedonian\",\"\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438
+ \u0458\u0430\u0437\u0438\u043A\"],[\"ml\",\"Malayalam\",\"\u0D2E\u0D32\u0D2F\u0D3E\u0D33\u0D02\"],[\"mn\",\"Mongolian\",\"\u041C\u043E\u043D\u0433\u043E\u043B
+ \u0445\u044D\u043B\"],[\"mn-Mong\",\"Traditional Mongolian\",\"\u182E\u1823\u1829\u182D\u1823\u182F
+ \u182C\u1821\u182F\u1821\"],[\"mr\",\"Marathi\",\"\u092E\u0930\u093E\u0920\u0940\"],[\"ms\",\"Malay\",\"Bahasa
+ Melayu\"],[\"ms-Arab\",\"Jawi Malay\",\"\u0628\u0647\u0627\u0633 \u0645\u0644\u0627\u064A\u0648\"],[\"mt\",\"Maltese\",\"Malti\"],[\"my\",\"Burmese\",\"\u1017\u1019\u102C\u1005\u102C\"],[\"na\",\"Nauru\",\"Ekakair\u0169
+ Naoero\"],[\"nb\",\"Norwegian Bokm\xE5l\",\"Norsk bokm\xE5l\"],[\"nd\",\"Northern
+ Ndebele\",\"isiNdebele\"],[\"ne\",\"Nepali\",\"\u0928\u0947\u092A\u093E\u0932\u0940\"],[\"ng\",\"Ndonga\",\"Owambo\"],[\"nl\",\"Dutch\",\"Nederlands\"],[\"nn\",\"Norwegian
+ Nynorsk\",\"Norsk Nynorsk\"],[\"no\",\"Norwegian\",\"Norsk\"],[\"nr\",\"Southern
+ Ndebele\",\"isiNdebele\"],[\"nv\",\"Navajo\",\"Din\xE9 bizaad\"],[\"ny\",\"Chichewa\",\"chiChe\u0175a\"],[\"oc\",\"Occitan\",\"occitan\"],[\"oj\",\"Ojibwe\",\"\u140A\u14C2\u1511\u14C8\u142F\u14A7\u140E\u14D0\"],[\"om\",\"Oromo\",\"Afaan
+ Oromoo\"],[\"or\",\"Oriya\",\"\u0B13\u0B21\u0B3C\u0B3F\u0B06\"],[\"os\",\"Ossetian\",\"\u0438\u0440\u043E\u043D
+ \xE6\u0432\u0437\u0430\u0433\"],[\"pa\",\"Punjabi\",\"\u0A2A\u0A70\u0A1C\u0A3E\u0A2C\u0A40\"],[\"pi\",\"P\u0101li\",\"\u092A\u093E\u0934\u093F\"],[\"pl\",\"Polish\",\"Polski\"],[\"ps\",\"Pashto\",\"\u067E\u069A\u062A\u0648\"],[\"pt\",\"Portuguese\",\"Portugu\xEAs\"],[\"qu\",\"Quechua\",\"Runa
+ Simi\"],[\"rm\",\"Romansh\",\"rumantsch grischun\"],[\"rn\",\"Kirundi\",\"Ikirundi\"],[\"ro\",\"Romanian\",\"Rom\xE2n\u0103\"],[\"ru\",\"Russian\",\"\u0420\u0443\u0441\u0441\u043A\u0438\u0439\"],[\"rw\",\"Kinyarwanda\",\"Ikinyarwanda\"],[\"sa\",\"Sanskrit\",\"\u0938\u0902\u0938\u094D\u0915\u0943\u0924\u092E\u094D\"],[\"sc\",\"Sardinian\",\"sardu\"],[\"sd\",\"Sindhi\",\"\u0938\u093F\u0928\u094D\u0927\u0940\"],[\"se\",\"Northern
+ Sami\",\"Davvis\xE1megiella\"],[\"sg\",\"Sango\",\"y\xE2ng\xE2 t\xEE s\xE4ng\xF6\"],[\"si\",\"Sinhala\",\"\u0DC3\u0DD2\u0D82\u0DC4\u0DBD\"],[\"sk\",\"Slovak\",\"sloven\u010Dina\"],[\"sl\",\"Slovenian\",\"sloven\u0161\u010Dina\"],[\"sn\",\"Shona\",\"chiShona\"],[\"so\",\"Somali\",\"Soomaaliga\"],[\"sq\",\"Albanian\",\"Shqip\"],[\"sr\",\"Serbian\",\"\u0441\u0440\u043F\u0441\u043A\u0438
+ \u0458\u0435\u0437\u0438\u043A\"],[\"ss\",\"Swati\",\"SiSwati\"],[\"st\",\"Southern
+ Sotho\",\"Sesotho\"],[\"su\",\"Sundanese\",\"Basa Sunda\"],[\"sv\",\"Swedish\",\"Svenska\"],[\"sw\",\"Swahili\",\"Kiswahili\"],[\"ta\",\"Tamil\",\"\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD\"],[\"te\",\"Telugu\",\"\u0C24\u0C46\u0C32\u0C41\u0C17\u0C41\"],[\"tg\",\"Tajik\",\"\u0442\u043E\u04B7\u0438\u043A\u04E3\"],[\"th\",\"Thai\",\"\u0E44\u0E17\u0E22\"],[\"ti\",\"Tigrinya\",\"\u1275\u130D\u122D\u129B\"],[\"tk\",\"Turkmen\",\"T\xFCrkmen\"],[\"tl\",\"Tagalog\",\"Tagalog\"],[\"tn\",\"Tswana\",\"Setswana\"],[\"to\",\"Tonga\",\"faka
+ Tonga\"],[\"tr\",\"Turkish\",\"T\xFCrk\xE7e\"],[\"ts\",\"Tsonga\",\"Xitsonga\"],[\"tt\",\"Tatar\",\"\u0442\u0430\u0442\u0430\u0440
+ \u0442\u0435\u043B\u0435\"],[\"tw\",\"Twi\",\"Twi\"],[\"ty\",\"Tahitian\",\"Reo
+ Tahiti\"],[\"ug\",\"Uyghur\",\"\u0626\u06C7\u064A\u063A\u06C7\u0631\u0686\u06D5\u200E\"],[\"uk\",\"Ukrainian\",\"\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430\"],[\"ur\",\"Urdu\",\"\u0627\u0631\u062F\u0648\"],[\"uz\",\"Uzbek\",\"\u040E\u0437\u0431\u0435\u043A\"],[\"ve\",\"Venda\",\"Tshiven\u1E13a\"],[\"vi\",\"Vietnamese\",\"Ti\u1EBFng
+ Vi\u1EC7t\"],[\"vo\",\"Volap\xFCk\",\"Volap\xFCk\"],[\"wa\",\"Walloon\",\"walon\"],[\"wo\",\"Wolof\",\"Wollof\"],[\"xh\",\"Xhosa\",\"isiXhosa\"],[\"yi\",\"Yiddish\",\"\u05D9\u05D9\u05B4\u05D3\u05D9\u05E9\"],[\"yo\",\"Yoruba\",\"Yor\xF9b\xE1\"],[\"za\",\"Zhuang\",\"Sa\u026F
+ cue\u014B\u0185\"],[\"zh\",\"Chinese\",\"\u4E2D\u6587\"],[\"zu\",\"Zulu\",\"isiZulu\"],[\"zh-CN\",\"Chinese
+ (China)\",\"\u7B80\u4F53\u4E2D\u6587\"],[\"zh-HK\",\"Chinese (Hong Kong)\",\"\u7E41\u9AD4\u4E2D\u6587\uFF08\u9999\u6E2F\uFF09\"],[\"zh-TW\",\"Chinese
+ (Taiwan)\",\"\u7E41\u9AD4\u4E2D\u6587\uFF08\u81FA\u7063\uFF09\"],[\"zh-YUE\",\"Cantonese\",\"\u5EE3\u6771\u8A71\"],[\"ast\",\"Asturian\",\"Asturianu\"],[\"chr\",\"Cherokee\",\"\u13E3\u13B3\u13A9
+ \u13A6\u13EC\u13C2\u13AF\u13CD\u13D7\"],[\"ckb\",\"Sorani (Kurdish)\",\"\u0633\u06C6\u0631\u0627\u0646\u06CC\"],[\"cnr\",\"Montenegrin\",\"crnogorski\"],[\"csb\",\"Kashubian\",\"Kasz\xEBbsczi\"],[\"gsw\",\"Swiss
+ German\",\"Schwiizert\xFCtsch\"],[\"jbo\",\"Lojban\",\"la .lojban.\"],[\"kab\",\"Kabyle\",\"Taqbaylit\"],[\"ldn\",\"L\xE1adan\",\"L\xE1adan\"],[\"lfn\",\"Lingua
+ Franca Nova\",\"lingua franca nova\"],[\"moh\",\"Mohawk\",\"Kanien\u02BCk\xE9ha\"],[\"nds\",\"Low
+ German\",\"Plattd\xFC\xFCtsch\"],[\"pdc\",\"Pennsylvania Dutch\",\"Pennsilfaani-Deitsch\"],[\"sco\",\"Scots\",\"Scots\"],[\"sma\",\"Southern
+ Sami\",\"\xC5arjelsaemien G\xEFele\"],[\"smj\",\"Lule Sami\",\"Julevs\xE1megiella\"],[\"szl\",\"Silesian\",\"\u015Bl\u016Fnsko
+ godka\"],[\"tok\",\"Toki Pona\",\"toki pona\"],[\"vai\",\"Vai\",\"\uA559\uA524\"],[\"xal\",\"Kalmyk\",\"\u0425\u0430\u043B\u044C\u043C\u0433
+ \u043A\u0435\u043B\u043D\"],[\"zba\",\"Balaibalan\",\"\u0628\u0627\u0644\u064A\u0628\u0644\u0646\"],[\"zgh\",\"Standard
+ Moroccan Tamazight\",\"\u2D5C\u2D30\u2D4E\u2D30\u2D63\u2D49\u2D56\u2D5C\"]],\"features\":[],\"push_subscription\":null,\"role\":null}</script>\n<script
+ src=\"/packs/assets/application-BFamdUJE.js\" crossorigin=\"anonymous\" integrity=\"sha384-g/YjiCdNS7jgwfIFloEl3A54P0sTsuB5w1eKXnBmA81hhk5J0J6DjUdbVsIbEX6q\"
+ type=\"module\"></script><link rel=\"modulepreload\" href=\"/packs/index-TEHZzOO_.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-YgR2DVAuuEvYlCMAWpiv9PYSxo7USWNSFcuJzSPQPA8CKdpH0dgpfA8uszznQBqb\"><link
+ rel=\"modulepreload\" href=\"/packs/load_locale-Cgitxm3i.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-tUFP9E50Tp1krLh+79U0oE+r3GVNKo5sYdidT4OQdKz+s8Ah9wjtul7IN2qKDjSY\"><link
+ rel=\"modulepreload\" href=\"/packs/client-By3tlFYA.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-iuVa8PBvsgyFFjchLcPl5vis6x1L2AMLSKKHAPrPQA+LagYXw2W9jYTQObfUa9ds\"><link
+ rel=\"modulepreload\" href=\"/packs/useSelectableClick-BYvi7VqR.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-VLG6bKvKGJbLPVos+JirPPGYxjlF7Ix98padRMv2lqvWZMs/8kIsLnT0P25bB8+l\"><link
+ rel=\"modulepreload\" href=\"/packs/Helmet-BG0DmkIY.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-YcG+Ht3XXL5LFSS49jsDsaUFfYugKHxpH0MPhJA+lUCGW7saFSboMDqTZsPDjB3m\"><link
+ rel=\"modulepreload\" href=\"/packs/streaming-BXjhs_FD.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-hAYDdWjuWFh+UKT5XIbUr1IQ/l2hUa5Q0ElXgmDYn0H/UJoWx1fAZyl2RKOc/hZ1\"><link
+ rel=\"modulepreload\" href=\"/packs/message-CVkQtbZv.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-t7OYJQT2A/AJencsn+l5B3DyUXO/2eL7EXWK1A+A16ebF4FUu+wWfUygg68CiRBF\"><link
+ rel=\"modulepreload\" href=\"/packs/index-DkCxcZFY.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-udXsODRMSF9x4AYFOM2kqLTr/q1VuFlei3hXentTP0WRt7P+cXIXCHMLK8IPpSK2\"><link
+ rel=\"modulepreload\" href=\"/packs/onboarding-BXIEf7uI.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-hdnofZ+4BYZAlRFxc0bsDaI11jA3Rwcds0SQDOf/EMrQEl3+LiS9gSexkBmlm/bs\"><link
+ rel=\"modulepreload\" href=\"/packs/modal_container-8WXQkVja.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-ehyIPHLh+ikXPc7BqZp2uzglMRZ37XeP5q3CSKsYVSEz7f56C+A2OH97WRC0tWqG\"><link
+ rel=\"modulepreload\" href=\"/packs/status_quoted-COWx4v82.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-aWyQH2BUMuxn+TnPfaXq4BjlwhFhCSDNpOCUooxm2IDQ89T5SXWjvj4TBpat0ckD\"><link
+ rel=\"modulepreload\" href=\"/packs/short_number-C9zm8Jg6.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-3wz18HXABj8duzPCOkycoVs6MWd56WgrkuweQBqGX83tIo8A1reDTf3tML/4t4Y9\"><link
+ rel=\"modulepreload\" href=\"/packs/familiar_followers-DxpEq7S3.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-G8l25fRAmILeDqfO012P2fC/kQwkWPx7rWMm8HK4lRp/zdvQMi3tZE+RJJEOU+dZ\"><link
+ rel=\"modulepreload\" href=\"/packs/avatar_group-DgqlUJ8x.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-7bE6H1LUgUkQhAqJdxCn3w4gIIgTchhWIUi91p20V4qAvtNSFCI5CpoxBRTgbcN6\"><link
+ rel=\"modulepreload\" href=\"/packs/counters-O2iLRFgv.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-OYGumcZaNwBA4kc5TPLweJIccj/Qic+/GgIWfAR5ezVkxslfMqKMPCDs4ksBz4xh\"><link
+ rel=\"modulepreload\" href=\"/packs/follow_button-DIqb6GWd.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-RSWzpkdbkdXBOSgiaYkK02bzw/eHGocptS3NzFokjJ0OsbW69VXKhafMJJn/9xqG\"><link
+ rel=\"modulepreload\" href=\"/packs/useTimeout-BP4Egvtt.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-yymIwtNijuCITgUAS3FLgwEvfiRtnN7ubkkzEwbpdXo42GnCJ8JR2kIldN9+gIsU\"><link
+ rel=\"modulepreload\" href=\"/packs/media_modal-DBnvNnPm.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-cvi7bQFtha9KPUHC1XJ8fgKtMINXcG/jAuFo884H7w/BjD1IzBs4UioS2898hio6\"><link
+ rel=\"modulepreload\" href=\"/packs/bundle_column_error-BVGOC1je.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-muV5AjArWoo/iC+0dabXUDedoXr5t0RKIRNxPbycXGEhiJfIbAZnmCJQG4F3epEC\"><link
+ rel=\"modulepreload\" href=\"/packs/navigation_bar-BOdpvw18.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-JfIUFJ7ksCBrpy2c/bsjsIsJFGnJadhTTJLSEvtN1hfNyN4NwX4z67yZParnz/zB\"><link
+ rel=\"modulepreload\" href=\"/packs/scroll-BygYx8ga.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-jIZOX3+fCnbj97stw4XNycf0ur8+QQ918rmIdhs0BF/k3eiL1jwTf6L4DbvbAk+I\"><link
+ rel=\"modulepreload\" href=\"/packs/column_header-p8rqASZP.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-n7dXdYn2CnIE5FvuTKsFpfkammnRXhCzFBl4M0lS5fNVTrO/bgFxQ+bKiAsyaHwM\"><link
+ rel=\"modulepreload\" href=\"/packs/column-KuFpKGtG.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-S4+9ZIeZZ/okQAo4d/Ea4HlDboCQFfn0hsTKLKaUt6bvVNT4PWj1v2FZ4am70II5\"><link
+ rel=\"modulepreload\" href=\"/packs/index-CHtA0Quh.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-xO5sb1fy95DVogA7rQY1oqiRADRQEFFy2ZUv0ANHVaTqbLrxaIi+/8JAMLCq5kO9\"><link
+ rel=\"modulepreload\" href=\"/packs/server_hero_image-Bc4TNH3X.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-BCIq3ODpHuyYaOeI6roUvdlKX7lfqDu2/nJDUaKtA31VTNeUcStcLFb7vIuJh1WH\"><link
+ rel=\"modulepreload\" href=\"/packs/skeleton-CwYXpOUk.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-ZXoxMaXjYgFLH2JijKCEeiWX0OdCydlNCYuLuTu6t80eyghOltRYqw01cMmHT9U7\"><link
+ rel=\"modulepreload\" href=\"/packs/search-jNboxAdS.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-Vvxis5p77BCw9MFe8HzOYsenN4XzuAYdsGDQNonz01hY/r7Q+AD3EWeesH466abT\"><link
+ rel=\"modulepreload\" href=\"/packs/compose_form_container-CTuM2Iic.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-PEfezqEwMFbtLTyPe3sTfkwjVrdYOrIiVM2pS+lVsyDQ8tNk9MGaXJwY8Ehaqqoi\"><link
+ rel=\"modulepreload\" href=\"/packs/link_footer-DV5Raeuc.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-p+L/FO5hyM/o6iXgPPX+nxfQo1qJBgNK8NNXcxtBijaT9omv03fuNFIXQcNYgKNt\"><link
+ rel=\"modulepreload\" href=\"/packs/index-BgdWMHoM.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-if8LQHmzjRWNTn0UqW7D2nbwlNqO76v2kV/sVamh2O8HhFvzidTH3TN3fqgXHxDL\"><link
+ rel=\"modulepreload\" href=\"/packs/intl_provider-uoqkHfpw.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-qtgXcOhHvtTC+QCnsdi/Ht6PfcNmY0uOBd/n3ajlCffryN8amR4mcuNcdqfaQX9I\"><link
+ rel=\"modulepreload\" href=\"/packs/scroll_context-BQXokJOn.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-nkNQQwvDQE9r4KvOgFZPmcIDOxKBhVEs7cHNrrz1iYdgoZlVDi+wU+qGkek4bTai\"><link
+ rel=\"modulepreload\" href=\"/packs/ready-DpOgoWSg.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-22hVUedg0ViqHBSq0xZOejCiuRf00gNIUPOuN3DqhipWYIaGi2H3wdFJxpJo3ZRJ\"><link
+ rel=\"modulepreload\" href=\"/packs/relative_timestamp-BOUL06oe.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-nhFGRwYl2xmlDmzKgujmY2mT5bXTGS+5sGj1f4VO6O1bHWtfutUw0LBjI9DlmDEl\"><link
+ rel=\"modulepreload\" href=\"/packs/index-DUY7J2K7.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-AA2upUZgniO0wHTCPjsggtFkY6+fuxT9VmGm0pQo/HYjHU7u43FDMV9f3fXq1/Lj\"><link
+ rel=\"modulepreload\" href=\"/packs/api-C8Dh2R2O.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-s5a4f7jovDHX3AiqrHa0+IPOVsYNosz+iYXi2m/rpkEQdJLsIYghaZSGoiW0x/u8\"><link
+ rel=\"modulepreload\" href=\"/packs/index-DiPYjm3h.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-LRo4fOi630D7fNc/37wm94vCvC6uoOWywtEqNH4Xtpew6NWh93iXWXxTwD0Ywkdi\"><link
+ rel=\"modulepreload\" href=\"/packs/index-DCHK9s8F.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-7x/9rmsrFJl1Kc3+MA9yyIlon09shGev2MhyxckUa5Ufkbrgdx79Q/cO2z/YwoS9\"><link
+ rel=\"modulepreload\" href=\"/packs/react-textarea-autosize.browser.esm-CJKL8aJv.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-2+p+K1NHW9WG8fJ+OXQTVsB2PQwx1O6txfVWkVu4zXE7K4i0X9xIM/k8EVCVKMju\"><link
+ rel=\"modulepreload\" href=\"/packs/use-isomorphic-layout-effect.browser.esm-Du49dnA5.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-0MViW01nS/YFJh7zDrQKBMJgntJ7gibRjlcEUNx27Tc8Hcb+F61vDfnCYPBcP3O8\"><link
+ rel=\"modulepreload\" href=\"/packs/embedded_status-DyQXHDzn.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-vKFoAp5TPyMQKezrvadVaYylO/WihIjLA/HZDDuV19yDdjwrDPtGlOyouL1T6UAN\"><link
+ rel=\"modulepreload\" href=\"/packs/embedded_status_content-BkUdoobN.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-+0AOPWBDIVcuAkzEPeiAjOjReZrKjsTYkvjPFrSLWOZ42BhT4Wsn003vqi0KHIpL\"><link
+ rel=\"modulepreload\" href=\"/packs/gif-BE-9FJsW.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-q3jHMivH0HI1qpNg4PP4dLzRZsuJG48cNDA2YDfH7jFeQhZzhx5jYBaTbmn+QUTn\"><link
+ rel=\"modulepreload\" href=\"/packs/unfold_more-Dg1Ay52N.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-WUE5MOatL0b0MCFHwes/AC5FobL3DRE4z1mY/oltPxdH9SqCs38QQAu4Nu2uStp/\"><link
+ rel=\"modulepreload\" href=\"/packs/dropdown_selector-BO6B2TH1.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-VwfuUY5C2QdC34IzM6OtsgHpd8mEQcTxndIQXAFPjIexJf9/SsC0bgPpKqljTry6\"><link
+ rel=\"modulepreload\" href=\"/packs/info-onfAZF3m.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-YWL4HQL2QNbVuSu6tlrTMjHauccTq6KfboKLrU0zEwWnbIp1WEm9gBNMfLUanyq1\"><link
+ rel=\"modulepreload\" href=\"/packs/numbers-BLyy7tyF.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-cq6MiPGwO6bw4zSmQ5ZiG9fD+AXZVyalfRjO/t8k/oHS3EAnl8Oj3e3OfsA+sQBr\"><link
+ rel=\"modulepreload\" href=\"/packs/index-D_ISdKlU.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-OV5BH0NaTYqoPD77XUKHp/Mb6barjTSoimsT/yFF+y0d8rtmO0OARwUh6dmBdZeq\"><link
+ rel=\"modulepreload\" href=\"/packs/chevron_left-tY77j9LU.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-TKquuKk7fb6A7RvBGA0wVxXBpBG8jJZ7kpkw3PnPQ0dWzq+qO9fqf0aWMbGDcSCt\"><link
+ rel=\"modulepreload\" href=\"/packs/use-gesture-react.esm-DRqc-06E.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-4k2Ap+138s9MX6LXXbXyrbq6CSD4scEo3irwJVLIyOu49Og+Z04LMLqlon4/lyJc\"><link
+ rel=\"modulepreload\" href=\"/packs/add-CxOAEcXl.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-BaOg9llVhpPu4wV/PUepr1Rf1oyV3sSrwUK0+U0AZAjBsfLZ9Dfwcnq3JzRFkf20\"><link
+ rel=\"modulepreload\" href=\"/packs/home-fill-Coz6pq9r.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-k0zjCQVxMJbxWlii8xSA7r9xT1AqOE5+Cd7UAmKRmUrG3XUyDqytfLlQwQShp8Rv\"><link
+ rel=\"modulepreload\" href=\"/packs/settings-DdL_27J2.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-VZWNFIneZYCCJmwMjNrbpC6h2q4ltT57pxw1Tzjb06U+7pg0d/+v5Iba0CZj5g6J\"><link
+ rel=\"modulepreload\" href=\"/packs/notifications-By79xQr0.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-JgnFkS88W8J6spsUvKhELM8HuRN/YQwhSyQJ29vHynG56E+FdHL2CS6sxFGeeB0Y\"><link
+ rel=\"modulepreload\" href=\"/packs/notifications-CQHZPMn8.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-srveWL0Ig0hbqWtz0JAeo8jGz0YZaC8r88OOXppbOQFGF3x94bGZLjiTLRAFTs96\"><link
+ rel=\"modulepreload\" href=\"/packs/hashtags-CRafzBM6.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-a0Pi8g9yFt3+zhDCpKHYHyY4LS/m/IuMCMcvO3C/gwxpc5NMXIUmOgbe59LefDML\"><link
+ rel=\"modulepreload\" href=\"/packs/icon_with_badge-B0FOK3P8.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-Tz2xzm04AHDZokloXNkpV6tPjjRikyRmQ3coZQKY2AEmdo+gZ91aJ1TkITWWdOd+\"><link
+ rel=\"modulepreload\" href=\"/packs/verified_badge-DxL9WvZz.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-KAPykseWi1DMdYX38rYFNAtE1KWNGr2tQEcZrHwbHu4NIro2v2i67DBcI3VMeclN\"><link
+ rel=\"modulepreload\" href=\"/packs/check_box-D80X2ctM.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-CAFk353S5pd2a1hxoruurbk/mckwcu0fO64twKGoQuXHcGAWPgIwgpPrw+hbY7Ra\"><link
+ rel=\"modulepreload\" href=\"/packs/done-Bx77AbGW.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-yuGQ4E353/V65XesjP6i2UlA/0LpL6Ttsm1xx0lw9WvWvFp2eSMonuiUZ91tLGuJ\"><link
+ rel=\"modulepreload\" href=\"/packs/emoji_picker_dropdown_container-Bor6yIoQ.js\"
+ as=\"script\" crossorigin=\"anonymous\" integrity=\"sha384-v2DjwjWoG2NBTtQxDwzPldGXzYP1B0JIdpFzgYTICOgg2EwBqj3eScpwOMnPETM5\"><link
+ rel=\"modulepreload\" href=\"/packs/fuzzysort-Dw0vBoYW.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-sdNLUiMN9tEvNmLR5uTu9gF4ZkZVprkTgVhUks+dhAH0W1fRbUEjYomt2ql9xvGY\"><link
+ rel=\"modulepreload\" href=\"/packs/edit-D0aVSJLs.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-ZCrxFyfbwhLMMtcodWqkLq2rnK1MfJFeDy1nWapbWhDAdDbBsFuLnZM51AZNF1Cy\"><link
+ rel=\"modulepreload\" href=\"/packs/bookmarks-fill-BJZqYgcx.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-Kz5XfDjpSNPb1/CiwNzh7hE2jUBdmIqAWBRzuUmHe/HuJfCmO8ltAi+3j0JFK6ON\"><link
+ rel=\"modulepreload\" href=\"/packs/person_add-fill-D_R35QfA.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-YuVQqd8lKZzyX2GHX/7yuzbQ0Ztytq1c8rKtoJuG9Bl0h3oRgJva/oLirmO8xRD0\"><link
+ rel=\"modulepreload\" href=\"/packs/person_add-D-MnufZZ.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-VJQaV879O2TNVckAxq+GL08vLBUInf5694rOQKDf47KN/85+phSohgQ3F56/PGZs\"><link
+ rel=\"modulepreload\" href=\"/packs/trending_up-B8osPcfX.js\" as=\"script\"
+ crossorigin=\"anonymous\" integrity=\"sha384-h0xWXFvdpYNaWQPuhQf/SOdBwa9qf+LqYyoizaS1VFII/cJA0Xnq62saPhjCuqDa\"><link
+ rel=\"modulepreload\" href=\"/packs/tag-BoJoWhSB.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-c0BPWaM5IENcnwxMEeFWIv1+L2mg8uWIvVgdUtbF0dipbuNHo/hNYbLn8IVoHprh\"><link
+ rel=\"modulepreload\" href=\"/packs/list_alt-DxJSZxN2.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-xChZzZgaUzSLvFWlxswbhX5sCcOR0d1xfrbXBMgJP4MyN19pfiLWniDHJLrgMlIB\"><link
+ rel=\"modulepreload\" href=\"/packs/lists-Ceu3VwkD.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-kLpNlZ6QIHECt8TDvqyRgZCQSG7K4J0vD6VP0nhL4dabD7FEtcNgPEKRTk+k6r2A\"><link
+ rel=\"modulepreload\" href=\"/packs/hashtag-T8rSpi30.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-CdymHSs1jgpSEypTDkJ0EWMMZzA42NwfNMznLpuqlRI5SGWuBN15lWXC5ROhyZsK\"><link
+ rel=\"modulepreload\" href=\"/packs/index-C_3HmjFF.js\" as=\"script\" crossorigin=\"anonymous\"
+ integrity=\"sha384-r0bS8UaxERxUjiImRXDXMMF8QLDJQ1lJgL3J8DmnegY3ru5q53Jx/ZkZi9A67/k8\"><link
+ rel=\"stylesheet\" crossorigin=\"anonymous\" href=\"/packs/assets/status_quoted-BaLPn7qW.css\"
+ integrity=\"sha384-QjVZFmiWsaPUNFSMGrLB2evHpPx6TRe+Iu7u3nKrtmfgJzm3T+Orr4o43FlsfzoI\"
+ media=\"screen\" /><link rel=\"stylesheet\" crossorigin=\"anonymous\" href=\"/packs/assets/compose_form_container-D8HBmaSh.css\"
+ integrity=\"sha384-hjY308WloggahHkay1PearY31vO6kJkmW/gx9OD03gb7OE549JNJTylIBwNGUFED\"
+ media=\"screen\" />\n\n</head>\n<body class='app-body theme-mastodon-light
+ custom-scrollbars no-reduce-motion'>\n<div class='notranslate app-holder'
+ data-props='{"locale":"en"}' id='mastodon'>\n<noscript>\n<img
+ alt=\"Mastodon\" src=\"/packs/assets/logo-DXQkHAe5.svg\" />\n<div>\nTo use
+ the Mastodon web application, please enable JavaScript. Alternatively, try
+ one of the <a href=\"https://joinmastodon.org/apps\">native apps</a> for Mastodon
+ for your platform.\n</div>\n</noscript>\n</div>\n\n\n<div aria-hidden='true'
+ class='logo-resources' inert tabindex='-1'>\n<svg xmlns=\"http://www.w3.org/2000/svg\"
+ xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"79\" height=\"79\" viewBox=\"0
+ 0 79 75\"><symbol id=\"logo-symbol-icon\"><path d=\"M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1
+ 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1
+ 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9
+ 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3
+ 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9
+ 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1
+ 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7
+ 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0
+ 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9
+ 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8
+ 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z\" fill=\"currentColor\"></path></symbol><use
+ xlink:href=\"#logo-symbol-icon\"></use></svg>\n<svg xmlns=\"http://www.w3.org/2000/svg\"
+ xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"261\" height=\"66\" viewBox=\"0
+ 0 261 66\" fill=\"none\">\n<symbol id=\"logo-symbol-wordmark\"><path d=\"M60.7539
+ 14.4034C59.8143 7.41942 53.7273 1.91557 46.5117 0.849066C45.2943 0.668854
+ 40.6819 0.0130005 29.9973 0.0130005H29.9175C19.2299 0.0130005 16.937 0.668854
+ 15.7196 0.849066C8.70488 1.88602 2.29885 6.83152 0.744617 13.8982C-0.00294988
+ 17.3784 -0.0827298 21.2367 0.0561464 24.7759C0.254119 29.8514 0.292531 34.918
+ 0.753482 39.9728C1.07215 43.3305 1.62806 46.6614 2.41704 49.9406C3.89445 55.9969
+ 9.87499 61.0369 15.7344 63.0931C22.0077 65.2374 28.7542 65.5934 35.2184 64.1212C35.9295
+ 63.9558 36.6318 63.7638 37.3252 63.5451C38.8971 63.0459 40.738 62.4875 42.0913
+ 61.5067C42.1099 61.4929 42.1251 61.4751 42.1358 61.4547C42.1466 61.4342 42.1526
+ 61.4116 42.1534 61.3885V56.4903C42.153 56.4687 42.1479 56.4475 42.1383 56.4281C42.1287
+ 56.4088 42.1149 56.3918 42.0979 56.3785C42.0809 56.3652 42.0611 56.3559 42.04
+ 56.3512C42.019 56.3465 41.9971 56.3466 41.9761 56.3514C37.8345 57.3406 33.5905
+ 57.8364 29.3324 57.8286C22.0045 57.8286 20.0336 54.3514 19.4693 52.9038C19.0156
+ 51.6527 18.7275 50.3476 18.6124 49.0218C18.6112 48.9996 18.6153 48.9773 18.6243
+ 48.9569C18.6333 48.9366 18.647 48.9186 18.6643 48.9045C18.6816 48.8904 18.7019
+ 48.8805 18.7237 48.8758C18.7455 48.871 18.7681 48.8715 18.7897 48.8771C22.8622
+ 49.8595 27.037 50.3553 31.2265 50.3542C32.234 50.3542 33.2387 50.3542 34.2463
+ 50.3276C38.4598 50.2094 42.9009 49.9938 47.0465 49.1843C47.1499 49.1636 47.2534
+ 49.1459 47.342 49.1193C53.881 47.8637 60.1038 43.9227 60.7362 33.9431C60.7598
+ 33.5502 60.8189 29.8278 60.8189 29.4201C60.8218 28.0345 61.2651 19.5911 60.7539
+ 14.4034Z\" fill=\"url(#paint0_linear_89_11)\"></path>\n<path d=\"M12.3442
+ 18.3034C12.3442 16.2668 13.9777 14.6194 15.997 14.6194C18.0163 14.6194 19.6497
+ 16.2668 19.6497 18.3034C19.6497 20.34 18.0163 21.9874 15.997 21.9874C13.9777
+ 21.9874 12.3442 20.34 12.3442 18.3034Z\" fill=\"currentColor\"></path>\n<path
+ d=\"M66.1484 21.4685V38.3839H59.4988V21.9744C59.4988 18.5109 58.0583 16.7597
+ 55.1643 16.7597C51.9746 16.7597 50.3668 18.8482 50.3668 22.9603V31.9499H43.7687V22.9603C43.7687
+ 18.8352 42.1738 16.7597 38.9712 16.7597C36.0901 16.7597 34.6367 18.5109 34.6367
+ 21.9744V38.3839H28V21.4685C28 18.018 28.8746 15.268 30.6238 13.2314C32.4374
+ 11.1948 34.8039 10.157 37.7365 10.157C41.132 10.157 43.7172 11.4802 45.415
+ 14.1135L47.0742 16.9154L48.7334 14.1135C50.4311 11.4802 53.0035 10.157 56.4119
+ 10.157C59.3444 10.157 61.711 11.1948 63.5246 13.2314C65.2738 15.268 66.1484
+ 18.005 66.1484 21.4685ZM89.0297 29.8743C90.4059 28.4085 91.0619 26.5795 91.0619
+ 24.3613C91.0619 22.1431 90.4059 20.3011 89.0297 18.9001C87.7049 17.4343 86.0329
+ 16.7338 84.0007 16.7338C81.9685 16.7338 80.2965 17.4343 78.9717 18.9001C77.6469
+ 20.3011 76.991 22.1431 76.991 24.3613C76.991 26.5795 77.6469 28.4215 78.9717
+ 29.8743C80.2965 31.2753 81.9685 31.9888 84.0007 31.9888C86.0329 31.9888 87.7049
+ 31.2883 89.0297 29.8743ZM91.0619 10.8316H97.6086V37.891H91.0619V34.6999C89.0811
+ 37.3462 86.3416 38.6563 82.7788 38.6563C79.2161 38.6563 76.4765 37.3073 74.0456
+ 34.5442C71.6533 31.7812 70.4443 28.3696 70.4443 24.3743C70.4443 20.3789 71.6661
+ 17.0192 74.0456 14.2561C76.4893 11.4931 79.3833 10.0922 82.7788 10.0922C86.1744
+ 10.0922 89.0811 11.3894 91.0619 14.0356V10.8445V10.8316ZM119.654 23.8683C121.583
+ 25.3342 122.548 27.3837 122.496 29.9781C122.496 32.7411 121.532 34.9075 119.551
+ 36.4122C117.57 37.878 115.178 38.6304 112.284 38.6304C107.049 38.6304 103.499
+ 36.4641 101.621 32.1963L107.306 28.7847C108.065 31.1067 109.737 32.3001 112.284
+ 32.3001C114.625 32.3001 115.782 31.5477 115.782 29.9781C115.782 28.8366 114.265
+ 27.8118 111.165 27.0075C109.995 26.6833 109.03 26.359 108.271 26.0865C107.204
+ 25.6585 106.29 25.1655 105.532 24.5688C103.654 23.103 102.689 21.1572 102.689
+ 18.6666C102.689 16.0203 103.602 13.9059 105.429 12.3882C107.306 10.8186 109.596
+ 10.0662 112.335 10.0662C116.709 10.0662 119.898 11.9601 121.982 15.7998L116.4
+ 19.0428C115.59 17.2008 114.213 16.2798 112.335 16.2798C110.355 16.2798 109.39
+ 17.0321 109.39 18.498C109.39 19.6395 110.908 20.6643 114.008 21.4685C116.4
+ 22.0134 118.278 22.8176 119.641 23.8554L119.654 23.8683ZM140.477 17.538H134.741V28.7977C134.741
+ 30.1468 135.255 30.964 136.22 31.3402C136.927 31.6126 138.355 31.6645 140.49
+ 31.5607V37.891C136.079 38.4358 132.876 37.9948 130.998 36.5419C129.12 35.1409
+ 128.207 32.5336 128.207 28.8106V17.538H123.795V10.8316H128.207V5.37038L134.754
+ 3.25595V10.8316H140.49V17.538H140.477ZM161.352 29.7187C162.677 28.3177 163.333
+ 26.5276 163.333 24.3613C163.333 22.195 162.677 20.4178 161.352 19.0039C160.027
+ 17.6029 158.407 16.8894 156.426 16.8894C154.445 16.8894 152.825 17.5899 151.5
+ 19.0039C150.227 20.4697 149.571 22.2469 149.571 24.3613C149.571 26.4757 150.227
+ 28.2529 151.5 29.7187C152.825 31.1196 154.445 31.8331 156.426 31.8331C158.407
+ 31.8331 160.027 31.1326 161.352 29.7187ZM146.883 34.5313C144.297 31.7682 143.024
+ 28.4215 143.024 24.3613C143.024 20.3011 144.297 17.0062 146.883 14.2432C149.468
+ 11.4802 152.67 10.0792 156.426 10.0792C160.182 10.0792 163.384 11.4802 165.97
+ 14.2432C168.555 17.0062 169.88 20.4178 169.88 24.3613C169.88 28.3047 168.555
+ 31.7682 165.97 34.5313C163.384 37.2943 160.233 38.6434 156.426 38.6434C152.619
+ 38.6434 149.468 37.2943 146.883 34.5313ZM191.771 29.8743C193.095 28.4085 193.751
+ 26.5795 193.751 24.3613C193.751 22.1431 193.095 20.3011 191.771 18.9001C190.446
+ 17.4343 188.774 16.7338 186.742 16.7338C184.709 16.7338 183.037 17.4343 181.661
+ 18.9001C180.336 20.3011 179.68 22.1431 179.68 24.3613C179.68 26.5795 180.336
+ 28.4215 181.661 29.8743C183.037 31.2753 184.761 31.9888 186.742 31.9888C188.722
+ 31.9888 190.446 31.2883 191.771 29.8743ZM193.751 0H200.298V37.891H193.751V34.6999C191.822
+ 37.3462 189.082 38.6563 185.52 38.6563C181.957 38.6563 179.179 37.3073 176.735
+ 34.5442C174.343 31.7812 173.134 28.3696 173.134 24.3743C173.134 20.3789 174.356
+ 17.0192 176.735 14.2561C179.166 11.4931 182.111 10.0922 185.52 10.0922C188.928
+ 10.0922 191.822 11.3894 193.751 14.0356V0.0129719V0ZM223.308 29.7057C224.633
+ 28.3047 225.289 26.5146 225.289 24.3483C225.289 22.182 224.633 20.4048 223.308
+ 18.9909C221.983 17.5899 220.363 16.8765 218.382 16.8765C216.401 16.8765 214.78
+ 17.577 213.456 18.9909C212.182 20.4567 211.526 22.2339 211.526 24.3483C211.526
+ 26.4627 212.182 28.2399 213.456 29.7057C214.78 31.1067 216.401 31.8201 218.382
+ 31.8201C220.363 31.8201 221.983 31.1196 223.308 29.7057ZM208.838 34.5183C206.253
+ 31.7553 204.98 28.4085 204.98 24.3483C204.98 20.2881 206.253 16.9932 208.838
+ 14.2302C211.424 11.4672 214.626 10.0662 218.382 10.0662C222.137 10.0662 225.34
+ 11.4672 227.925 14.2302C230.511 16.9932 231.835 20.4048 231.835 24.3483C231.835
+ 28.2918 230.511 31.7553 227.925 34.5183C225.34 37.2813 222.189 38.6304 218.382
+ 38.6304C214.575 38.6304 211.424 37.2813 208.838 34.5183ZM260.17 21.261V37.878H253.623V22.1301C253.623
+ 20.34 253.173 18.9909 252.247 17.9661C251.385 17.0451 250.164 16.5651 248.594
+ 16.5651C244.89 16.5651 243.012 18.7833 243.012 23.2716V37.878H236.466V10.8316H243.012V13.867C244.581
+ 11.3245 247.077 10.0792 250.575 10.0792C253.366 10.0792 255.656 11.0521 257.431
+ 13.0498C259.257 15.0474 260.17 17.7586 260.17 21.274\" fill=\"currentColor\"></path>\n<defs>\n<linearGradient
+ id=\"paint0_linear_89_11\" x1=\"30.5\" y1=\"0.0130005\" x2=\"30.5\" y2=\"65.013\"
+ gradientUnits=\"userSpaceOnUse\">\n<stop stop-color=\"#6364FF\"></stop>\n<stop
+ offset=\"1\" stop-color=\"#563ACC\"></stop>\n</linearGradient>\n</defs></symbol><use
+ xlink:href=\"#logo-symbol-wordmark\"></use>\n</svg>\n</div>\n</body>\n</html>\n"
+ headers:
+ Connection:
+ - close
+ Content-Length:
+ - '35825'
+ Content-Type:
+ - text/html; charset=utf-8
+ Date:
+ - Tue, 31 Mar 2026 18:28:40 GMT
+ Strict-Transport-Security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ Vary:
+ - Accept-Encoding
+ - Accept, Accept-Language, Cookie
+ cache-control:
+ - max-age=15, public, stale-while-revalidate=30, stale-if-error=86400
+ content-security-policy:
+ - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
+ ''self'' https://social.alexwlchan.net; img-src ''self'' data: blob: https://social.alexwlchan.net
+ https://cdn.masto.host; media-src ''self'' data: https://social.alexwlchan.net
+ https://cdn.masto.host; manifest-src ''self'' https://social.alexwlchan.net;
+ form-action ''none''; child-src ''self'' blob: https://social.alexwlchan.net;
+ worker-src ''self'' blob: https://social.alexwlchan.net; connect-src ''self''
+ data: blob: https://social.alexwlchan.net https://cdn.masto.host wss://social.alexwlchan.net;
+ script-src ''self'' https://social.alexwlchan.net ''wasm-unsafe-eval''; frame-src
+ ''self'' https:; style-src ''self'' https://social.alexwlchan.net ''nonce-XkCHQQX3C3RpkX/PbOM/9Q=='''
+ etag:
+ - W/"d1d0fd4facd88acdd8c10381703c9feb"
+ referrer-policy:
+ - same-origin
+ server:
+ - Mastodon
+ strict-transport-security:
+ - max-age=63072000; includeSubDomains
+ - max-age=31536000
+ vary:
+ - Accept-Encoding
+ - Accept, Accept-Language, Cookie
+ x-content-type-options:
+ - nosniff
+ x-frame-options:
+ - DENY
+ x-request-id:
+ - ae24e495-76fa-4e9d-a16e-5ed8453bca11
+ x-runtime:
+ - '0.013862'
+ x-xss-protection:
+ - '0'
+ status:
+ code: 200
+ message: OK
+version: 1
tests/test_urls.py (4358) → tests/test_urls.py (5594)
diff --git a/tests/test_urls.py b/tests/test_urls.py
index 4fdb2bd..12151b7 100644
--- a/tests/test_urls.py
+++ b/tests/test_urls.py
@@ -41,22 +41,31 @@ def test_clean_youtube_url(url: str, cleaned_url: str) -> None:
@pytest.mark.parametrize(
"url, server, acct, post_id",
[
- (
+ pytest.param(
"https://iconfactory.world/@Iconfactory/115650922400392083",
"iconfactory.world",
"Iconfactory",
"115650922400392083",
+ id="iconfactory",
),
- (
+ pytest.param(
"https://social.alexwlchan.net/@chris__martin@functional.cafe/113369395383537892",
"functional.cafe",
"chris__martin",
- "113369395383537892",
+ "113369395366414375",
+ id="alexwlchan_redirect",
+ ),
+ pytest.param(
+ "https://social.alexwlchan.net/@alex/116300317590482708",
+ "social.alexwlchan.net",
+ "alex",
+ "116300317590482708",
+ id="alexwlchan_self",
),
],
)
def test_parse_mastodon_post_url(
- url: str, server: str, acct: str, post_id: str
+ vcr_cassette: Cassette, url: str, server: str, acct: str, post_id: str
) -> None:
"""
Mastodon post URLs are parsed correctly.
@@ -67,13 +76,32 @@ def test_parse_mastodon_post_url(
@pytest.mark.parametrize(
"url, error",
[
- ("https://mastodon.social/", "Cannot parse Mastodon URL"),
- ("https://mastodon.social/about", "Cannot parse Mastodon URL"),
- ("https://mastodon.social/about/subdir", "Cannot find `acct`"),
- ("https://mastodon.social/@example/about", "Mastodon post ID is not numeric"),
+ pytest.param(
+ "https://mastodon.social/", "Cannot parse Mastodon URL", id="no_path"
+ ),
+ pytest.param(
+ "https://mastodon.social/about",
+ "Cannot parse Mastodon URL",
+ id="no_post_id",
+ ),
+ pytest.param(
+ "https://mastodon.social/about/subdir", "Cannot find `acct`", id="no_acct"
+ ),
+ pytest.param(
+ "https://mastodon.social/@example/about",
+ "Mastodon post ID is not numeric",
+ id="non_numeric_post_id",
+ ),
+ pytest.param(
+ "https://social.alexwlchan.net/@does@not.exist/123",
+ "Cannot parse Mastodon URL",
+ id="alexwlchan_does_not_exist",
+ ),
],
)
-def test_parse_mastodon_post_url_errors(url: str, error: str) -> None:
+def test_parse_mastodon_post_url_errors(
+ vcr_cassette: Cassette, url: str, error: str
+) -> None:
"""
parse_mastodon_post_url returns a useful error if it can't parse the URL.
"""
@@ -103,6 +131,23 @@ def test_parse_tumblr_post_url(url: str, blog_identifier: str, post_id: str) ->
assert parse_tumblr_post_url(url) == (blog_identifier, post_id)
+@pytest.mark.parametrize(
+ "url",
+ [
+ "https://www.tumblr.com/",
+ "https://www.tumblr.com/staff/",
+ "https://staff.tumblr.com/",
+ "https://www.example.com/",
+ ],
+)
+def test_parse_bad_tumblr_url(url: str) -> None:
+ """
+ Parsing a non-Tumblr URL throws a ValueError.
+ """
+ with pytest.raises(ValueError, match="Cannot parse Tumblr URL"):
+ parse_tumblr_post_url(url)
+
+
class TestIsMastodonHost:
"""
Tests for `is_mastodon_host`.