$def with (url, details, audits, a11y, manifest) $ short_title = str(url).removeprefix("@").removeprefix("https://") $# var title = short_title $ axes = ["identity", "authentication", "posts", "syndication", "posting UI", $ "navigation", "search", "aggregation", "interactivity", "security", $ "responses"] $ statuses = ["pass", "maybe", "fail"] $def render_uninterpreted(title, object, type):
microformats logo

Uninterpreted $title $type:

$for key, values in sorted(object.items()):
$key
$if not isinstance(values, list): $ values = [values] $for value in values:
$if type == "links": $uri(value).minimized $elif type == "properties": $value
$ card = details["card"] $if featured := card.pop("featured", [None])[0]: $ all_urls = [] $ rels = details["mf2json"]["rels"] $ meta_props = {} $ items = details["mf2json"]["items"] $if items and items[-1]["source"] == "metaformats": $ meta_props = items[-1]["properties"]
$ name = card.pop("name", [None])[0] $if name: $var title = name $elif meta_name := meta_props.get("name"): $var title = meta_name[0]

$if details["domain"]["hsts"]: https:// $elif url.scheme == "https": https:// $else: http:// $details["domain"]["name"] $if "metaverse" in details: $ hash = details["metaverse"][:5] $hash

Accessed $details["accessed"]

$ response = details["response"] $response["length"] KB $if audits: / $get_human_size(audits["audits"]["total-byte-weight"]["numericValue"]) / $if response["time"] < 1: $round(response["time"] * 1000) ms $else: $round(response["time"], 2) s

$ urls = [] $ web_sign_in = [] $if card:
$# XXX $var title: $:name $ card.pop("family-name", None) $ card.pop("given-name", None) $ nicknames = card.pop("nickname", []) $ orgs = card.pop("org", None) $if photo := card.pop("photo", None): $name's profile picture $# XXX

$name

$ ipa = card.pop("ipa", None) $ sound = card.pop("sound", None)

$if ipa: $ipa[0] $if sound:

$if nicknames:

a.k.a. $", ".join(nicknames)

$ pronouns = card.pop("pronouns", []) $ card.pop("pronoun", None) $if orgs and name == orgs[0]: 🧑‍🤝‍🧑 $elif pronouns: $if "they" in pronouns[0]: 🧑 $elif "she" in pronouns[0]: 👩 $elif "he" in pronouns[0]: 👨 $else: 🧑 $if pronouns: $:pronouns[0].replace(" ", "").replace("/", " / ") $elif pronouns := card.pop("pronoun", None): $for pronoun in pronouns: $pronoun\ $if not loop.last:  / \ $if bday := card.pop("bday", None): $ year, month, day = re.match("(\d\d\d\d|-)-(\d\d?|-)-(\d\d?|-)", bday[0]).groups() $if year != "-": $ year = int(year) $ month = int(month) $ day = int(day) $ months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"] $ months += ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] $ n = now() 🎂 $if "rel_me" in details: $ details["rel_me"] = details["rels"].pop("me", []) # TODO REMOVE $ urls = set(uri(u).minimized for u in card.pop("url", []) + details["rel_me"]) $ reciprocals = set(details.pop("reciprocals", [])) $ self_rel_me = f"indieweb.rocks/{url.minimized}" $if self_rel_me in reciprocals: $ urls.discard(self_rel_me) $ reciprocals.discard(self_rel_me) 🍄 $if orgs:
🧑‍🤝‍🧑 $for org in orgs: $if isinstance(org, dict): $ org_props = org.pop("properties") $if "url" in org_props: \ $org_props["name"][0]\ $if "url" in org_props: \ $else: $org\ $if not loop.last: , $if roles := card.pop("role", None):
$for role in roles: $role\ $if not loop.last: , $if note := card.pop("note", None):

$note[0]

$if categories := card.pop("category", None):

🏷ī¸ $for category in categories: \ $if isinstance(category, dict): $ cat_props = category.pop("properties") $if "url" in cat_props: \ $cat_props["name"][0]\ $if "url" in cat_props: \ $else: $category\ \ $if not loop.last: ,

$ street_address = card.pop("street-address", None) $ locality = card.pop("locality", None) $ region = card.pop("region", None) $ postal_code = card.pop("postal-code", None) $ country_name = card.pop("country-name", None) $if street_address:

📍 $if street_address: $street_address[0] $ area_line = [] $if locality: $ area_line.append(locality[0]) $if region: $ area_line.append(region[0]) $", ".join(area_line) $if postal_code: $postal_code[0] $if country_name: $country_name[0]

$ emails = [e.partition(":")[2] for e in card.pop("email", [])] $ tels = [] $for tel in card.pop("tel", []): $if ":" in tel: $tels.append(tel.partition(":")[2]) $else: $tels.append(tel) $ keys = set(card.pop("key", []) + rels.pop("pgpkey", [])) $ all_urls = list(urls) $for _url in sorted(urls): $if _url.startswith("sms:") or _url.startswith("callto:"): $ tel = _url.partition(":")[2] $if tel not in tels: $ tels.append(tel) $urls.remove(_url) $elif _url.startswith("mailto:"): $ email = _url.partition(":")[2] $if email not in emails: $ emails.append(email) $urls.remove(_url) $if emails: $if tels: $if keys:

🔐 $for key in keys: $key $if not loop.last: , $ web_sign_in.append(uri(key).minimized)

$def render_rel_me(silo_name, domain, profile_pattern, user): $ path = re.sub(r"(\(.+\))", user, profile_pattern).replace("\\", "") $user $ supported_web_signin_silos = ["github.com", "twitter.com"] $if urls: $for _url in sorted(urls): $if _url.startswith(url.minimized): $ urls.remove(_url) $continue $ card.pop("uid", None) # FIXME: what is it good for? $if card: $:render_uninterpreted("h-card", card, "properties")
$if payments := rels.pop("payment", None):

Payment

$else: $if meta_props: $if meta_photo := meta_props.get("photo"):
$if meta_summary := meta_props.get("summary"):

$meta_summary[0]

$if meta_content := meta_props.get("content"):
$meta_content[0]

No representative card found. $if meta_props: Falling back to metaformats.

$ license = rels.pop("license", None) $if license:

$if cc := re.match(r"https://creativecommons.org/licenses/([a-z-]+)/(\d.\d)", license[0]): $ license, version = cc.groups() Creative Commons logo\ $for part in license.split("-"): Creative Commons $(part) license logo\ $else: Licensed $license[0].

$if "search_url" in details: $ search_url, search_query_name = details["search_url"]
$ rels.pop("search") $if manifest: $ bgcolor = manifest.get("background_color", "none")
$ auth_ep = rels.pop("authorization_endpoint", None) $ token_ep = rels.pop("token_endpoint", None) $ ticket_ep = None $ indieauth_metadata = details.pop("indieauth_metadata", None) $ openid_delegate = rels.pop("openid.delegate", None) $ openid_server = rels.pop("openid.server", None) $if indieauth_metadata: $ auth_ep = indieauth_metadata.get("authorization_endpoint", None) $ token_ep = indieauth_metadata.get("token_endpoint", None) $ ticket_ep = indieauth_metadata.get("ticket_endpoint", None) $if auth_ep:

Supports $else:

Does not support IndieAuth\ $if auth_ep: $if token_ep: with a token endpoint\ $if ticket_ep: and a ticket endpoint\ .

$# $if auth_ep and not indieauth_metadata: $#

rel=authorization_endpoint is deprecated, leave $# it for now but start using rel=indieauth-metadata instead $# read more

$ authn = [uri(authn).minimized for authn in rels.pop("authn", [])] $if web_sign_in:

Supports web sign-in.

$# $if openid_delegate and openid_server: $#

OpenID was a protocol for using a web address $# as an identity to sign-in to websites; it is losing support, is $# effectively dead (versions 1 & 2 are both deprecated, sites are $# dropping support), and has been replaced on the IndieWeb with $# web-sign-in and IndieAuth. read more

$ webmention_ep = rels.pop("webmention", None) $if webmention_ep:

Supports $else:

Does not support Webmention on the homepage.

$ micropub_ep = rels.pop("micropub", None) $ media_ep = rels.pop("media-endpoint", None) $if micropub_ep:

Supports $else:

Does not support Micropub\ $if micropub_ep and media_ep: with a media endpoint\ .

$ microsub_ep = rels.pop("microsub", None) $if microsub_ep:

Supports $else:

Does not support Microsub.

$ dependencies = [] $#details.pop("stylesheets") $# $for stylesheet in details.pop("stylesheets"): $# $if not stylesheet.startswith(url.normalized): $# $ dependencies.append(stylesheet) $# $for script in details.pop("scripts"): $# $if "src" in script: $# $if not script["src"].startswith(url.normalized): $# $ dependencies.append(script["src"]) $#

Media

$# $#

Stylesheets

$# $if details["stylesheets"]: $#
    $# $for stylesheet in details["stylesheets"]: $#
  1. $uri(stylesheet).normalized
  2. $#
$# $else: $#

No external stylesheets.

$# $# TODO inline stylesheets $# $#

Scripts

$# $ scripts = details.pop("scripts") $# $if scripts: $# $# $# $else: $#

No scripting.

$# $#

Images/Audio/Video

$#

...

Privacy

$ dns_prefetches = rels.pop("dns-prefetch", None) $ preconnects = rels.pop("preconnect", None) $if dns_prefetches or preconnects: $if dns_prefetches: $ dependencies.extend(dns_prefetches)
DNS Prefetch
    $for dns_prefetch in dns_prefetches:
  1. $dns_prefetch
$if preconnects: $ dependencies.extend(preconnects)
Preconnect
    $for preconnect in preconnects:
  1. $preconnect
$if dependencies:

This site has external dependencies.

$else:

This site is truly independent.

Accessibility

$if a11y:

$len(a11y) accessibility concerns.

$else:

There are no accessibility concerns.

$if feed := details.pop("feed", None): $if feed["items"]:
$for entry in feed["items"]: $#
$pformat(entry)
$# $if details["whostyle"]: $# $if rel_next := rels.pop("next", None):

next: $rel_next[0]

$if rel_prev := rels.pop("prev", None):

previous: $rel_prev[0]

$else:

No content feed available.

$if scores := details.get("scores"):
$def list_reasons(level):

Level 1: Use your domain for identity, sign-in, and publishing posts

$:list_reasons(1)

Level 2: Improve your personal identity and post multiple types of posts

$:list_reasons(2)

Level 3: Post and send replies from your own site

$:list_reasons(3)

Level 4: Receive and show comments

$:list_reasons(4)

Level 5: Manage comments

$:list_reasons(5)
$if rels: $:render_uninterpreted("rel=", rels, "links")