Code and data for arewedecentralizedyet.online and related projects
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Script for fetching geo information for the networks

For now, it's only really intended to be used with the social networks,
but it might be expandable to some of the others

+764
+32
data-fetchers/geo/at-host-overrides.json
··· 1 + { 2 + "blacksky.app": { 3 + "name": "Blacksky", 4 + "color": "#000000", 5 + "icon": "data-static/icons/blacksky.png", 6 + "type": "Blacksky" 7 + }, 8 + "northsky.social": { 9 + "name": "Northsky", 10 + "color": "#3FFFA8", 11 + "icon": "data-static/icons/northsky.png", 12 + "type": "northsky" 13 + }, 14 + "tngl.sh": { 15 + "name": "Tangled", 16 + "color": "#FFFFFF", 17 + "icon": "data-static/icons/tangled.png", 18 + "type": "tangled" 19 + }, 20 + "atproto.brid.gy": { 21 + "name": "Bridgy", 22 + "color": "#FFFFFF", 23 + "icon": "data-static/icons/bridgy.png", 24 + "type": "bridgy-fed" 25 + }, 26 + "at.app.wafrn.net": { 27 + "name": "Wafrn", 28 + "color": "#28B8F8", 29 + "icon": "data-static/icons/wafrn.png", 30 + "type": "wafrn" 31 + } 32 + }
+20
data-fetchers/geo/fedi-host-overrides.json
··· 1 + { 2 + "mastodon.social": { 3 + "city": "Falkenstein", 4 + "country": "DE", 5 + "lat": 50.4777, 6 + "lon": 12.3649, 7 + "network": "Hetzner Online GmbH", 8 + "cdn": false, 9 + "anycast": false 10 + }, 11 + "mastodon.online": { 12 + "city": "Falkenstein", 13 + "country": "DE", 14 + "lat": 50.4777, 15 + "lon": 12.3649, 16 + "network": "Hetzner Online GmbH", 17 + "cdn": false, 18 + "anycast": false 19 + } 20 + }
+546
data-fetchers/geo/fetch-geo-hosts.py
··· 1 + #!/usr/bin/env python3 2 + 3 + import argparse 4 + import asyncio 5 + import csv 6 + import json 7 + import os 8 + import socket 9 + import tarfile 10 + from pathlib import Path 11 + 12 + try: 13 + import ipinfo 14 + except ImportError as exc: 15 + raise SystemExit( 16 + "Missing dependency: ipinfo. Install with `pip install ipinfo`." 17 + ) from exc 18 + 19 + 20 + REPO_ROOT = Path(__file__).resolve().parents[2] 21 + DATA_DIR = REPO_ROOT / "data" 22 + ICON_DIR = Path("data-static") / "icons" 23 + 24 + AT_BSKY_STYLE = { 25 + "color": "#1185FE", 26 + "icon": str(ICON_DIR / "bluesky.png"), 27 + "type": "bluesky", 28 + } 29 + 30 + AT_PROTO_STYLE = { 31 + "color": "#CBD5E1", 32 + "icon": str(ICON_DIR / "atproto.png"), 33 + "type": "atmosphere", 34 + } 35 + 36 + AT_TYPE_STYLE = { 37 + "bridgy-fed": { 38 + "name": "Bridgy", 39 + "color": "#FFFFFF", 40 + "icon": str(ICON_DIR / "bridgy.png"), 41 + "type": "bridgy-fed", 42 + }, 43 + } 44 + 45 + AT_HOST_TYPES = { 46 + "atproto.brid.gy": "bridgy-fed", 47 + } 48 + 49 + FEDI_SOFTWARE_STYLE = { 50 + "ghost": {"color": "#E5E7EB", "icon": str(ICON_DIR / "ghost.png")}, 51 + "mastodon": {"color": "#6364FF", "icon": str(ICON_DIR / "mastodon.png")}, 52 + "wordpress": {"color": "#21759B", "icon": str(ICON_DIR / "wordpress.png")}, 53 + "peertube": {"color": "#F1680D", "icon": str(ICON_DIR / "peertube.png")}, 54 + "lemmy": {"color": "#FFFFFF", "icon": str(ICON_DIR / "lemmy.png")}, 55 + "pixelfed": {"color": "#00A86B", "icon": str(ICON_DIR / "pixelfed.png")}, 56 + "pleroma": {"color": "#8B5CF6", "icon": str(ICON_DIR / "pleroma.png")}, 57 + "friendica": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 58 + "akkoma": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 59 + "owncast": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 60 + "bookwyrm": {"color": "#F8F8F8", "icon": str(ICON_DIR / "bookwyrm.png")}, 61 + "hometown": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 62 + "iceshrimp.net": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 63 + "hubzilla": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 64 + "writefreely": {"color": "#9CA3AF", "icon": str(ICON_DIR / "fediverse.png")}, 65 + "wafrn": {"color": "#28B8F8", "icon": str(ICON_DIR / "wafrn.png")}, 66 + } 67 + 68 + FEDI_DEFAULT_STYLE = { 69 + "color": "#000000", 70 + "icon": str(ICON_DIR / "fediverse.png"), 71 + } 72 + 73 + 74 + def latest_csv_path(dir_path: Path) -> Path: 75 + csv_paths = [ 76 + path for path in dir_path.glob("*.csv") 77 + ] 78 + if not csv_paths: 79 + raise FileNotFoundError(f"No CSV files found in {dir_path}") 80 + return max(csv_paths, key=lambda path: path.stat().st_mtime) 81 + 82 + 83 + def load_hosts(source: str) -> tuple[Path, list[dict]]: 84 + if source == "fedi-mau": 85 + csv_path = latest_csv_path(DATA_DIR / "fedi-mau") 86 + with csv_path.open(newline="", encoding="utf-8") as f: 87 + reader = csv.DictReader(f) 88 + rows = [ 89 + { 90 + "hostname": row["hostname"].strip(), 91 + "users": int(row["active_month"] or 0), 92 + "software": (row.get("software") or "").strip(), 93 + } 94 + for row in reader 95 + if row.get("hostname") 96 + ] 97 + elif source == "at-mau": 98 + csv_path = latest_csv_path(DATA_DIR / "at-mau") 99 + with csv_path.open(newline="", encoding="utf-8") as f: 100 + reader = csv.DictReader(f) 101 + rows = [ 102 + {"hostname": row["domain"].strip(), "users": int(row["mau"] or 0)} 103 + for row in reader 104 + if row.get("domain") 105 + ] 106 + else: 107 + raise ValueError(f"Unsupported source: {source}") 108 + 109 + return csv_path, rows 110 + 111 + 112 + def load_at_overrides(path: Path) -> dict: 113 + if not path.exists(): 114 + return {} 115 + try: 116 + with path.open(encoding="utf-8") as f: 117 + data = json.load(f) 118 + except json.JSONDecodeError as exc: 119 + raise ValueError(f"Invalid JSON in overrides file: {path}") from exc 120 + if not isinstance(data, dict): 121 + raise ValueError("Overrides JSON must be an object keyed by hostname") 122 + return data 123 + 124 + 125 + def load_fedi_overrides(path: Path) -> dict: 126 + if not path.exists(): 127 + return {} 128 + try: 129 + with path.open(encoding="utf-8") as f: 130 + data = json.load(f) 131 + except json.JSONDecodeError as exc: 132 + raise ValueError(f"Invalid JSON in fedi overrides file: {path}") from exc 133 + if not isinstance(data, dict): 134 + raise ValueError("Fedi overrides JSON must be an object keyed by hostname") 135 + return data 136 + 137 + 138 + def load_ipinfo_token(config_path: Path) -> str | None: 139 + if not config_path.exists(): 140 + return None 141 + try: 142 + with config_path.open(encoding="utf-8") as f: 143 + data = json.load(f) 144 + except json.JSONDecodeError as exc: 145 + raise ValueError(f"Invalid JSON in ipinfo config: {config_path}") from exc 146 + if not isinstance(data, dict): 147 + raise ValueError("ipinfo config must be a JSON object") 148 + token = data.get("token") 149 + if token: 150 + return str(token) 151 + return None 152 + 153 + 154 + def get_detail_field(details, name: str): 155 + if isinstance(details, dict): 156 + return details.get(name) 157 + return getattr(details, name, None) 158 + 159 + 160 + def normalize_details(details) -> dict: 161 + if isinstance(details, dict): 162 + return details 163 + all_field = getattr(details, "all", None) 164 + if isinstance(all_field, dict): 165 + return all_field 166 + if hasattr(details, "__dict__"): 167 + return {k: v for k, v in vars(details).items() if not k.startswith("_")} 168 + return {} 169 + 170 + 171 + def load_cache(cache_path: Path) -> dict: 172 + if not cache_path.exists(): 173 + return {} 174 + try: 175 + with cache_path.open(encoding="utf-8") as f: 176 + data = json.load(f) 177 + except json.JSONDecodeError as exc: 178 + raise ValueError(f"Invalid JSON in cache file: {cache_path}") from exc 179 + if not isinstance(data, dict): 180 + raise ValueError("Cache file must be a JSON object keyed by IP") 181 + return data 182 + 183 + 184 + def extract_network(details) -> str | None: 185 + org = get_detail_field(details, "org") 186 + if org: 187 + return org 188 + asn = get_detail_field(details, "asn") 189 + if isinstance(asn, dict): 190 + return asn.get("name") 191 + return getattr(asn, "name", None) 192 + 193 + 194 + def extract_lat_lon(details) -> tuple[float | None, float | None]: 195 + loc = get_detail_field(details, "loc") 196 + if not loc or "," not in loc: 197 + return None, None 198 + lat_str, lon_str = loc.split(",", 1) 199 + try: 200 + return float(lat_str), float(lon_str) 201 + except ValueError: 202 + return None, None 203 + 204 + 205 + def is_cdn(details) -> bool: 206 + org = get_detail_field(details, "org") 207 + asn = get_detail_field(details, "asn") 208 + asn_domain = None 209 + if isinstance(asn, dict): 210 + asn_domain = asn.get("domain") 211 + asn_name = asn.get("name") 212 + else: 213 + asn_name = None 214 + 215 + haystacks = [ 216 + s.lower() 217 + for s in [ 218 + org, 219 + asn_domain, 220 + asn_name, 221 + ] 222 + if s 223 + ] 224 + cdn_markers = [ 225 + "akamai", 226 + "akamaiedge", 227 + "akamaitechnologies", 228 + "amazonaws", 229 + "cdn", 230 + "cloudflare", 231 + "cloudfront", 232 + "edgesuite", 233 + "fastly", 234 + "gcore", 235 + "googleusercontent", 236 + "google", 237 + "stackpath", 238 + "stackpathdns", 239 + ] 240 + return any(any(marker in s for marker in cdn_markers) for s in haystacks) 241 + 242 + 243 + async def resolve_hostnames( 244 + hostnames: list[str], 245 + dns_cache: dict, 246 + progress_every: int = 200, 247 + ) -> tuple[dict, dict]: 248 + hostname_to_ip: dict[str, str] = {} 249 + ip_to_hosts: dict[str, list[str]] = {} 250 + sem = asyncio.Semaphore(200) 251 + lock = asyncio.Lock() 252 + completed = 0 253 + total = len(hostnames) 254 + 255 + for hostname in hostnames: 256 + cached_ip = dns_cache.get(hostname) 257 + if cached_ip: 258 + hostname_to_ip[hostname] = cached_ip 259 + ip_to_hosts.setdefault(cached_ip, []).append(hostname) 260 + completed += 1 261 + 262 + async def resolve(hostname: str) -> None: 263 + nonlocal completed 264 + async with sem: 265 + try: 266 + infos = await asyncio.get_running_loop().getaddrinfo( 267 + hostname, None, proto=socket.IPPROTO_TCP 268 + ) 269 + except socket.gaierror: 270 + infos = None 271 + ip = None 272 + if infos: 273 + for family, _, _, _, sockaddr in infos: 274 + if family == socket.AF_INET: 275 + ip = sockaddr[0] 276 + break 277 + if not ip: 278 + ip = infos[0][4][0] 279 + if ip: 280 + hostname_to_ip[hostname] = ip 281 + ip_to_hosts.setdefault(ip, []).append(hostname) 282 + dns_cache[hostname] = ip 283 + async with lock: 284 + completed += 1 285 + if progress_every and completed % progress_every == 0: 286 + print(f"Resolved {completed}/{total} hostnames") 287 + 288 + unresolved = [h for h in hostnames if h not in hostname_to_ip] 289 + await asyncio.gather(*(resolve(host) for host in unresolved)) 290 + return hostname_to_ip, ip_to_hosts 291 + 292 + 293 + def main() -> int: 294 + parser = argparse.ArgumentParser( 295 + description="Generate geocoded host summary JSON from the latest MAU CSV." 296 + ) 297 + parser.add_argument("source", choices=["fedi-mau", "at-mau"]) 298 + parser.add_argument( 299 + "-o", 300 + "--output", 301 + help="Output JSON path (default: data/<source>-geo.json)", 302 + ) 303 + parser.add_argument( 304 + "--token", 305 + help="IPinfo access token (default: let ipinfo resolve from env/config)", 306 + ) 307 + parser.add_argument( 308 + "--at-overrides", 309 + default=str(REPO_ROOT / "data-fetchers/geo/at-host-overrides.json"), 310 + help="Overrides JSON keyed by hostname for at-mau (default: data-fetchers/geo/at-host-overrides.json)", 311 + ) 312 + parser.add_argument( 313 + "--fedi-overrides", 314 + default=str(REPO_ROOT / "data-fetchers/geo/fedi-host-overrides.json"), 315 + help="Overrides JSON keyed by hostname for fedi-mau (default: data-fetchers/geo/fedi-host-overrides.json)", 316 + ) 317 + parser.add_argument( 318 + "--tarball", 319 + help="Optional tar.gz output including JSON and referenced icons", 320 + ) 321 + parser.add_argument( 322 + "--debug", 323 + action="store_true", 324 + help="Print debug information about DNS and ipinfo responses", 325 + ) 326 + parser.add_argument( 327 + "--limit", 328 + type=int, 329 + help="Limit number of hosts processed (for testing)", 330 + ) 331 + parser.add_argument( 332 + "--cache", 333 + default=str(DATA_DIR / "cache/ipinfo-cache.json"), 334 + help="Path to IPinfo cache JSON (default: data/cache/ipinfo-cache.json)", 335 + ) 336 + parser.add_argument( 337 + "--dns-cache", 338 + default=str(DATA_DIR / "cache/dns-cache.json"), 339 + help="Path to DNS cache JSON (default: data/cache/dns-cache.json)", 340 + ) 341 + args = parser.parse_args() 342 + 343 + csv_path, hosts = load_hosts(args.source) 344 + if args.limit is not None: 345 + hosts = hosts[: max(args.limit, 0)] 346 + 347 + output_path = ( 348 + Path(args.output) 349 + if args.output 350 + else DATA_DIR / f"geo/{args.source}-geo.json" 351 + ) 352 + 353 + token = args.token 354 + if not token: 355 + token = load_ipinfo_token(Path("~/.config/ipinfo/config.json").expanduser()) 356 + handler = ipinfo.getHandler(token) if token else ipinfo.getHandler() 357 + at_overrides = ( 358 + load_at_overrides(Path(args.at_overrides)) 359 + if args.source == "at-mau" 360 + else {} 361 + ) 362 + fedi_overrides = ( 363 + load_fedi_overrides(Path(args.fedi_overrides)) 364 + if args.source == "fedi-mau" 365 + else {} 366 + ) 367 + 368 + cache_path = Path(args.cache) 369 + cache = load_cache(cache_path) 370 + dns_cache_path = Path(args.dns_cache) 371 + dns_cache = load_cache(dns_cache_path) 372 + 373 + hostnames = [entry["hostname"] for entry in hosts] 374 + details_by_ip: dict[str, object] = {} 375 + details_by_host: dict[str, object] = {} 376 + batch_size = 1000 377 + 378 + hostname_to_ip, ip_to_hosts = asyncio.run( 379 + resolve_hostnames(hostnames, dns_cache) 380 + ) 381 + if args.debug: 382 + unresolved = [h for h in hostnames if h not in hostname_to_ip] 383 + print(f"Resolved {len(hostname_to_ip)}/{len(hostnames)} hostnames to IPs") 384 + if unresolved: 385 + sample = ", ".join(unresolved[:10]) 386 + print(f"Sample unresolved hostnames: {sample}") 387 + for ip, detail in cache.items(): 388 + details_by_ip[ip] = detail 389 + for hostname in ip_to_hosts.get(ip, []): 390 + details_by_host[hostname] = detail 391 + 392 + targets = [ip for ip in ip_to_hosts.keys() if ip not in cache] 393 + target_label = "IPs" 394 + 395 + for i in range(0, len(targets), batch_size): 396 + batch = targets[i : i + batch_size] 397 + batch_num = i // batch_size + 1 398 + batch_total = (len(targets) + batch_size - 1) // batch_size 399 + print( 400 + f"Looking up ipinfo batch {batch_num}/{batch_total} ({len(batch)} {target_label})" 401 + ) 402 + try: 403 + batch_details = handler.getBatchDetails(batch) 404 + except Exception as exc: 405 + print(f"Warning: ipinfo batch lookup failed: {exc}") 406 + batch_details = {} 407 + 408 + def item_field(item, name: str): 409 + if isinstance(item, dict): 410 + return item.get(name) 411 + return getattr(item, name, None) 412 + 413 + def store_detail(key: str, detail: object) -> None: 414 + normalized = normalize_details(detail) 415 + details_by_ip[key] = normalized 416 + for hostname in ip_to_hosts.get(key, []): 417 + details_by_host[hostname] = normalized 418 + cache[key] = normalized 419 + 420 + if isinstance(batch_details, dict): 421 + for key, detail in batch_details.items(): 422 + if key: 423 + store_detail(key, detail) 424 + elif isinstance(batch_details, list): 425 + for item in batch_details: 426 + key = ( 427 + item_field(item, "ip") 428 + or item_field(item, "query") 429 + or item_field(item, "hostname") 430 + or item_field(item, "host") 431 + ) 432 + if key: 433 + store_detail(key, item) 434 + if args.debug: 435 + print( 436 + f"Batch {batch_num} returned {len(batch_details) if hasattr(batch_details, '__len__') else 'unknown'} records" 437 + ) 438 + if isinstance(batch_details, dict): 439 + sample_keys = list(batch_details.keys())[:5] 440 + if sample_keys: 441 + print(f"Sample ipinfo keys: {sample_keys}") 442 + elif isinstance(batch_details, list) and batch_details: 443 + sample_item = batch_details[0] 444 + key_sample = ( 445 + item_field(sample_item, "ip") 446 + or item_field(sample_item, "query") 447 + or item_field(sample_item, "hostname") 448 + or item_field(sample_item, "host") 449 + ) 450 + print(f"Sample ipinfo item key: {key_sample}") 451 + 452 + results = [] 453 + for entry in hosts: 454 + hostname = entry["hostname"] 455 + users = entry["users"] 456 + if users <= 0: 457 + continue 458 + software = (entry.get("software") or "").strip() 459 + ip = hostname_to_ip.get(hostname) 460 + details = ( 461 + details_by_host.get(hostname) 462 + or details_by_ip.get(ip) 463 + or details_by_ip.get(hostname) 464 + ) 465 + if not details: 466 + print(f"Warning: ipinfo lookup missing for {hostname}") 467 + continue 468 + 469 + if args.source == "at-mau": 470 + if hostname.endswith(".bsky.network"): 471 + style = AT_BSKY_STYLE 472 + else: 473 + override = at_overrides.get(hostname, {}) 474 + if not isinstance(override, dict): 475 + override = {} 476 + resolved_type = override.get("type") or AT_HOST_TYPES.get(hostname) 477 + style = AT_PROTO_STYLE 478 + if resolved_type in AT_TYPE_STYLE: 479 + style = {**style, **AT_TYPE_STYLE[resolved_type]} 480 + style = {**style, **override} 481 + else: 482 + software_key = software.lower() if software else "" 483 + style = FEDI_SOFTWARE_STYLE.get(software_key, FEDI_DEFAULT_STYLE) 484 + if software_key in FEDI_SOFTWARE_STYLE: 485 + style = {**style, "type": software_key} 486 + else: 487 + style = {**style, "type": "other"} 488 + 489 + lat, lon = extract_lat_lon(details) 490 + record = { 491 + "hostname": hostname, 492 + "city": get_detail_field(details, "city"), 493 + "country": get_detail_field(details, "country"), 494 + "users": users, 495 + "lat": lat, 496 + "lon": lon, 497 + "network": extract_network(details), 498 + "cdn": is_cdn(details), 499 + "anycast": bool(get_detail_field(details, "anycast")), 500 + "color": style.get("color"), 501 + "icon": style.get("icon"), 502 + "type": style.get("type"), 503 + } 504 + 505 + if args.source == "fedi-mau": 506 + override = fedi_overrides.get(hostname, {}) 507 + if isinstance(override, dict): 508 + record.update(override) 509 + 510 + results.append(record) 511 + 512 + output_path.parent.mkdir(parents=True, exist_ok=True) 513 + with output_path.open("w", encoding="utf-8") as f: 514 + json.dump(results, f, ensure_ascii=True, indent=2) 515 + 516 + cache_path.parent.mkdir(parents=True, exist_ok=True) 517 + with cache_path.open("w", encoding="utf-8") as f: 518 + json.dump(cache, f, ensure_ascii=True, indent=2) 519 + 520 + dns_cache_path.parent.mkdir(parents=True, exist_ok=True) 521 + with dns_cache_path.open("w", encoding="utf-8") as f: 522 + json.dump(dns_cache, f, ensure_ascii=True, indent=2) 523 + 524 + if args.tarball: 525 + tar_path = Path(args.tarball) 526 + tar_path.parent.mkdir(parents=True, exist_ok=True) 527 + tar_root = Path(args.source) 528 + with tarfile.open(tar_path, "w:gz") as tar: 529 + tar.add(output_path, arcname=str(tar_root / output_path.name)) 530 + icon_root = REPO_ROOT / "data-static" / "icons" 531 + if icon_root.exists(): 532 + tar.add( 533 + icon_root, 534 + arcname=str(tar_root / icon_root.relative_to(REPO_ROOT)), 535 + ) 536 + else: 537 + print(f"Warning: missing icon directory {icon_root}") 538 + print(f"Wrote tarball to {tar_path}") 539 + 540 + print(f"Loaded {len(hosts)} hosts from {csv_path.name}") 541 + print(f"Wrote {len(results)} geocoded hosts to {output_path}") 542 + return 0 543 + 544 + 545 + if __name__ == "__main__": 546 + raise SystemExit(main())
data-static/icons/atproto.png

This is a binary file and will not be displayed.

+41
data-static/icons/atproto.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + viewBox="0 0 27.005761 27.000008" 4 + aria-hidden="true" 5 + class="h-6" 6 + version="1.1" 7 + id="svg3" 8 + sodipodi:docname="AT_Protocol_Logo.svg" 9 + inkscape:version="1.4.3 (0d15f75042, 2025-12-25)" 10 + width="27.00576" 11 + height="27.000008" 12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 14 + xmlns="http://www.w3.org/2000/svg" 15 + xmlns:svg="http://www.w3.org/2000/svg"> 16 + <defs 17 + id="defs3" /> 18 + <sodipodi:namedview 19 + id="namedview3" 20 + pagecolor="#ffffff" 21 + bordercolor="#000000" 22 + borderopacity="0.25" 23 + inkscape:showpageshadow="2" 24 + inkscape:pageopacity="0.0" 25 + inkscape:pagecheckerboard="0" 26 + inkscape:deskcolor="#d1d1d1" 27 + inkscape:zoom="9.6919523" 28 + inkscape:cx="67.220719" 29 + inkscape:cy="59.740286" 30 + inkscape:window-width="3840" 31 + inkscape:window-height="2160" 32 + inkscape:window-x="0" 33 + inkscape:window-y="0" 34 + inkscape:window-maximized="0" 35 + inkscape:current-layer="svg3" /> 36 + <path 37 + class="fill-blue-500" 38 + d="M 13.482,27 C 11.526,27 9.726,26.676 8.082,26.028 6.438,25.38 5.01,24.462 3.798,23.274 A 12.247,12.247 0 0 1 0.99,19.116 C 0.33,17.52 0,15.786 0,13.914 0,11.682 0.342,9.702 1.026,7.974 1.722,6.246 2.682,4.794 3.906,3.618 A 12.48,12.48 0 0 1 8.19,0.918 C 9.822,0.306 11.568,0 13.428,0 c 2.28,0 4.278,0.354 5.994,1.062 1.716,0.708 3.144,1.668 4.284,2.88 A 11.706,11.706 0 0 1 26.244,8.1 c 0.552,1.548 0.804,3.168 0.756,4.86 -0.06,2.328 -0.546,4.116 -1.458,5.364 -0.912,1.236 -2.328,1.854 -4.248,1.854 a 5.839,5.839 0 0 1 -2.826,-0.702 3.703,3.703 0 0 1 -1.764,-2.07 l 1.044,0.054 c -0.492,0.924 -1.164,1.572 -2.016,1.944 a 6.464,6.464 0 0 1 -2.61,0.558 c -1.212,0 -2.28,-0.258 -3.204,-0.774 A 5.682,5.682 0 0 1 7.74,16.974 C 7.212,16.026 6.948,14.928 6.948,13.68 c 0,-1.284 0.276,-2.394 0.828,-3.33 A 5.77,5.77 0 0 1 10.008,8.154 C 10.944,7.638 12,7.38 13.176,7.38 c 0.78,0 1.59,0.162 2.43,0.486 0.852,0.324 1.512,0.78 1.98,1.368 L 16.848,10.17 V 7.884 h 2.412 l -0.054,6.462 c 0,0.924 0.18,1.62 0.54,2.088 0.36,0.468 0.894,0.702 1.602,0.702 0.624,0 1.104,-0.174 1.44,-0.522 0.348,-0.36 0.588,-0.846 0.72,-1.458 A 10.66,10.66 0 0 0 23.76,13.05 C 23.796,11.19 23.52,9.624 22.932,8.352 22.344,7.08 21.546,6.054 20.538,5.274 a 9.499,9.499 0 0 0 -3.294,-1.71 c -1.2,-0.36 -2.394,-0.54 -3.582,-0.54 -1.68,0 -3.174,0.27 -4.482,0.81 -1.308,0.528 -2.412,1.278 -3.312,2.25 -0.888,0.96 -1.56,2.1 -2.016,3.42 -0.444,1.308 -0.654,2.748 -0.63,4.32 0.048,1.56 0.33,2.964 0.846,4.212 a 9.324,9.324 0 0 0 2.16,3.204 9.38,9.38 0 0 0 3.276,2.034 c 1.26,0.468 2.64,0.702 4.14,0.702 0.84,0 1.674,-0.096 2.502,-0.288 0.84,-0.18 1.608,-0.438 2.304,-0.774 l 1.026,2.808 c -0.924,0.432 -1.896,0.75 -2.916,0.954 A 14.649,14.649 0 0 1 13.482,27 Z M 13.338,16.902 c 0.852,0 1.566,-0.246 2.142,-0.738 0.576,-0.492 0.864,-1.326 0.864,-2.502 0,-1.068 -0.258,-1.872 -0.774,-2.412 -0.504,-0.552 -1.218,-0.828 -2.142,-0.828 -1.092,0 -1.908,0.288 -2.448,0.864 -0.54,0.576 -0.81,1.368 -0.81,2.376 0,1.032 0.276,1.83 0.828,2.394 0.564,0.564 1.344,0.846 2.34,0.846 z" 39 + id="path1" 40 + style="fill:#3b82f5;fill-opacity:1" /> 41 + </svg>
data-static/icons/blacksky.png

This is a binary file and will not be displayed.

+6
data-static/icons/blacksky.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.0620117 0.348442 87.9941 74.9653"> 2 + <path d="M41.9565 74.9643L24.0161 74.9653L41.9565 74.9643ZM63.8511 74.9653H45.9097L63.8501 74.9643V57.3286H63.8511V74.9653ZM45.9097 44.5893C45.9099 49.2737 49.7077 53.0707 54.3921 53.0707H63.8501V57.3286H54.3921C49.7077 57.3286 45.9099 61.1257 45.9097 65.81V74.9643H41.9565V65.81C41.9563 61.1258 38.1593 57.3287 33.4751 57.3286H24.0161V53.0707H33.4741C38.1587 53.0707 41.9565 49.2729 41.9565 44.5883V35.1303H45.9097V44.5893ZM63.8511 53.0707H63.8501V35.1303H63.8511V53.0707Z" fill="#ffffff"/> 3 + <path d="M52.7272 9.83198C49.4148 13.1445 49.4148 18.5151 52.7272 21.8275L59.4155 28.5158L56.4051 31.5262L49.7169 24.8379C46.4044 21.5254 41.0338 21.5254 37.7213 24.8379L31.2482 31.3111L28.4527 28.5156L34.9259 22.0424C38.2383 18.7299 38.2383 13.3594 34.9259 10.0469L28.2378 3.35883L31.2482 0.348442L37.9365 7.03672C41.2489 10.3492 46.6195 10.3492 49.932 7.03672L56.6203 0.348442L59.4155 3.14371L52.7272 9.83198Z" fill="#ffffff"/> 4 + <path d="M24.3831 23.2335C23.1706 27.7584 25.8559 32.4095 30.3808 33.6219L39.5172 36.07L38.4154 40.182L29.2793 37.734C24.7544 36.5215 20.1033 39.2068 18.8909 43.7317L16.5215 52.5745L12.7028 51.5513L15.0721 42.7088C16.2846 38.1839 13.5993 33.5328 9.07434 32.3204L-0.0620117 29.8723L1.03987 25.76L10.1762 28.2081C14.7011 29.4206 19.3522 26.7352 20.5647 22.2103L23.0127 13.074L26.8311 14.0971L24.3831 23.2335Z" fill="#ffffff"/> 5 + <path d="M67.3676 22.0297C68.5801 26.5546 73.2311 29.2399 77.756 28.0275L86.8923 25.5794L87.9941 29.6914L78.8578 32.1394C74.3329 33.3519 71.6476 38.003 72.86 42.5279L75.2294 51.3707L71.411 52.3938L69.0417 43.5513C67.8293 39.0264 63.1782 36.3411 58.6533 37.5535L49.5169 40.0016L48.415 35.8894L57.5514 33.4413C62.0763 32.2288 64.7616 27.5778 63.5492 23.0528L61.1011 13.9165L64.9195 12.8934L67.3676 22.0297Z" fill="#ffffff"/> 6 + </svg>
data-static/icons/bluesky.png

This is a binary file and will not be displayed.

+1
data-static/icons/bluesky.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026"/></svg>
data-static/icons/bookwyrm.png

This is a binary file and will not be displayed.

data-static/icons/bridgy.png

This is a binary file and will not be displayed.

data-static/icons/fediverse.png

This is a binary file and will not be displayed.

+17
data-static/icons/fediverse.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="196.52mm" height="196.52mm" viewBox="0 0 196.52 196.52"> 2 + <path fill="#a730b8" d="M47.9242 72.7966a18.2278 18.2278 0 0 1-7.7959 7.7597l42.7984 42.9653 10.3182-5.2291zm56.4524 56.6704-10.3182 5.2291 21.686 21.7708a18.2278 18.2278 0 0 1 7.7975-7.7608z"/> 3 + <path fill="#5496be" d="M129.6645 102.0765l1.7865 11.4272 27.4149-13.8942a18.2278 18.2278 0 0 1-4.9719-9.8124zm-14.0658 7.1282-57.2891 29.0339a18.2278 18.2278 0 0 1 4.9728 9.8133l54.1027-27.4194z"/> 4 + <path fill="#ce3d1a" d="M69.5312 91.6539l8.1618 8.1933 29.269-57.1387a18.2278 18.2278 0 0 1-9.787-5.0219zm-7.1897 14.0363-14.0022 27.3353a18.2278 18.2278 0 0 1 9.786 5.0214l12.3775-24.1639z"/> 5 + <path fill="#d0188f" d="M39.8906 80.6763a18.2278 18.2278 0 0 1-10.8655 1.7198l8.1762 52.2981a18.2278 18.2278 0 0 1 10.8645-1.7198z"/> 6 + <path fill="#5b36e9" d="M63.3259 148.3109a18.2278 18.2278 0 0 1-1.7322 10.8629l52.2893 8.3907a18.2278 18.2278 0 0 1 1.7322-10.8629z"/> 7 + <path fill="#30b873" d="M134.9148 146.9182a18.2278 18.2278 0 0 1 9.788 5.0224l24.1345-47.117a18.2278 18.2278 0 0 1-9.7875-5.0229z"/> 8 + <path fill="#ebe305" d="M126.1329 33.1603a18.2278 18.2278 0 0 1-7.7975 7.7608l37.3765 37.5207a18.2278 18.2278 0 0 1 7.7969-7.7608z"/> 9 + <path fill="#f47601" d="M44.7704 51.6279a18.2278 18.2278 0 0 1 4.9723 9.8123l47.2478-23.9453a18.2278 18.2278 0 0 1-4.9718-9.8113z"/> 10 + <path fill="#57c115" d="M118.2491 40.9645a18.2278 18.2278 0 0 1-10.8511 1.8123l4.1853 26.8 11.42 1.8324zm-4.2333 44.1927 9.8955 63.3631a18.2278 18.2278 0 0 1 10.88-1.6278l-9.355-59.9035z"/> 11 + <path fill="#dbb210" d="M49.7763 61.6412a18.2278 18.2278 0 0 1-1.694 10.8686l26.8206 4.3077 5.2715-10.2945zm45.9677 7.382-5.272 10.2955 63.3713 10.1777a18.2278 18.2278 0 0 1 1.7606-10.8593z"/> 12 + <path fill="#ffca00" d="M93.4385 23.8419a1 1 0 1 0 33.0924 1.8025 1 1 0 1 0-33.0924-1.8025"/> 13 + <path fill="#64ff00" d="M155.314 85.957a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/> 14 + <path fill="#00a3ff" d="M115.3466 163.9824a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/> 15 + <path fill="#9500ff" d="M28.7698 150.0898a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/> 16 + <path fill="#ff0000" d="M15.2298 63.4781a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/> 17 + </svg>
data-static/icons/ghost.png

This is a binary file and will not be displayed.

+1
data-static/icons/ghost.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Ghost</title><path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm.256 2.313c2.47.005 5.116 2.008 5.898 2.962l.244.3c1.64 1.994 3.569 4.34 3.569 6.966 0 3.719-2.98 5.808-6.158 7.508-1.433.766-2.98 1.508-4.748 1.508-4.543 0-8.366-3.569-8.366-8.112 0-.706.17-1.425.342-2.15.122-.515.244-1.033.307-1.549.548-4.539 2.967-6.795 8.422-7.408a4.29 4.29 0 01.49-.026Z"/></svg>
data-static/icons/lemmy.png

This is a binary file and will not be displayed.

+1
data-static/icons/lemmy.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Lemmy</title><path d="M2.9595 4.2228a3.9132 3.9132 0 0 0-.332.019c-.8781.1012-1.67.5699-2.155 1.3862-.475.8-.5922 1.6809-.35 2.4971.2421.8162.8297 1.5575 1.6982 2.1449.0053.0035.0106.0076.0163.0114.746.4498 1.492.7431 2.2877.8994-.02.3318-.0272.6689-.006 1.0181.0634 1.0432.4368 2.0006.996 2.8492l-2.0061.8189a.4163.4163 0 0 0-.2276.2239.416.416 0 0 0 .0879.455.415.415 0 0 0 .2941.1231.4156.4156 0 0 0 .1595-.0312l2.2093-.9035c.408.4859.8695.9315 1.3723 1.318.0196.0151.0407.0264.0603.0423l-1.2918 1.7103a.416.416 0 0 0 .664.501l1.314-1.7385c.7185.4548 1.4782.7927 2.2294 1.0242.3833.7209 1.1379 1.1871 2.0202 1.1871.8907 0 1.6442-.501 2.0242-1.2072.744-.2347 1.4959-.5729 2.2073-1.0262l1.332 1.7606a.4157.4157 0 0 0 .7439-.1936.4165.4165 0 0 0-.0799-.3074l-1.3099-1.7345c.0083-.0075.0178-.0113.0261-.0188.4968-.3803.9549-.8175 1.3622-1.2939l2.155.8794a.4156.4156 0 0 0 .5412-.2276.4151.4151 0 0 0-.2273-.5432l-1.9438-.7928c.577-.8538.9697-1.8183 1.0504-2.8693.0268-.3507.0242-.6914.0079-1.0262.7905-.1572 1.5321-.4502 2.2737-.8974.0053-.0033.011-.0076.0163-.0113.8684-.5874 1.456-1.3287 1.6982-2.145.2421-.8161.125-1.697-.3501-2.497-.4849-.8163-1.2768-1.2852-2.155-1.3863a3.2175 3.2175 0 0 0-.332-.0189c-.7852-.0151-1.6231.229-2.4286.6942-.5926.342-1.1252.867-1.5433 1.4387-1.1699-.6703-2.6923-1.0476-4.5635-1.0785a15.5768 15.5768 0 0 0-.5111 0c-2.085.034-3.7537.43-5.0142 1.1449-.0033-.0038-.0045-.0114-.008-.0152-.4233-.5916-.973-1.1365-1.5835-1.489-.8055-.465-1.6434-.7083-2.4286-.6941Zm.2858.7365c.5568.042 1.1696.2358 1.7787.5875.485.28.9757.7554 1.346 1.2696a5.6875 5.6875 0 0 0-.4969.4085c-.9201.8516-1.4615 1.9597-1.668 3.2335-.6809-.1402-1.3183-.3945-1.984-.7948-.7553-.5128-1.2159-1.1225-1.4004-1.7445-.1851-.624-.1074-1.2712.2776-1.9196.3743-.63.9275-.9534 1.6118-1.0322a2.796 2.796 0 0 1 .5352-.0076Zm17.5094 0a2.797 2.797 0 0 1 .5353.0075c.6842.0786 1.2374.4021 1.6117 1.0322.385.6484.4627 1.2957.2776 1.9196-.1845.622-.645 1.2317-1.4004 1.7445-.6578.3955-1.2881.6472-1.9598.7888-.1942-1.2968-.7375-2.4338-1.666-3.302a5.5639 5.5639 0 0 0-.4709-.3923c.3645-.49.8287-.9428 1.2938-1.2113.6091-.3515 1.2219-.5454 1.7787-.5875ZM12.006 6.0036a14.832 14.832 0 0 1 .487 0c2.3901.0393 4.0848.67 5.1631 1.678 1.1501 1.0754 1.6423 2.6006 1.499 4.467-.1311 1.7079-1.2203 3.2281-2.652 4.324-.694.5313-1.4626.9354-2.2254 1.2294.0031-.0453.014-.0888.014-.1349.0029-1.1964-.9313-2.2133-2.2918-2.2133-1.3606 0-2.3222 1.0154-2.2918 2.2213.0013.0507.014.0972.0181.1471-.781-.2933-1.5696-.7013-2.2777-1.2456-1.4239-1.0945-2.4997-2.6129-2.6037-4.322-.1129-1.8567.3778-3.3382 1.5212-4.3965C7.5094 6.7 9.352 6.047 12.006 6.0036Zm-3.6419 6.8291c-.6053 0-1.0966.4903-1.0966 1.0966 0 .6063.4913 1.0986 1.0966 1.0986s1.0966-.4923 1.0966-1.0986c0-.6063-.4913-1.0966-1.0966-1.0966zm7.2819.0113c-.5998 0-1.0866.4859-1.0866 1.0866s.4868 1.0885 1.0866 1.0885c.5997 0 1.0865-.4878 1.0865-1.0885s-.4868-1.0866-1.0865-1.0866zM12 16.0835c1.0237 0 1.5654.638 1.5634 1.4829-.0018.7849-.6723 1.485-1.5634 1.485-.9167 0-1.54-.5629-1.5634-1.493-.0212-.8347.5397-1.4749 1.5634-1.4749Z"/></svg>
data-static/icons/mastodon.png

This is a binary file and will not be displayed.

+1
data-static/icons/mastodon.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg>
data-static/icons/northsky.png

This is a binary file and will not be displayed.

data-static/icons/peertube.png

This is a binary file and will not be displayed.

+1
data-static/icons/peertube.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>PeerTube</title><path d="M12 6.545v10.91L20.727 12M3.273 12v12L12 17.455M3.273 0v12L12 6.545"/></svg>
data-static/icons/pixelfed.png

This is a binary file and will not be displayed.

+1
data-static/icons/pixelfed.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Pixelfed</title><path d="M12 24C5.3726 24 0 18.6274 0 12S5.3726 0 12 0s12 5.3726 12 12-5.3726 12-12 12m-.9526-9.3802h2.2014c2.0738 0 3.7549-1.6366 3.7549-3.6554S15.3226 7.309 13.2488 7.309h-3.1772c-1.1964 0-2.1663.9442-2.1663 2.1089v8.208z"/></svg>
data-static/icons/pleroma.png

This is a binary file and will not be displayed.

+1
data-static/icons/pleroma.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Pleroma</title><path d="M6.36 0A1.868 1.868 0 004.49 1.868V24h5.964V0zm7.113 0v12h4.168a1.868 1.868 0 001.868-1.868V0zm0 18.036V24h4.168a1.868 1.868 0 001.868-1.868v-4.096Z"/></svg>
data-static/icons/tangled.png

This is a binary file and will not be displayed.

+94
data-static/icons/tangled.svg
··· 1 + <svg 2 + version="1.1" 3 + id="svg1" 4 + class="size-8 text-black dark:text-white" 5 + width="25" 6 + height="25" 7 + viewBox="0 0 25 25" 8 + sodipodi:docname="tangled_dolly_face_only_black_on_trans.svg" 9 + inkscape:export-filename="tangled_logotype_black_on_trans.svg" 10 + inkscape:export-xdpi="96" 11 + inkscape:export-ydpi="96" 12 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 14 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 15 + xmlns="http://www.w3.org/2000/svg" 16 + xmlns:svg="http://www.w3.org/2000/svg" 17 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 18 + xmlns:cc="http://creativecommons.org/ns#"> 19 + <style> 20 + .dolly { 21 + color: #000000; 22 + } 23 + 24 + @media (prefers-color-scheme: dark) { 25 + .dolly { 26 + color: #ffffff; 27 + } 28 + } 29 + </style> 30 + <sodipodi:namedview 31 + id="namedview1" 32 + pagecolor="#ffffff" 33 + bordercolor="#000000" 34 + borderopacity="0.25" 35 + inkscape:showpageshadow="2" 36 + inkscape:pageopacity="0.0" 37 + inkscape:pagecheckerboard="true" 38 + inkscape:deskcolor="#d5d5d5" 39 + inkscape:zoom="45.254834" 40 + inkscape:cx="3.1377863" 41 + inkscape:cy="8.9382717" 42 + inkscape:window-width="3840" 43 + inkscape:window-height="2160" 44 + inkscape:window-x="0" 45 + inkscape:window-y="0" 46 + inkscape:window-maximized="0" 47 + inkscape:current-layer="g1" 48 + borderlayer="true"> 49 + <inkscape:page 50 + x="0" 51 + y="0" 52 + width="25" 53 + height="25" 54 + id="page2" 55 + margin="0" 56 + bleed="0" /> 57 + </sodipodi:namedview> 58 + <g 59 + inkscape:groupmode="layer" 60 + inkscape:label="Image" 61 + id="g1" 62 + transform="translate(-0.42924038,-0.87777209)"> 63 + <path 64 + class="dolly" 65 + fill="currentColor" 66 + style="stroke-width:0.111183;" 67 + d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z" 68 + id="path4" 69 + sodipodi:nodetypes="sccccccccccccccccccsscccccccccsccccccccccccccccccccccc" /> 70 + </g> 71 + <metadata 72 + id="metadata1"> 73 + <rdf:RDF> 74 + <cc:Work 75 + rdf:about=""> 76 + <cc:license 77 + rdf:resource="http://creativecommons.org/licenses/by/4.0/" /> 78 + </cc:Work> 79 + <cc:License 80 + rdf:about="http://creativecommons.org/licenses/by/4.0/"> 81 + <cc:permits 82 + rdf:resource="http://creativecommons.org/ns#Reproduction" /> 83 + <cc:permits 84 + rdf:resource="http://creativecommons.org/ns#Distribution" /> 85 + <cc:requires 86 + rdf:resource="http://creativecommons.org/ns#Notice" /> 87 + <cc:requires 88 + rdf:resource="http://creativecommons.org/ns#Attribution" /> 89 + <cc:permits 90 + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> 91 + </cc:License> 92 + </rdf:RDF> 93 + </metadata> 94 + </svg>
data-static/icons/wafrn.png

This is a binary file and will not be displayed.

data-static/icons/wordpress.png

This is a binary file and will not be displayed.

+1
data-static/icons/wordpress.svg
··· 1 + <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>WordPress</title><path d="M21.469 6.825c.84 1.537 1.318 3.3 1.318 5.175 0 3.979-2.156 7.456-5.363 9.325l3.295-9.527c.615-1.54.82-2.771.82-3.864 0-.405-.026-.78-.07-1.11m-7.981.105c.647-.03 1.232-.105 1.232-.105.582-.075.514-.93-.067-.899 0 0-1.755.135-2.88.135-1.064 0-2.85-.15-2.85-.15-.585-.03-.661.855-.075.885 0 0 .54.061 1.125.09l1.68 4.605-2.37 7.08L5.354 6.9c.649-.03 1.234-.1 1.234-.1.585-.075.516-.93-.065-.896 0 0-1.746.138-2.874.138-.2 0-.438-.008-.69-.015C4.911 3.15 8.235 1.215 12 1.215c2.809 0 5.365 1.072 7.286 2.833-.046-.003-.091-.009-.141-.009-1.06 0-1.812.923-1.812 1.914 0 .89.513 1.643 1.06 2.531.411.72.89 1.643.89 2.977 0 .915-.354 1.994-.821 3.479l-1.075 3.585-3.9-11.61.001.014zM12 22.784c-1.059 0-2.081-.153-3.048-.437l3.237-9.406 3.315 9.087c.024.053.05.101.078.149-1.12.393-2.325.609-3.582.609M1.211 12c0-1.564.336-3.05.935-4.39L7.29 21.709C3.694 19.96 1.212 16.271 1.211 12M12 0C5.385 0 0 5.385 0 12s5.385 12 12 12 12-5.385 12-12S18.615 0 12 0"/></svg>