From b83543a163a4d7048c77bdfce1c1b8c640680eb1 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 4 Jan 2024 13:03:10 -0800 Subject: [PATCH] Links --- build-staging/404.html | 8 ++++---- build-staging/assets/js/b2f554cd.0f0f1284.js | 1 + build-staging/assets/js/b2f554cd.f51eff8b.js | 1 - .../js/{d0554977.42033312.js => d0554977.2cdbecbc.js} | 2 +- .../assets/js/{main.c59698c8.js => main.10f93ed4.js} | 4 ++-- ...8c8.js.LICENSE.txt => main.10f93ed4.js.LICENSE.txt} | 0 ...ntime~main.e83a6af5.js => runtime~main.f1b2e7b1.js} | 2 +- build-staging/blog/archive/index.html | 8 ++++---- build-staging/blog/atom.xml | 2 +- build-staging/blog/autobindings-ii/index.html | 8 ++++---- build-staging/blog/autobindings/index.html | 8 ++++---- .../availability-status-profile-attributes/index.html | 8 ++++---- build-staging/blog/cwtch-1-13/index.html | 8 ++++---- .../blog/cwtch-android-reproducibility/index.html | 8 ++++---- .../blog/cwtch-bindings-reproducible/index.html | 8 ++++---- .../blog/cwtch-developer-documentation/index.html | 8 ++++---- build-staging/blog/cwtch-documentation/index.html | 8 ++++---- build-staging/blog/cwtch-nightly-1-11/index.html | 8 ++++---- build-staging/blog/cwtch-nightly-1-12/index.html | 8 ++++---- .../index.html | 8 ++++---- .../index.html | 8 ++++---- build-staging/blog/cwtch-nightly-v.11-74/index.html | 8 ++++---- build-staging/blog/cwtch-platform-support/index.html | 8 ++++---- build-staging/blog/cwtch-stable-api-design/index.html | 8 ++++---- .../blog/cwtch-stable-call-for-credits/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-june/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-sept/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update/index.html | 8 ++++---- build-staging/blog/cwtch-testing-i/index.html | 8 ++++---- build-staging/blog/cwtch-testing-ii/index.html | 8 ++++---- .../blog/cwtch-ui-reproducible-builds-linux/index.html | 8 ++++---- build-staging/blog/feed.json | 2 +- build-staging/blog/index.html | 8 ++++---- build-staging/blog/page/2/index.html | 8 ++++---- build-staging/blog/page/3/index.html | 8 ++++---- build-staging/blog/path-to-cwtch-stable/index.html | 8 ++++---- build-staging/blog/path-to-hybrid-groups/index.html | 10 +++++----- build-staging/blog/rss.xml | 2 +- build-staging/blog/tags/api/index.html | 8 ++++---- build-staging/blog/tags/autobindings/index.html | 8 ++++---- build-staging/blog/tags/bindings/index.html | 8 ++++---- build-staging/blog/tags/community/index.html | 8 ++++---- build-staging/blog/tags/contributors/index.html | 8 ++++---- build-staging/blog/tags/cwtch-stable/index.html | 8 ++++---- build-staging/blog/tags/cwtch-stable/page/2/index.html | 8 ++++---- build-staging/blog/tags/cwtch-stable/page/3/index.html | 8 ++++---- build-staging/blog/tags/cwtch/index.html | 8 ++++---- build-staging/blog/tags/cwtch/page/2/index.html | 8 ++++---- build-staging/blog/tags/cwtch/page/3/index.html | 8 ++++---- .../blog/tags/developer-documentation/index.html | 8 ++++---- build-staging/blog/tags/documentation/index.html | 8 ++++---- build-staging/blog/tags/hybrid-groups/index.html | 8 ++++---- build-staging/blog/tags/index.html | 8 ++++---- build-staging/blog/tags/libcwtch/index.html | 8 ++++---- build-staging/blog/tags/nightly/index.html | 8 ++++---- build-staging/blog/tags/planning/index.html | 8 ++++---- build-staging/blog/tags/preview/index.html | 8 ++++---- build-staging/blog/tags/release/index.html | 8 ++++---- build-staging/blog/tags/repliqate/index.html | 8 ++++---- build-staging/blog/tags/reproducible-builds/index.html | 8 ++++---- build-staging/blog/tags/search/index.html | 8 ++++---- build-staging/blog/tags/security-handbook/index.html | 8 ++++---- build-staging/blog/tags/support/index.html | 8 ++++---- build-staging/blog/tags/testing/index.html | 8 ++++---- build-staging/blog/tags/whonix/index.html | 8 ++++---- build-staging/de/404.html | 8 ++++---- build-staging/de/assets/js/291c70d7.b8d036cc.js | 1 - build-staging/de/assets/js/291c70d7.ca422c75.js | 1 + .../js/{d0554977.cd662b0d.js => d0554977.4178d8ba.js} | 2 +- .../assets/js/{main.aac398cc.js => main.f32429d1.js} | 4 ++-- ...8cc.js.LICENSE.txt => main.f32429d1.js.LICENSE.txt} | 0 ...ntime~main.cab19c87.js => runtime~main.5d8afb8d.js} | 2 +- build-staging/de/blog/archive/index.html | 8 ++++---- build-staging/de/blog/atom.xml | 2 +- build-staging/de/blog/autobindings-ii/index.html | 8 ++++---- build-staging/de/blog/autobindings/index.html | 8 ++++---- .../availability-status-profile-attributes/index.html | 8 ++++---- build-staging/de/blog/cwtch-1-13/index.html | 8 ++++---- build-staging/de/blog/cwtch-Dokumentation/index.html | 8 ++++---- .../de/blog/cwtch-android-reproducibility/index.html | 8 ++++---- .../de/blog/cwtch-bindings-reproducible/index.html | 8 ++++---- .../de/blog/cwtch-developer-documentation/index.html | 8 ++++---- build-staging/de/blog/cwtch-nightly-1-11/index.html | 8 ++++---- build-staging/de/blog/cwtch-nightly-1-12/index.html | 8 ++++---- .../index.html | 8 ++++---- .../index.html | 8 ++++---- build-staging/de/blog/cwtch-nightly-v.11-74/index.html | 8 ++++---- .../de/blog/cwtch-platform-support/index.html | 8 ++++---- .../de/blog/cwtch-stable-api-design/index.html | 8 ++++---- .../de/blog/cwtch-stable-call-for-credits/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-june/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-sept/index.html | 8 ++++---- .../de/blog/cwtch-stable-roadmap-update/index.html | 8 ++++---- build-staging/de/blog/cwtch-testing-i/index.html | 8 ++++---- build-staging/de/blog/cwtch-testing-ii/index.html | 8 ++++---- .../blog/cwtch-ui-reproducible-builds-linux/index.html | 8 ++++---- build-staging/de/blog/feed.json | 2 +- build-staging/de/blog/index.html | 8 ++++---- build-staging/de/blog/page/2/index.html | 8 ++++---- build-staging/de/blog/page/3/index.html | 8 ++++---- build-staging/de/blog/path-to-cwtch-stable/index.html | 8 ++++---- build-staging/de/blog/path-to-hybrid-groups/index.html | 10 +++++----- build-staging/de/blog/rss.xml | 2 +- build-staging/de/blog/tags/api/index.html | 8 ++++---- build-staging/de/blog/tags/autobindings/index.html | 8 ++++---- build-staging/de/blog/tags/bindings/index.html | 8 ++++---- build-staging/de/blog/tags/community/index.html | 8 ++++---- build-staging/de/blog/tags/cwtch-stable/index.html | 8 ++++---- .../de/blog/tags/cwtch-stable/page/2/index.html | 8 ++++---- .../de/blog/tags/cwtch-stable/page/3/index.html | 8 ++++---- build-staging/de/blog/tags/cwtch/index.html | 8 ++++---- build-staging/de/blog/tags/cwtch/page/2/index.html | 8 ++++---- build-staging/de/blog/tags/cwtch/page/3/index.html | 8 ++++---- .../de/blog/tags/developer-documentation/index.html | 8 ++++---- build-staging/de/blog/tags/dokumentation/index.html | 8 ++++---- build-staging/de/blog/tags/hybrid-groups/index.html | 8 ++++---- build-staging/de/blog/tags/index.html | 8 ++++---- build-staging/de/blog/tags/libcwtch/index.html | 8 ++++---- build-staging/de/blog/tags/mitwirkende/index.html | 8 ++++---- build-staging/de/blog/tags/nightly/index.html | 8 ++++---- build-staging/de/blog/tags/planning/index.html | 8 ++++---- build-staging/de/blog/tags/preview/index.html | 8 ++++---- build-staging/de/blog/tags/release/index.html | 8 ++++---- build-staging/de/blog/tags/repliqate/index.html | 8 ++++---- .../de/blog/tags/reproducible-builds/index.html | 8 ++++---- build-staging/de/blog/tags/search/index.html | 8 ++++---- .../de/blog/tags/sicherheitshandbuch/index.html | 8 ++++---- build-staging/de/blog/tags/support/index.html | 8 ++++---- build-staging/de/blog/tags/testing/index.html | 8 ++++---- build-staging/de/blog/tags/whonix/index.html | 8 ++++---- .../building-an-echobot/index.html | 8 ++++---- .../building-a-cwtch-app/core-concepts/index.html | 8 ++++---- .../developing/building-a-cwtch-app/intro/index.html | 8 ++++---- .../category/building-a-cwtch-app/index.html | 8 ++++---- build-staging/de/developing/intro/index.html | 8 ++++---- build-staging/de/developing/release/index.html | 8 ++++---- build-staging/de/docs/category/appearance/index.html | 8 ++++---- build-staging/de/docs/category/behaviour/index.html | 8 ++++---- build-staging/de/docs/category/contribute/index.html | 8 ++++---- .../de/docs/category/conversations/index.html | 8 ++++---- build-staging/de/docs/category/experiments/index.html | 8 ++++---- .../de/docs/category/getting-started/index.html | 8 ++++---- build-staging/de/docs/category/groups/index.html | 8 ++++---- build-staging/de/docs/category/platforms/index.html | 8 ++++---- build-staging/de/docs/category/profiles/index.html | 8 ++++---- build-staging/de/docs/category/servers/index.html | 8 ++++---- build-staging/de/docs/category/settings/index.html | 8 ++++---- .../docs/chat/accept-deny-new-conversation/index.html | 8 ++++---- build-staging/de/docs/chat/add-contact/index.html | 8 ++++---- build-staging/de/docs/chat/block-contact/index.html | 8 ++++---- .../de/docs/chat/conversation-settings/index.html | 8 ++++---- build-staging/de/docs/chat/delete-contact/index.html | 8 ++++---- build-staging/de/docs/chat/introduction/index.html | 8 ++++---- .../de/docs/chat/message-formatting/index.html | 8 ++++---- build-staging/de/docs/chat/reply-to-message/index.html | 8 ++++---- .../de/docs/chat/save-conversation-history/index.html | 8 ++++---- .../de/docs/chat/share-address-with-friends/index.html | 8 ++++---- build-staging/de/docs/chat/share-file/index.html | 8 ++++---- build-staging/de/docs/chat/unblock-contact/index.html | 8 ++++---- build-staging/de/docs/contribute/developing/index.html | 8 ++++---- .../de/docs/contribute/documentation/index.html | 8 ++++---- build-staging/de/docs/contribute/stickers/index.html | 8 ++++---- build-staging/de/docs/contribute/testing/index.html | 8 ++++---- build-staging/de/docs/contribute/translate/index.html | 8 ++++---- .../getting-started/supported_platforms/index.html | 8 ++++---- .../de/docs/groups/accept-group-invite/index.html | 8 ++++---- build-staging/de/docs/groups/create-group/index.html | 8 ++++---- .../de/docs/groups/edit-group-name/index.html | 8 ++++---- build-staging/de/docs/groups/introduction/index.html | 8 ++++---- build-staging/de/docs/groups/leave-group/index.html | 8 ++++---- .../de/docs/groups/manage-known-servers/index.html | 8 ++++---- build-staging/de/docs/groups/send-invite/index.html | 8 ++++---- build-staging/de/docs/intro/index.html | 8 ++++---- build-staging/de/docs/platforms/tails/index.html | 8 ++++---- build-staging/de/docs/platforms/whonix/index.html | 8 ++++---- .../de/docs/profiles/availability-status/index.html | 8 ++++---- build-staging/de/docs/profiles/change-name/index.html | 8 ++++---- .../de/docs/profiles/change-password/index.html | 8 ++++---- .../de/docs/profiles/change-profile-image/index.html | 8 ++++---- .../de/docs/profiles/create-a-profile/index.html | 8 ++++---- .../de/docs/profiles/delete-profile/index.html | 8 ++++---- .../de/docs/profiles/exporting-profile/index.html | 8 ++++---- .../de/docs/profiles/importing-a-profile/index.html | 8 ++++---- build-staging/de/docs/profiles/introduction/index.html | 8 ++++---- build-staging/de/docs/profiles/profile-info/index.html | 8 ++++---- .../de/docs/profiles/unlock-profile/index.html | 8 ++++---- build-staging/de/docs/servers/create-server/index.html | 8 ++++---- build-staging/de/docs/servers/delete-server/index.html | 8 ++++---- build-staging/de/docs/servers/edit-server/index.html | 8 ++++---- build-staging/de/docs/servers/introduction/index.html | 8 ++++---- build-staging/de/docs/servers/share-key/index.html | 8 ++++---- build-staging/de/docs/servers/unlock-server/index.html | 8 ++++---- .../settings/appearance/change-language/index.html | 8 ++++---- .../settings/appearance/light-dark-mode/index.html | 8 ++++---- .../docs/settings/appearance/streamer-mode/index.html | 8 ++++---- .../de/docs/settings/appearance/ui-columns/index.html | 8 ++++---- .../behaviour/block-unknown-connections/index.html | 8 ++++---- .../settings/behaviour/notification-content/index.html | 8 ++++---- .../settings/behaviour/notification-policy/index.html | 8 ++++---- .../settings/experiments/clickable-links/index.html | 8 ++++---- .../docs/settings/experiments/file-sharing/index.html | 8 ++++---- .../settings/experiments/group-experiment/index.html | 8 ++++---- .../image-previews-and-profile-pictures/index.html | 8 ++++---- .../settings/experiments/message-formatting/index.html | 8 ++++---- .../de/docs/settings/experiments/qrcodes/index.html | 8 ++++---- .../settings/experiments/server-hosting/index.html | 8 ++++---- build-staging/de/docs/settings/introduction/index.html | 8 ++++---- build-staging/de/docs/tor/index.html | 8 ++++---- build-staging/de/index.html | 8 ++++---- .../de/security/category/connectivity--tor/index.html | 8 ++++---- .../de/security/category/cwtch-components/index.html | 8 ++++---- build-staging/de/security/category/cwtch-ui/index.html | 8 ++++---- build-staging/de/security/category/cwtch/index.html | 8 ++++---- build-staging/de/security/category/tapir/index.html | 8 ++++---- .../security/components/connectivity/intro/index.html | 8 ++++---- .../de/security/components/cwtch/groups/index.html | 8 ++++---- .../security/components/cwtch/key_bundles/index.html | 8 ++++---- .../components/cwtch/message_formats/index.html | 8 ++++---- .../de/security/components/cwtch/server/index.html | 8 ++++---- .../security/components/ecosystem-overview/index.html | 8 ++++---- build-staging/de/security/components/intro/index.html | 8 ++++---- .../tapir/authentication_protocol/index.html | 8 ++++---- .../security/components/tapir/packet_format/index.html | 8 ++++---- .../de/security/components/ui/android/index.html | 8 ++++---- .../security/components/ui/image_previews/index.html | 8 ++++---- .../de/security/components/ui/input/index.html | 8 ++++---- .../de/security/components/ui/overlays/index.html | 8 ++++---- build-staging/de/security/deployment/index.html | 8 ++++---- build-staging/de/security/development/index.html | 8 ++++---- build-staging/de/security/intro/index.html | 8 ++++---- build-staging/de/security/references/index.html | 8 ++++---- build-staging/de/security/risk/index.html | 8 ++++---- .../building-an-echobot/index.html | 8 ++++---- .../building-a-cwtch-app/core-concepts/index.html | 8 ++++---- .../developing/building-a-cwtch-app/intro/index.html | 8 ++++---- .../category/building-a-cwtch-app/index.html | 8 ++++---- build-staging/developing/intro/index.html | 8 ++++---- build-staging/developing/release/index.html | 8 ++++---- build-staging/docs/category/appearance/index.html | 8 ++++---- build-staging/docs/category/behaviour/index.html | 8 ++++---- build-staging/docs/category/contribute/index.html | 8 ++++---- build-staging/docs/category/conversations/index.html | 8 ++++---- build-staging/docs/category/experiments/index.html | 8 ++++---- build-staging/docs/category/getting-started/index.html | 8 ++++---- build-staging/docs/category/groups/index.html | 8 ++++---- build-staging/docs/category/platforms/index.html | 8 ++++---- build-staging/docs/category/profiles/index.html | 8 ++++---- build-staging/docs/category/servers/index.html | 8 ++++---- build-staging/docs/category/settings/index.html | 8 ++++---- .../docs/chat/accept-deny-new-conversation/index.html | 8 ++++---- build-staging/docs/chat/add-contact/index.html | 8 ++++---- build-staging/docs/chat/block-contact/index.html | 8 ++++---- .../docs/chat/conversation-settings/index.html | 8 ++++---- build-staging/docs/chat/delete-contact/index.html | 8 ++++---- build-staging/docs/chat/introduction/index.html | 8 ++++---- build-staging/docs/chat/message-formatting/index.html | 8 ++++---- build-staging/docs/chat/reply-to-message/index.html | 8 ++++---- .../docs/chat/save-conversation-history/index.html | 8 ++++---- .../docs/chat/share-address-with-friends/index.html | 8 ++++---- build-staging/docs/chat/share-file/index.html | 8 ++++---- build-staging/docs/chat/unblock-contact/index.html | 8 ++++---- build-staging/docs/contribute/developing/index.html | 8 ++++---- build-staging/docs/contribute/documentation/index.html | 8 ++++---- build-staging/docs/contribute/stickers/index.html | 8 ++++---- build-staging/docs/contribute/testing/index.html | 8 ++++---- build-staging/docs/contribute/translate/index.html | 8 ++++---- .../getting-started/supported_platforms/index.html | 8 ++++---- .../docs/groups/accept-group-invite/index.html | 8 ++++---- build-staging/docs/groups/create-group/index.html | 8 ++++---- build-staging/docs/groups/edit-group-name/index.html | 8 ++++---- build-staging/docs/groups/introduction/index.html | 8 ++++---- build-staging/docs/groups/leave-group/index.html | 8 ++++---- .../docs/groups/manage-known-servers/index.html | 8 ++++---- build-staging/docs/groups/send-invite/index.html | 8 ++++---- build-staging/docs/intro/index.html | 8 ++++---- build-staging/docs/platforms/tails/index.html | 8 ++++---- build-staging/docs/platforms/whonix/index.html | 8 ++++---- .../docs/profiles/availability-status/index.html | 8 ++++---- build-staging/docs/profiles/change-name/index.html | 8 ++++---- build-staging/docs/profiles/change-password/index.html | 8 ++++---- .../docs/profiles/change-profile-image/index.html | 8 ++++---- .../docs/profiles/create-a-profile/index.html | 8 ++++---- build-staging/docs/profiles/delete-profile/index.html | 8 ++++---- .../docs/profiles/exporting-profile/index.html | 8 ++++---- .../docs/profiles/importing-a-profile/index.html | 8 ++++---- build-staging/docs/profiles/introduction/index.html | 8 ++++---- build-staging/docs/profiles/profile-info/index.html | 8 ++++---- build-staging/docs/profiles/unlock-profile/index.html | 8 ++++---- build-staging/docs/servers/create-server/index.html | 8 ++++---- build-staging/docs/servers/delete-server/index.html | 8 ++++---- build-staging/docs/servers/edit-server/index.html | 8 ++++---- build-staging/docs/servers/introduction/index.html | 8 ++++---- build-staging/docs/servers/share-key/index.html | 8 ++++---- build-staging/docs/servers/unlock-server/index.html | 8 ++++---- .../settings/appearance/change-language/index.html | 8 ++++---- .../settings/appearance/light-dark-mode/index.html | 8 ++++---- .../docs/settings/appearance/streamer-mode/index.html | 8 ++++---- .../docs/settings/appearance/ui-columns/index.html | 8 ++++---- .../behaviour/block-unknown-connections/index.html | 8 ++++---- .../settings/behaviour/notification-content/index.html | 8 ++++---- .../settings/behaviour/notification-policy/index.html | 8 ++++---- .../settings/experiments/clickable-links/index.html | 8 ++++---- .../docs/settings/experiments/file-sharing/index.html | 8 ++++---- .../settings/experiments/group-experiment/index.html | 8 ++++---- .../image-previews-and-profile-pictures/index.html | 8 ++++---- .../settings/experiments/message-formatting/index.html | 8 ++++---- .../docs/settings/experiments/qrcodes/index.html | 8 ++++---- .../settings/experiments/server-hosting/index.html | 8 ++++---- build-staging/docs/settings/introduction/index.html | 8 ++++---- build-staging/docs/tor/index.html | 8 ++++---- build-staging/es/404.html | 4 ++-- build-staging/es/assets/js/95c68178.22226d85.js | 1 + build-staging/es/assets/js/95c68178.3b47d7b2.js | 1 - .../js/{d0554977.f15b2155.js => d0554977.ff108c58.js} | 2 +- ...ntime~main.46cc586f.js => runtime~main.18cddbba.js} | 2 +- build-staging/es/blog/archive/index.html | 4 ++-- build-staging/es/blog/atom.xml | 2 +- build-staging/es/blog/autobindings-ii/index.html | 4 ++-- build-staging/es/blog/autobindings/index.html | 4 ++-- .../availability-status-profile-attributes/index.html | 4 ++-- build-staging/es/blog/cwtch-1-13/index.html | 4 ++-- .../es/blog/cwtch-android-reproducibility/index.html | 4 ++-- .../es/blog/cwtch-bindings-reproducible/index.html | 4 ++-- .../es/blog/cwtch-developer-documentation/index.html | 4 ++-- build-staging/es/blog/cwtch-documentation/index.html | 4 ++-- build-staging/es/blog/cwtch-nightly-1-11/index.html | 4 ++-- build-staging/es/blog/cwtch-nightly-1-12/index.html | 4 ++-- .../index.html | 4 ++-- .../index.html | 4 ++-- build-staging/es/blog/cwtch-nightly-v.11-74/index.html | 4 ++-- .../es/blog/cwtch-platform-support/index.html | 4 ++-- .../es/blog/cwtch-stable-api-design/index.html | 4 ++-- .../es/blog/cwtch-stable-call-for-credits/index.html | 4 ++-- .../blog/cwtch-stable-roadmap-update-june/index.html | 4 ++-- .../blog/cwtch-stable-roadmap-update-sept/index.html | 4 ++-- .../es/blog/cwtch-stable-roadmap-update/index.html | 4 ++-- build-staging/es/blog/cwtch-testing-i/index.html | 4 ++-- build-staging/es/blog/cwtch-testing-ii/index.html | 4 ++-- .../blog/cwtch-ui-reproducible-builds-linux/index.html | 4 ++-- build-staging/es/blog/feed.json | 2 +- build-staging/es/blog/index.html | 4 ++-- build-staging/es/blog/page/2/index.html | 4 ++-- build-staging/es/blog/page/3/index.html | 4 ++-- build-staging/es/blog/path-to-cwtch-stable/index.html | 4 ++-- build-staging/es/blog/path-to-hybrid-groups/index.html | 6 +++--- build-staging/es/blog/rss.xml | 2 +- build-staging/es/blog/tags/api/index.html | 4 ++-- build-staging/es/blog/tags/autobindings/index.html | 4 ++-- build-staging/es/blog/tags/bindings/index.html | 4 ++-- build-staging/es/blog/tags/community/index.html | 4 ++-- build-staging/es/blog/tags/contributors/index.html | 4 ++-- build-staging/es/blog/tags/cwtch-stable/index.html | 4 ++-- .../es/blog/tags/cwtch-stable/page/2/index.html | 4 ++-- .../es/blog/tags/cwtch-stable/page/3/index.html | 4 ++-- build-staging/es/blog/tags/cwtch/index.html | 4 ++-- build-staging/es/blog/tags/cwtch/page/2/index.html | 4 ++-- build-staging/es/blog/tags/cwtch/page/3/index.html | 4 ++-- .../es/blog/tags/developer-documentation/index.html | 4 ++-- build-staging/es/blog/tags/documentation/index.html | 4 ++-- build-staging/es/blog/tags/hybrid-groups/index.html | 4 ++-- build-staging/es/blog/tags/index.html | 4 ++-- build-staging/es/blog/tags/libcwtch/index.html | 4 ++-- build-staging/es/blog/tags/nightly/index.html | 4 ++-- build-staging/es/blog/tags/planning/index.html | 4 ++-- build-staging/es/blog/tags/preview/index.html | 4 ++-- build-staging/es/blog/tags/release/index.html | 4 ++-- build-staging/es/blog/tags/repliqate/index.html | 4 ++-- .../es/blog/tags/reproducible-builds/index.html | 4 ++-- build-staging/es/blog/tags/search/index.html | 4 ++-- .../es/blog/tags/security-handbook/index.html | 4 ++-- build-staging/es/blog/tags/support/index.html | 4 ++-- build-staging/es/blog/tags/testing/index.html | 4 ++-- build-staging/es/blog/tags/whonix/index.html | 4 ++-- .../building-an-echobot/index.html | 4 ++-- .../building-a-cwtch-app/core-concepts/index.html | 4 ++-- .../developing/building-a-cwtch-app/intro/index.html | 4 ++-- .../category/building-a-cwtch-app/index.html | 4 ++-- build-staging/es/developing/intro/index.html | 4 ++-- build-staging/es/developing/release/index.html | 4 ++-- build-staging/es/docs/category/appearance/index.html | 4 ++-- build-staging/es/docs/category/behaviour/index.html | 4 ++-- build-staging/es/docs/category/contribute/index.html | 4 ++-- .../es/docs/category/conversations/index.html | 4 ++-- build-staging/es/docs/category/experiments/index.html | 4 ++-- .../es/docs/category/getting-started/index.html | 4 ++-- build-staging/es/docs/category/groups/index.html | 4 ++-- build-staging/es/docs/category/platforms/index.html | 4 ++-- build-staging/es/docs/category/profiles/index.html | 4 ++-- build-staging/es/docs/category/servers/index.html | 4 ++-- build-staging/es/docs/category/settings/index.html | 4 ++-- .../docs/chat/accept-deny-new-conversation/index.html | 4 ++-- build-staging/es/docs/chat/add-contact/index.html | 4 ++-- build-staging/es/docs/chat/block-contact/index.html | 4 ++-- .../es/docs/chat/conversation-settings/index.html | 4 ++-- build-staging/es/docs/chat/delete-contact/index.html | 4 ++-- build-staging/es/docs/chat/introduction/index.html | 4 ++-- .../es/docs/chat/message-formatting/index.html | 4 ++-- build-staging/es/docs/chat/reply-to-message/index.html | 4 ++-- .../es/docs/chat/save-conversation-history/index.html | 4 ++-- .../es/docs/chat/share-address-with-friends/index.html | 4 ++-- build-staging/es/docs/chat/share-file/index.html | 4 ++-- build-staging/es/docs/chat/unblock-contact/index.html | 4 ++-- build-staging/es/docs/contribute/developing/index.html | 4 ++-- .../es/docs/contribute/documentation/index.html | 4 ++-- build-staging/es/docs/contribute/stickers/index.html | 4 ++-- build-staging/es/docs/contribute/testing/index.html | 4 ++-- build-staging/es/docs/contribute/translate/index.html | 4 ++-- .../getting-started/supported_platforms/index.html | 4 ++-- .../es/docs/groups/accept-group-invite/index.html | 4 ++-- build-staging/es/docs/groups/create-group/index.html | 4 ++-- .../es/docs/groups/edit-group-name/index.html | 4 ++-- build-staging/es/docs/groups/introduction/index.html | 4 ++-- build-staging/es/docs/groups/leave-group/index.html | 4 ++-- .../es/docs/groups/manage-known-servers/index.html | 4 ++-- build-staging/es/docs/groups/send-invite/index.html | 4 ++-- build-staging/es/docs/intro/index.html | 4 ++-- build-staging/es/docs/platforms/tails/index.html | 4 ++-- build-staging/es/docs/platforms/whonix/index.html | 4 ++-- .../es/docs/profiles/availability-status/index.html | 4 ++-- build-staging/es/docs/profiles/change-name/index.html | 4 ++-- .../es/docs/profiles/change-password/index.html | 4 ++-- .../es/docs/profiles/change-profile-image/index.html | 4 ++-- .../es/docs/profiles/create-a-profile/index.html | 4 ++-- .../es/docs/profiles/delete-profile/index.html | 4 ++-- .../es/docs/profiles/exporting-profile/index.html | 4 ++-- .../es/docs/profiles/importing-a-profile/index.html | 4 ++-- build-staging/es/docs/profiles/introduction/index.html | 4 ++-- build-staging/es/docs/profiles/profile-info/index.html | 4 ++-- .../es/docs/profiles/unlock-profile/index.html | 4 ++-- build-staging/es/docs/servers/create-server/index.html | 4 ++-- build-staging/es/docs/servers/delete-server/index.html | 4 ++-- build-staging/es/docs/servers/edit-server/index.html | 4 ++-- build-staging/es/docs/servers/introduction/index.html | 4 ++-- build-staging/es/docs/servers/share-key/index.html | 4 ++-- build-staging/es/docs/servers/unlock-server/index.html | 4 ++-- .../settings/appearance/change-language/index.html | 4 ++-- .../settings/appearance/light-dark-mode/index.html | 4 ++-- .../docs/settings/appearance/streamer-mode/index.html | 4 ++-- .../es/docs/settings/appearance/ui-columns/index.html | 4 ++-- .../behaviour/block-unknown-connections/index.html | 4 ++-- .../settings/behaviour/notification-content/index.html | 4 ++-- .../settings/behaviour/notification-policy/index.html | 4 ++-- .../settings/experiments/clickable-links/index.html | 4 ++-- .../docs/settings/experiments/file-sharing/index.html | 4 ++-- .../settings/experiments/group-experiment/index.html | 4 ++-- .../image-previews-and-profile-pictures/index.html | 4 ++-- .../settings/experiments/message-formatting/index.html | 4 ++-- .../es/docs/settings/experiments/qrcodes/index.html | 4 ++-- .../settings/experiments/server-hosting/index.html | 4 ++-- build-staging/es/docs/settings/introduction/index.html | 4 ++-- build-staging/es/docs/tor/index.html | 4 ++-- build-staging/es/index.html | 4 ++-- .../es/security/category/connectivity--tor/index.html | 4 ++-- .../es/security/category/cwtch-components/index.html | 4 ++-- build-staging/es/security/category/cwtch-ui/index.html | 4 ++-- build-staging/es/security/category/cwtch/index.html | 4 ++-- build-staging/es/security/category/tapir/index.html | 4 ++-- .../security/components/connectivity/intro/index.html | 4 ++-- .../es/security/components/cwtch/groups/index.html | 4 ++-- .../security/components/cwtch/key_bundles/index.html | 4 ++-- .../components/cwtch/message_formats/index.html | 4 ++-- .../es/security/components/cwtch/server/index.html | 4 ++-- .../security/components/ecosystem-overview/index.html | 4 ++-- build-staging/es/security/components/intro/index.html | 4 ++-- .../tapir/authentication_protocol/index.html | 4 ++-- .../security/components/tapir/packet_format/index.html | 4 ++-- .../es/security/components/ui/android/index.html | 4 ++-- .../security/components/ui/image_previews/index.html | 4 ++-- .../es/security/components/ui/input/index.html | 4 ++-- .../es/security/components/ui/overlays/index.html | 4 ++-- build-staging/es/security/deployment/index.html | 4 ++-- build-staging/es/security/development/index.html | 4 ++-- build-staging/es/security/intro/index.html | 4 ++-- build-staging/es/security/references/index.html | 4 ++-- build-staging/es/security/risk/index.html | 4 ++-- build-staging/index.html | 8 ++++---- build-staging/it/404.html | 8 ++++---- build-staging/it/assets/js/0a2b8ac2.94005e55.js | 1 + build-staging/it/assets/js/0a2b8ac2.9523f8cd.js | 1 - .../js/{d0554977.293a51bb.js => d0554977.9e6314c5.js} | 2 +- .../assets/js/{main.85e4969d.js => main.5814373c.js} | 4 ++-- ...69d.js.LICENSE.txt => main.5814373c.js.LICENSE.txt} | 0 ...ntime~main.a0965673.js => runtime~main.d1f2aa69.js} | 2 +- build-staging/it/blog/archive/index.html | 8 ++++---- build-staging/it/blog/atom.xml | 2 +- build-staging/it/blog/autobindings-ii/index.html | 8 ++++---- build-staging/it/blog/autobindings/index.html | 8 ++++---- .../availability-status-profile-attributes/index.html | 8 ++++---- build-staging/it/blog/cwtch-1-13/index.html | 8 ++++---- .../it/blog/cwtch-android-reproducibility/index.html | 8 ++++---- .../it/blog/cwtch-bindings-reproducible/index.html | 8 ++++---- .../it/blog/cwtch-developer-documentation/index.html | 8 ++++---- build-staging/it/blog/cwtch-documentation/index.html | 8 ++++---- build-staging/it/blog/cwtch-nightly-1-11/index.html | 8 ++++---- build-staging/it/blog/cwtch-nightly-1-12/index.html | 8 ++++---- .../index.html | 8 ++++---- .../index.html | 8 ++++---- build-staging/it/blog/cwtch-nightly-v.11-74/index.html | 8 ++++---- .../it/blog/cwtch-platform-support/index.html | 8 ++++---- .../it/blog/cwtch-stable-api-design/index.html | 8 ++++---- .../it/blog/cwtch-stable-call-for-credits/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-june/index.html | 8 ++++---- .../blog/cwtch-stable-roadmap-update-sept/index.html | 8 ++++---- .../it/blog/cwtch-stable-roadmap-update/index.html | 8 ++++---- build-staging/it/blog/cwtch-testing-i/index.html | 8 ++++---- build-staging/it/blog/cwtch-testing-ii/index.html | 8 ++++---- .../blog/cwtch-ui-reproducible-builds-linux/index.html | 8 ++++---- build-staging/it/blog/feed.json | 2 +- build-staging/it/blog/index.html | 8 ++++---- build-staging/it/blog/page/2/index.html | 8 ++++---- build-staging/it/blog/page/3/index.html | 8 ++++---- build-staging/it/blog/path-to-cwtch-stable/index.html | 8 ++++---- build-staging/it/blog/path-to-hybrid-groups/index.html | 10 +++++----- build-staging/it/blog/rss.xml | 2 +- build-staging/it/blog/tags/api/index.html | 8 ++++---- build-staging/it/blog/tags/autobindings/index.html | 8 ++++---- build-staging/it/blog/tags/bindings/index.html | 8 ++++---- build-staging/it/blog/tags/community/index.html | 8 ++++---- build-staging/it/blog/tags/contributors/index.html | 8 ++++---- build-staging/it/blog/tags/cwtch-stable/index.html | 8 ++++---- .../it/blog/tags/cwtch-stable/page/2/index.html | 8 ++++---- .../it/blog/tags/cwtch-stable/page/3/index.html | 8 ++++---- build-staging/it/blog/tags/cwtch/index.html | 8 ++++---- build-staging/it/blog/tags/cwtch/page/2/index.html | 8 ++++---- build-staging/it/blog/tags/cwtch/page/3/index.html | 8 ++++---- .../it/blog/tags/developer-documentation/index.html | 8 ++++---- build-staging/it/blog/tags/documentation/index.html | 8 ++++---- build-staging/it/blog/tags/hybrid-groups/index.html | 8 ++++---- build-staging/it/blog/tags/index.html | 8 ++++---- build-staging/it/blog/tags/libcwtch/index.html | 8 ++++---- build-staging/it/blog/tags/nightly/index.html | 8 ++++---- build-staging/it/blog/tags/planning/index.html | 8 ++++---- build-staging/it/blog/tags/preview/index.html | 8 ++++---- build-staging/it/blog/tags/release/index.html | 8 ++++---- build-staging/it/blog/tags/repliqate/index.html | 8 ++++---- .../it/blog/tags/reproducible-builds/index.html | 8 ++++---- build-staging/it/blog/tags/search/index.html | 8 ++++---- .../it/blog/tags/security-handbook/index.html | 8 ++++---- build-staging/it/blog/tags/support/index.html | 8 ++++---- build-staging/it/blog/tags/testing/index.html | 8 ++++---- build-staging/it/blog/tags/whonix/index.html | 8 ++++---- .../building-an-echobot/index.html | 8 ++++---- .../building-a-cwtch-app/core-concepts/index.html | 8 ++++---- .../developing/building-a-cwtch-app/intro/index.html | 8 ++++---- .../category/building-a-cwtch-app/index.html | 8 ++++---- build-staging/it/developing/intro/index.html | 8 ++++---- build-staging/it/developing/release/index.html | 8 ++++---- build-staging/it/docs/category/appearance/index.html | 8 ++++---- build-staging/it/docs/category/behaviour/index.html | 8 ++++---- build-staging/it/docs/category/contribute/index.html | 8 ++++---- .../it/docs/category/conversations/index.html | 8 ++++---- build-staging/it/docs/category/experiments/index.html | 8 ++++---- .../it/docs/category/getting-started/index.html | 8 ++++---- build-staging/it/docs/category/groups/index.html | 8 ++++---- build-staging/it/docs/category/platforms/index.html | 8 ++++---- build-staging/it/docs/category/profiles/index.html | 8 ++++---- build-staging/it/docs/category/servers/index.html | 8 ++++---- build-staging/it/docs/category/settings/index.html | 8 ++++---- .../docs/chat/accept-deny-new-conversation/index.html | 8 ++++---- build-staging/it/docs/chat/add-contact/index.html | 8 ++++---- build-staging/it/docs/chat/block-contact/index.html | 8 ++++---- .../it/docs/chat/conversation-settings/index.html | 8 ++++---- build-staging/it/docs/chat/delete-contact/index.html | 8 ++++---- build-staging/it/docs/chat/introduction/index.html | 8 ++++---- .../it/docs/chat/message-formatting/index.html | 8 ++++---- build-staging/it/docs/chat/reply-to-message/index.html | 8 ++++---- .../it/docs/chat/save-conversation-history/index.html | 8 ++++---- .../it/docs/chat/share-address-with-friends/index.html | 8 ++++---- build-staging/it/docs/chat/share-file/index.html | 8 ++++---- build-staging/it/docs/chat/unblock-contact/index.html | 8 ++++---- build-staging/it/docs/contribute/developing/index.html | 8 ++++---- .../it/docs/contribute/documentation/index.html | 8 ++++---- build-staging/it/docs/contribute/stickers/index.html | 8 ++++---- build-staging/it/docs/contribute/testing/index.html | 8 ++++---- build-staging/it/docs/contribute/translate/index.html | 8 ++++---- .../getting-started/supported_platforms/index.html | 8 ++++---- .../it/docs/groups/accept-group-invite/index.html | 8 ++++---- build-staging/it/docs/groups/create-group/index.html | 8 ++++---- .../it/docs/groups/edit-group-name/index.html | 8 ++++---- build-staging/it/docs/groups/introduction/index.html | 8 ++++---- build-staging/it/docs/groups/leave-group/index.html | 8 ++++---- .../it/docs/groups/manage-known-servers/index.html | 8 ++++---- build-staging/it/docs/groups/send-invite/index.html | 8 ++++---- build-staging/it/docs/intro/index.html | 8 ++++---- build-staging/it/docs/platforms/tails/index.html | 8 ++++---- build-staging/it/docs/platforms/whonix/index.html | 8 ++++---- .../it/docs/profiles/availability-status/index.html | 8 ++++---- build-staging/it/docs/profiles/change-name/index.html | 8 ++++---- .../it/docs/profiles/change-password/index.html | 8 ++++---- .../it/docs/profiles/change-profile-image/index.html | 8 ++++---- .../it/docs/profiles/create-a-profile/index.html | 8 ++++---- .../it/docs/profiles/delete-profile/index.html | 8 ++++---- .../it/docs/profiles/exporting-profile/index.html | 8 ++++---- .../it/docs/profiles/importing-a-profile/index.html | 8 ++++---- build-staging/it/docs/profiles/introduction/index.html | 8 ++++---- build-staging/it/docs/profiles/profile-info/index.html | 8 ++++---- .../it/docs/profiles/unlock-profile/index.html | 8 ++++---- build-staging/it/docs/servers/create-server/index.html | 8 ++++---- build-staging/it/docs/servers/delete-server/index.html | 8 ++++---- build-staging/it/docs/servers/edit-server/index.html | 8 ++++---- build-staging/it/docs/servers/introduction/index.html | 8 ++++---- build-staging/it/docs/servers/share-key/index.html | 8 ++++---- build-staging/it/docs/servers/unlock-server/index.html | 8 ++++---- .../settings/appearance/change-language/index.html | 8 ++++---- .../settings/appearance/light-dark-mode/index.html | 8 ++++---- .../docs/settings/appearance/streamer-mode/index.html | 8 ++++---- .../it/docs/settings/appearance/ui-columns/index.html | 8 ++++---- .../behaviour/block-unknown-connections/index.html | 8 ++++---- .../settings/behaviour/notification-content/index.html | 8 ++++---- .../settings/behaviour/notification-policy/index.html | 8 ++++---- .../settings/experiments/clickable-links/index.html | 8 ++++---- .../docs/settings/experiments/file-sharing/index.html | 8 ++++---- .../settings/experiments/group-experiment/index.html | 8 ++++---- .../image-previews-and-profile-pictures/index.html | 8 ++++---- .../settings/experiments/message-formatting/index.html | 8 ++++---- .../it/docs/settings/experiments/qrcodes/index.html | 8 ++++---- .../settings/experiments/server-hosting/index.html | 8 ++++---- build-staging/it/docs/settings/introduction/index.html | 8 ++++---- build-staging/it/docs/tor/index.html | 8 ++++---- build-staging/it/index.html | 8 ++++---- .../it/security/category/connectivity--tor/index.html | 8 ++++---- .../it/security/category/cwtch-components/index.html | 8 ++++---- build-staging/it/security/category/cwtch-ui/index.html | 8 ++++---- build-staging/it/security/category/cwtch/index.html | 8 ++++---- build-staging/it/security/category/tapir/index.html | 8 ++++---- .../security/components/connectivity/intro/index.html | 8 ++++---- .../it/security/components/cwtch/groups/index.html | 8 ++++---- .../security/components/cwtch/key_bundles/index.html | 8 ++++---- .../components/cwtch/message_formats/index.html | 8 ++++---- .../it/security/components/cwtch/server/index.html | 8 ++++---- .../security/components/ecosystem-overview/index.html | 8 ++++---- build-staging/it/security/components/intro/index.html | 8 ++++---- .../tapir/authentication_protocol/index.html | 8 ++++---- .../security/components/tapir/packet_format/index.html | 8 ++++---- .../it/security/components/ui/android/index.html | 8 ++++---- .../security/components/ui/image_previews/index.html | 8 ++++---- .../it/security/components/ui/input/index.html | 8 ++++---- .../it/security/components/ui/overlays/index.html | 8 ++++---- build-staging/it/security/deployment/index.html | 8 ++++---- build-staging/it/security/development/index.html | 8 ++++---- build-staging/it/security/intro/index.html | 8 ++++---- build-staging/it/security/references/index.html | 8 ++++---- build-staging/it/security/risk/index.html | 8 ++++---- .../security/category/connectivity--tor/index.html | 8 ++++---- .../security/category/cwtch-components/index.html | 8 ++++---- build-staging/security/category/cwtch-ui/index.html | 8 ++++---- build-staging/security/category/cwtch/index.html | 8 ++++---- build-staging/security/category/tapir/index.html | 8 ++++---- .../security/components/connectivity/intro/index.html | 8 ++++---- .../security/components/cwtch/groups/index.html | 8 ++++---- .../security/components/cwtch/key_bundles/index.html | 8 ++++---- .../components/cwtch/message_formats/index.html | 8 ++++---- .../security/components/cwtch/server/index.html | 8 ++++---- .../security/components/ecosystem-overview/index.html | 8 ++++---- build-staging/security/components/intro/index.html | 8 ++++---- .../tapir/authentication_protocol/index.html | 8 ++++---- .../security/components/tapir/packet_format/index.html | 8 ++++---- .../security/components/ui/android/index.html | 8 ++++---- .../security/components/ui/image_previews/index.html | 8 ++++---- build-staging/security/components/ui/input/index.html | 8 ++++---- .../security/components/ui/overlays/index.html | 8 ++++---- build-staging/security/deployment/index.html | 8 ++++---- build-staging/security/development/index.html | 8 ++++---- build-staging/security/intro/index.html | 8 ++++---- build-staging/security/references/index.html | 8 ++++---- build-staging/security/risk/index.html | 8 ++++---- 666 files changed, 2246 insertions(+), 2246 deletions(-) create mode 100644 build-staging/assets/js/b2f554cd.0f0f1284.js delete mode 100644 build-staging/assets/js/b2f554cd.f51eff8b.js rename build-staging/assets/js/{d0554977.42033312.js => d0554977.2cdbecbc.js} (78%) rename build-staging/assets/js/{main.c59698c8.js => main.10f93ed4.js} (99%) rename build-staging/assets/js/{main.c59698c8.js.LICENSE.txt => main.10f93ed4.js.LICENSE.txt} (100%) rename build-staging/assets/js/{runtime~main.e83a6af5.js => runtime~main.f1b2e7b1.js} (99%) delete mode 100644 build-staging/de/assets/js/291c70d7.b8d036cc.js create mode 100644 build-staging/de/assets/js/291c70d7.ca422c75.js rename build-staging/de/assets/js/{d0554977.cd662b0d.js => d0554977.4178d8ba.js} (77%) rename build-staging/de/assets/js/{main.aac398cc.js => main.f32429d1.js} (97%) rename build-staging/de/assets/js/{main.aac398cc.js.LICENSE.txt => main.f32429d1.js.LICENSE.txt} (100%) rename build-staging/de/assets/js/{runtime~main.cab19c87.js => runtime~main.5d8afb8d.js} (99%) create mode 100644 build-staging/es/assets/js/95c68178.22226d85.js delete mode 100644 build-staging/es/assets/js/95c68178.3b47d7b2.js rename build-staging/es/assets/js/{d0554977.f15b2155.js => d0554977.ff108c58.js} (77%) rename build-staging/es/assets/js/{runtime~main.46cc586f.js => runtime~main.18cddbba.js} (98%) create mode 100644 build-staging/it/assets/js/0a2b8ac2.94005e55.js delete mode 100644 build-staging/it/assets/js/0a2b8ac2.9523f8cd.js rename build-staging/it/assets/js/{d0554977.293a51bb.js => d0554977.9e6314c5.js} (77%) rename build-staging/it/assets/js/{main.85e4969d.js => main.5814373c.js} (97%) rename build-staging/it/assets/js/{main.85e4969d.js.LICENSE.txt => main.5814373c.js.LICENSE.txt} (100%) rename build-staging/it/assets/js/{runtime~main.a0965673.js => runtime~main.d1f2aa69.js} (98%) diff --git a/build-staging/404.html b/build-staging/404.html index e780a4b0..bc7f8908 100644 --- a/build-staging/404.html +++ b/build-staging/404.html @@ -12,13 +12,13 @@ - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - + + \ No newline at end of file diff --git a/build-staging/assets/js/b2f554cd.0f0f1284.js b/build-staging/assets/js/b2f554cd.0f0f1284.js new file mode 100644 index 00000000..bf9ccd86 --- /dev/null +++ b/build-staging/assets/js/b2f554cd.0f0f1284.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1477],{10:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"path-to-hybrid-groups","metadata":{"permalink":"/blog/path-to-hybrid-groups","source":"@site/blog/2024-01-05-path-to-hybrid-groups.md","title":"Path to Hybrid Groups","description":"A look at how we plan on implementing the next generation of Cwtch multi-party messaging","date":"2024-01-05T00:00:00.000Z","formattedDate":"January 5, 2024","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"hybrid-groups","permalink":"/blog/tags/hybrid-groups"}],"readingTime":5.14,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Path to Hybrid Groups","description":"A look at how we plan on implementing the next generation of Cwtch multi-party messaging","slug":"path-to-hybrid-groups","tags":["cwtch","hybrid-groups"],"image":"/img/hybridgroups.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"nextItem":{"title":"Cwtch 1.13 Stable Release Candidate","permalink":"/blog/cwtch-1-13"}},"content":"Back in [September 2023 we released Cwtch 1.13](/blog/cwtch-1-13), the first version of Cwtch to be labelled as **stable**, \\nand a major milestone in Cwtch development. \\n\\nWith the Cwtch interface now stable, we are in a position to begin a new phase in Cwtch development: a Path towards\\n**Hybrid Groups**.\\n\\n![](/img/hybridgroups.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## The Problem with Cwtch Groups\\n\\nOne of the unique features of Cwtch is that [groups](/docs/groups/introduction) are dependent on [untrusted infrastructure](/security/components/cwtch/server).\\n\\nBecause of this, at their most basic, a Cwtch group is simply an agreement between a set of peers on a common\\ncryptographic key, and a common (set of) untrusted server(s).\\n\\nThis provides Cwtch Groups with very nice properties such as anonymity to anyone not in the group, but it does mean\\nthat certain other nice properties like member flexibility, and credential rotation are difficult to achieve.\\n\\nWe want to allow people to make the right trade-off when it comes to their own risk models, i.e. to be able to trade\\nefficiency for trust when that decision makes sense.\\n\\nTo do that we need to introduce a new class of group into Cwtch, something we are calling **Hybrid Groups**.\\n\\n## What Are Hybrid Groups?\\n\\nThe goal of hybrid groups is to balance the security properties of Cwtch peer-to-peer communication with the\\nproperties of untrusted infrastructure. \\n\\nThis is done by augmenting existing Cwtch Groups with an additional layer of peer-to-peer communication in order to provide\\nefficient participant management, key rotation, and other useful features.\\n\\n### Levels of Hybrid Groups\\n\\nIn practice, we imagine there will be a few different levels of Hybrid Group, reflecting different trade-offs between inter-peer trust,\\ncommunication efficiency, and group security.\\n\\nThere are **Traditional Groups**, these have similar properties to the existing Cwtch Groups. Highly inefficient, but essentially \\nrequire zero-trust on behalf of participants other than an expectation that the key is kept secret.\\n\\nWe plan to introduce **Managed Groups**: A new kind of group where all participants explicitly trust a given always-online peer (e.g. a bot) with group operations. These \\nwill be highly efficient, at the cost of that explicit trust (if that peer behaves maliciously then certain properties are broken). Managed groups will\\nbe the first Cwtch groups to allow **Contractable** and **Expandable** groups, and more efficient **Key Rotation**.\\n\\nAnd finally a category of **Augmented Groups**: An extension of Managed Groups that places configurable restrictions of the trust given to \\nthe peer e.g. by requiring participants to take part in a meta-protocol that confirms certain actions before they are carried out (preventing\\nthe trusted-peer from harming properties like **Participant Consistency**.\\n\\n## Group Messaging Metadata\\n\\nAs with the rest of Cwtch, our ultimate goal is that no metadata (and specifically as part of this work, no group metadata e.g. membership, message timing) be\\navailable to a party outside of the group.\\n\\nTraditional Cwtch Groups take this to the extreme, and the expense of long syncing times, and a high possibility of disruption. Managed Groups\\nand Augmented groups will allow communities to make the right trade-offs allowing for greater resilience and faster syncing.\\n\\n## A Rough Timeline (Q1: Week 0 - Week 10 2024)\\n\\n- **Week 0** - Planning Q1 Cwtch Timeline (this devlog), minor bug fixes and other small UI-focused work originating from reports and feedback\\nfrom [Cwtch testers](/docs/contribute/testing).\\n- **Week 1** - Work begins on exposing **Enhanced Permissions** in the Cwtch library. These are essential to implementing many of the aspects\\nof the new group design, as well as improving other parts of contact management. (Expect more about this in a future devlog). Also, a formal model for Managed Groups will be created and documented. \\nThis will form the basis of the implementation.\\n- **Week 2** - At this point we should be able to begin designing the Managed Group Extension to Cwtch. This will use the Cwtch Event Hooks API\\nto respond to Peer events to manage groups. During this work, we also expect to migrate the legacy group code into it\'s own similar extension to make\\nbest use of the APIs. \\n- **Week 3** - Towards the end of January we expect to have a complete formal model of Managed Groups and to be able to start integrating the new extensions into the\\nCwtch-UI. We also expect to be in the process of releasing a new 1.14 version of Cwtch that supports Enhanced Permissions.\\n- **Weeks 4 - Week 6** - February marks the 6th anniversary of the founding of [Open Privacy Research Society](https://openprivacy.ca), and our organizational year end. During this\\ntime core members of the Cwtch team are often involved in administrative tasks that need to be done during this time, as such we are not planning to make too much progress on Cwtch during this time.\\n- **Weeks 7 - Week 10** - As we approach March, we will be formally integrating Managed Groups in Cwtch, and planning a Cwtch 1.15 release which will feature the new group type. During this time we will also be updating\\nCwtch [Group Documentation](https://docs.cwtch.im/docs/category/groups) .\\n\\nOnce Managed Groups have been rolled out, we will assess what we have learned and proceed with similar steps for \\nAugmented Groups in Q2 (more on that in a later devlog!).\\n\\n## Stay up to date!\\n\\nAs always, we will be regularly updating this devlog [and other channels](https://fosstodon.org/@cwtch) as we continue to make progress towards\\nsurveillance resistant infrastructure!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-1-13","metadata":{"permalink":"/blog/cwtch-1-13","source":"@site/blog/2023-09-27-cwtch-1.13-nightly.md","title":"Cwtch 1.13 Stable Release Candidate","description":"Cwtch 1.13 (Stable Release Candidate)","date":"2023-09-27T00:00:00.000Z","formattedDate":"September 27, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":5.74,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch 1.13 Stable Release Candidate","description":"Cwtch 1.13 (Stable Release Candidate)","slug":"cwtch-1-13","tags":["cwtch","cwtch-stable","release"],"image":"/img/picnic1.13.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Path to Hybrid Groups","permalink":"/blog/path-to-hybrid-groups"},"nextItem":{"title":"September Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-sept"}},"content":"[Cwtch 1.13 is now available for download](https://cwtch.im/download)!\\n\\nCwtch is a communication application (and associated libraries) that uses Tor v3 Onion Services to establish surveillance resistant channels between people. Cwtch has been designed to be \\nsecure, private, and resilient.\\n\\nCwtch 1.13 is the culmination of the last few years of effort by the Cwtch team, and is the first release that meets our bar to be labelled a [Cwtch Stable](/blog/path-to-cwtch-stable) candidate.\\n\\nWhile much more work remains, we are now very confident in the state of the Cwtch library, and the Cwtch UI. We are prepared to make certain commitments regarding peer-to-peer messaging, the UI,\\nand experimental interfaces. In this post we will chart the journey that got us to this point, highlight what is in this new release, and talk about our next steps.\\n\\n![](/img/devlog14.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Cwtch Stable and Beyond!\\n\\nOver five years ago, on the 28th June 2018, we published the first official announcement of Cwtch. Throughout 2019 we published various Alpha releases of Cwtch. The original plan was to release a Cwtch Beta in 2020.\\n\\nLike so many other projects in 2020, Cwtch Beta was delayed, and towards the end of 2020 it became clear that our original approach to a cross-platform UI was not sustainable long term.\\n\\nFinally, in June 2021 we launched Cwtch Beta 1.0. We have spent the years since refining beta, adding features, and responding to feedback.\\n\\nWe have now reached a pivotal moment in Cwtch, one that the team has been working towards for many years. We now believe that Cwtch has reached a point where people can use core features, and enable\\nexperimental features, with a confidence that any risks are well understood and appropriately mitigated. As such we are dropping the \\"beta\\" label.\\n\\nSome features, like automatically downloading and displaying images, will always carry some risk - as such these will always remain off-by-default in Cwtch. \\n\\nHowever, if approporate precautions are taken (like never accepting conversations from untrusted entities) then these features can be turned on and used without additional considerable risk.\\n\\nFurther, we believe that the API presented by libCwtch has reached a point where its core design is unlikely to require changes - and as such are prepared to make additional committements to the stability\\nof that API going forward. Any new functionality will be provided by new interfaces, or otherwise be handled behind the scenes.\\n\\nThis is certainly not the end of Cwtch development. We have big plans for the future including the long-anticipated Hybrid Groups\\nimplementation, a light client for restricted mobile operating systems, a return of the bulletin boards overlay, and much more.\\n\\nWe want to extend a huge thank you to everyone who helped Cwtch get this far. We could not have done it without you. If you\\nhave helped in any way and would like to be listed in the contributor credits [please reach out](https://docs.cwtch.im/blog/cwtch-stable-call-for-credits).\\n\\n## A Big Thank You\\n\\nOn a personal note, as Executive Director of Open Privacy, and lead of the Cwtch project. I want to take this opportunity to thank the Cwtch core team across time: Dan Ballard, Erinn Atwater and Marcia D\xedaz Agudelo - this work isn\u2019t glamorous, and doesn\u2019t pay well, \\nthere is no profit to be made in decentralizing power. A lack of funding means we don\'t all work together any more, but you all still contribute so much to this project.\\n\\nIt takes a special kind of person to be willing to spend a significant fraction of their lives devoted to working on something for the benefit of other people. \\nThank you for believing in this mission.\\n\\nI also want to say thank you to all the people who tested Cwtch over the years and provided invaluable feedback, bug reports and critique. \\nYou have made Cwtch what it is today, and I am sure you will be making it even better in the coming weeks, months, and years.\\n\\nLast, but certainly not least, I want to extend a big thank you to all of the supporters of Open Privacy around the world - without your donations\\n and continued enthusiasm for the work that we do, none of this would be possible.\\n\\n## Download Cwtch 1.13\\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic1.13.png)](/img/picnic1.13.png)\\n\\n
A screenshot of Cwtch 1.13
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Conversation Search** - Cwtch can now find messages based on their content.\\n - **Appear Offline Mode** - in this mode Cwtch does not launch a listening service for inbound contacts, and allows a profile to be more selective in the contacts they connect to.\\n - **Whonix Support** - new runtime flags make changes that allow Cwtch to [run on Whonix](https://docs.cwtch.im/docs/platforms/whonix)\\n - **Save History Global Setting** - by default Cwtch deletes all messages on shutdown unless a conversation is otherwise configured. This change allows a user to change this default behaviour.\\n- **Bug Fixes / Improvements:**\\n - Based on Flutter 3.13.4\\n - Updated Android Target to 33\\n - Profile Status Menu now has many more options, including offline status, edit profile and enabling/disabling profile\\n - File Sharing Bug Fixes\\n - Manage shared files now supports re-enabling older file shares\\n - Improvements towards [UI Reproducible Builds](https://docs.cwtch.im/blog/cwtch-ui-reproducible-builds-linux)\\n - Server Info now propagates to the UI consistently\\n - Prevent DBus Exceptions on platforms where it is unsupported\\n - Packaged Emoji Font\\n - Fixes to retry manager which have greater improved (re)connection efficacy\\n - Allow deleting server info in Manage Servers\\n- **Accessibility / UX:**\\n - Core translations for **Brazilian Portuguese**, **Danish** , **Dutch**, **French**, **German**, **Italian**, **Norwegian** , **Romanian** , **Russian**, **Polish**, **Slovak**, **Spanish**, **Swahili**, **Swedish**, **Turkish**, and **Welsh**\\n - Partial translations for **Korean** (37%), **Japanese** (27%), , **Luxembourgish** (20%), **Greek** (15%), **Uzbek** (10%), and **Portuguese** (5%)\\n - Font Scaling improvements on several screens\\n\\n## Reproducible Bindings\\n\\nCwtch 1.13 is based on libCwtch version `libCwtch-autobindings-2023-09-26-13-15-v0.0.10`. \\nThe [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source \\ncan be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.10](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.10)\\n\\n\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update-sept","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update-sept","source":"@site/blog/2023-09-06-cwtch-stable-roadmap-update.md","title":"September Cwtch Stable Roadmap Update","description":"Back in July we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","date":"2023-09-06T00:00:00.000Z","formattedDate":"September 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":3.265,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"September Cwtch Stable Roadmap Update","description":"Back in July we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","slug":"cwtch-stable-roadmap-update-sept","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch 1.13 Stable Release Candidate","permalink":"/blog/cwtch-1-13"},"nextItem":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","permalink":"/blog/cwtch-nightly-preview-whonix-save-history"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider \\nCwtch to be secure and usable. We have been working hard towards that goal over the last year.\\n\\nToday, as we approach the release of Cwtch Stable we would like to provide another update on the ongoing work, and the remaining blockers to certifying a Cwtch Stable release. We also have a new nightly to\\ntest out!\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stable Blocker and Timelines\\n\\nBack in January we set the ambitious goal of launching a Cwtch Stable in the Summer of 2023. We had planned to finish all of the work\\nprior to the end of August. The vast majority of that work has now been completed - what remains is captured in [Stable Blockers](https://git.openprivacy.ca/cwtch.im/cwtch-ui/projects/15) project which tracks the current state\\nof work that we have marked as being critical to a Cwtch Stable release.\\n\\nDespite there being a large number of remaining issues, many of the outstanding work is inter-related, relies on common implementations or\\n are tightly coupled together.\\n\\n In summary the final few areas of concern are:\\n\\n - The ability to delete or purge group conversation history. (For historical reasons storing group history was once considered necessary\\n but this is no longer the case. We plan on enabling this feature in the coming weeks)\\n - Appropriate handling of less common system configurations. Cwtch current emits non-fatal exceptions if certain services are not available\\n e.g. dbus. This is related to former 3rd party code for managing networking and notification.\\n - A final UI pass. We have designs for better ways to convey certain information and functionality. We would like to implement these\\n prior to a stable release.\\n\\nBecause of this, we have set a goal of labelling a Cwtch Stable Release Candidate by **30th September 2023**.\\n\\n## A New Nightly\\n\\nThere is a [new nightly version of Cwtch available for testing (2023-09-06-21-25-v1.12.0-33-g05b1)](https://build.openprivacy.ca/files/flwtch-2023-09-06-21-25-v1.12.0-33-g05b1/). This version contains a few bug fixes related to file share management,\\nin addition to a significant improvement in the connection management code.\\n\\nAdditionally, thanks to volunteer testers [and contributors](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/715) the installation instructions\\nand packaged configurations for Whonix have been much improved. See [running Cwtch on Whonix](https://docs.cwtch.im/docs/platforms/whonix) for more information.\\n\\n## Get Involved\\n\\nStaff and volunteer shortages have slightly extended our original estimates. In particular we are bottle-necked on review effort for new code. This is\\nwhy we would like to encourage people to test out the latest nightlies and report any bugs/issues/improvements.\\n\\nIn order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-preview-whonix-save-history","metadata":{"permalink":"/blog/cwtch-nightly-preview-whonix-save-history","source":"@site/blog/2023-08-18-whonix-nightly-preview.md","title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","description":"A new Cwtch Nightly contains a first cut of support for Whonix, Default Save History, Bug Fixes","date":"2023-08-18T00:00:00.000Z","formattedDate":"August 18, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"},{"label":"whonix","permalink":"/blog/tags/whonix"},{"label":"preview","permalink":"/blog/tags/preview"}],"readingTime":1.04,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","description":"A new Cwtch Nightly contains a first cut of support for Whonix, Default Save History, Bug Fixes","slug":"cwtch-nightly-preview-whonix-save-history","tags":["cwtch","cwtch-stable","nightly","whonix","preview"],"image":"/img/devlog10_small.png","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"September Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-sept"},"nextItem":{"title":"Nightly Preview: Conversation Search","permalink":"/blog/cwtch-nightly-preview-conversation-search"}},"content":"There is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing \\nis [2023-08-22-23-27-v1.12.0-25-ge019f](https://build.openprivacy.ca/files/flwtch-2023-08-22-23-27-v1.12.0-25-ge019f/).\\n\\nThis nightly contains a first cut of [support for Whonix](https://docs.cwtch.im/docs/platforms/whonix), a new global setting for managing how conversation\\nhistory is preserved, in addition to several bug fixes reported in the last nightly.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n![](/img/devlog10.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-preview-conversation-search","metadata":{"permalink":"/blog/cwtch-nightly-preview-conversation-search","source":"@site/blog/2023-08-03-nightly-preview-conversation-search.md","title":"Nightly Preview: Conversation Search","description":"A new Cwtch Nightly contains a first cut of Conversation Search.","date":"2023-08-03T00:00:00.000Z","formattedDate":"August 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"},{"label":"search","permalink":"/blog/tags/search"},{"label":"preview","permalink":"/blog/tags/preview"}],"readingTime":1.12,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Nightly Preview: Conversation Search","description":"A new Cwtch Nightly contains a first cut of Conversation Search.","slug":"cwtch-nightly-preview-conversation-search","tags":["cwtch","cwtch-stable","nightly","search","preview"],"image":"/img/devlog10_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","permalink":"/blog/cwtch-nightly-preview-whonix-save-history"},"nextItem":{"title":"Cwtch Call for Contributor Credits","permalink":"/blog/cwtch-stable-call-for-credits"}},"content":"There is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing \\nis [2023-08-02-20-24-v1.12.0-19-g75b7](https://build.openprivacy.ca/files/flwtch-2023-08-02-20-24-v1.12.0-19-g75b7/).\\n\\nThis nightly contains a first cut of Conversation Search, in addition to several bug fixes impacting effectiveness of the contact retry plugin when combined with a large contact list, and an unstable network\\nconnection. Finally we have made a few tweaks to the font scaling based on feedback.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n![](/img/search-nightly.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-call-for-credits","metadata":{"permalink":"/blog/cwtch-stable-call-for-credits","source":"@site/blog/2023-07-26-cwtch-stable-call-for-credits.md","title":"Cwtch Call for Contributor Credits","description":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed to Cwtch over the years have the optiont to be credited.","date":"2023-07-26T00:00:00.000Z","formattedDate":"July 26, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"contributors","permalink":"/blog/tags/contributors"},{"label":"community","permalink":"/blog/tags/community"}],"readingTime":2.91,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Call for Contributor Credits","description":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed to Cwtch over the years have the optiont to be credited.","slug":"cwtch-stable-call-for-credits","tags":["cwtch","cwtch-stable","contributors","community"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Nightly Preview: Conversation Search","permalink":"/blog/cwtch-nightly-preview-conversation-search"},"nextItem":{"title":"Progress Towards Reproducible UI Builds","permalink":"/blog/cwtch-ui-reproducible-builds-linux"}},"content":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed\\nto Cwtch over the years have the option to be credited in some way.\\n\\nIf you have participated in the development process in any way e.g. protocol design, writing code, UI design, writing tests, testing release candidates, reporting issues,\\ntranslating the application or documentation, promoting metadata resistant applications or any other meaningful contribution to the Cwtch ecosystem we want\\nto offer you the option to have your name or handle credited in both the source code repository and the application itself.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## A History of Cwtch Contibutions and Anonmymity \\n\\nIn the early days of Cwtch we made the explicit decision to not include credits anywhere in the application, and to accept contributions\\nanonymously over a variety of channels, including Cwtch itself.\\n\\nDue to the nature of the application, and the privacy and metadata resistant space in general, we have always had a policy of\\nevaluating contributions based on merit, and not on identity. This approach means that, while we do have contributors whose identity\\nis known to us in some way, we have many who we know only by writing style, contribution type, or cwtch address.\\n\\nWe understand that many people much prefer it this way, and have no desire to have any identity linked to the Cwtch project. To those\\npeople we offer our deep gratitude. Thank you. You have made Cwtch what it is. (And if you ever want Cwtch Stickers - please let us know!)\\n\\nHowever, it would not be right of us to release Cwtch Stable without at least one final offer to all contributors. If you want\\nto be credited for your contributions to Cwtch then, please, reach out to us and let us know of a way to appropriately credit\\nyou. \\n\\n## Getting in Touch\\n\\nYou can ask for credit via email (team@cwtch.im), or via Cwtch (either publicly via the [Cwtch Release Candidate Testers groups](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group), or privately\\nin a message to Sarah: `icyt7rvdsdci42h6si2ibtwucdmjrlcb2ezkecuagtquiiflbkxf2cqd`).\\n\\nYou can also [open an issue](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/new).\\n\\nWhen asking, please provide a name or handle, and if desired, a rough description of the contribution (e.g. development, design, documentation, translating, funding). Anyone who does\\nnot provide a description will be grouped under a general thanks section.\\n\\nThis is an open offer. If at any time you change your mind and wish to have credit added (or removed) please let us know.\\n\\nI want to take another opporunity to say, regardless of whether you wish to be publicly credited for your work on Cwtch, **thank you**.\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-ui-reproducible-builds-linux","metadata":{"permalink":"/blog/cwtch-ui-reproducible-builds-linux","source":"@site/blog/2023-07-14-cwtch-ui-reproducible-builds.md","title":"Progress Towards Reproducible UI Builds","description":"","date":"2023-07-14T00:00:00.000Z","formattedDate":"July 14, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":4.16,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Progress Towards Reproducible UI Builds","description":"","slug":"cwtch-ui-reproducible-builds-linux","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Call for Contributor Credits","permalink":"/blog/cwtch-stable-call-for-credits"},"nextItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-june"}},"content":"Earlier this year we talked about the changes we have made to make [Cwtch Bindings Reproducible](https://docs.cwtch.im/blog/cwtch-bindings-reproducible).\\n\\nIn this devlog we will talk about how the Cwtch UI are currently built, the changes we have made to Cwtch UI to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible. \\n\\nThis will be useful to anyone who is looking to reproduce Cwtch UI builds specifically, and to anyone who wants to start implementing reproducible builds in their own project.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Building the Cwtch UI\\n\\nThe official Cwtch UI project uses the FLutter framework. The Cwtch UI deliberately tracks the `stable` channel.\\n\\nAll builds are conducted through the `flutter` tool e.g. `flutter build`. We inject two build flags as part of the official build `VERSION` and `COMMIT_DATE`:\\n\\n\\t\\tflutter build linux --dart-define BUILD_VER=`cat VERSION` --dart-define BUILD_DATE=`cat COMMIT_DATE`\\n\\nThese flags are defined to be identical to Cwtch Bindings. `VERSION` is the latest git tag: `git describe --tags --abbrev=1` and `COMMIT_DATE` is the date of the latest commit on the branch ``echo `git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M` > COMMIT_DATE``\\n\\nAll Cwtch UI builds also depend on two external dependencies not managed directly by the flutter project: Tor (implicit as part of the fetchTor scripts) and libCwtch (defined in `LIBCWTCH-GO.version`, and fetched via the fetch-libcwtch scripts).\\n\\nThe binaries are downloaded via their respective scripts prior to the build, and managed via a separate update process.\\n\\n## Changes we made for reproducible builds\\n\\nFor reproducible linux builds we had to modify the generated `linux/CMakeLists.txt` file to include the following compiler and linker flags:\\n\\n* `-fno-ident` - suppresses compiler identifying information from compiled artifacts. Without this small changes in compiler versions will result in different binaries.\\n* `--hash-style=gnu` - asserts a standard hashing scheme to use across all compiled artifacts. Without this compilers that have been compiled with different default schemes will produce different artifacts\\n* `--build-id=none` - suppresses build id generation. Without this each compiled artifact will have a section of effectively randomized data.\\n\\nWe have also defined a new [linker script](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/commit/3148a8e0642e51bc59d9eb00ca2b319a7097285a/elf_x86_64.x) that differs from the default by removing all `.comment` sections from object files. We do this because the linking process links in non-project artifacts like `crtbeginS.o` which, in most systems, us compiled with a `.comment` section (the default linking script already removes the `.note.gnu*` sections.\\n\\n### Tar Archives\\n\\nFinally, following the [guide at reproducible-builds.org](https://reproducible-builds.org/docs/archives/) we have defined standard metadata for the generated Tar archives to make them also reproducible.\\n\\n## Limitations and Next Steps\\n\\nThe above changes mean that official linux builds of the same commit will now result in identical artifacts.\\n\\nThe next step is to roll these changes into [repliqate](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) as we have done with our bindings builds.\\n\\nHowever, because Repliqate is based on Debian images and our official UI builds are based on an Ubuntu distribution the resulting archives differ by a single instruction at the start of a few sections - introduced because Ubuntu compiles and provides C Runtime (CRT) artifacts (e.g. `crti.o` with full branch protection enabled. On 64-bit systems this results in an `endcr64` instruction being inserted at the start of the `.init` and `.fini` sections, among others.\\n\\nIn order to allow people to fully repliqate Cwtch builds in an isolated environment like repliqate, as we do for Cwtch Bindings, it will be necessary to provide instructions for setting up a hardened image that can work the same way in repliqate.\\n\\n### Pinned Dependencies\\n\\nAdditionally, while our repliqate scripts pin several major dependencies like flutter and go, and the dependencies managed by these systems are locked to specific versions, there are still a few dependencies within the ecosystems that are not strictly pinned. \\n\\nThe major one is libc. Operating systems rarely make big changes to packaged libc versions for a specific distribution (typically because doing so in a non-breaking way would be a major undertaking). \\n\\nHowever this does mean that Cwtch reproduciblility is implicitly tied to operating system practices - this is something we would like to begin decoupling ourselves from going forward.\\n\\n## Stay up to date!\\n\\nWe expect to make additional progress on this in the coming weeks and months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update-june","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update-june","source":"@site/blog/2023-07-05-cwtch-stable-roadmap-update.md","title":"Cwtch Stable Roadmap Update","description":"Back in March we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","date":"2023-07-05T00:00:00.000Z","formattedDate":"July 5, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":5.26,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable Roadmap Update","description":"Back in March we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","slug":"cwtch-stable-roadmap-update-june","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Progress Towards Reproducible UI Builds","permalink":"/blog/cwtch-ui-reproducible-builds-linux"},"nextItem":{"title":"Cwtch Beta 1.12","permalink":"/blog/cwtch-nightly-1-12"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable. We have been working hard towards that goal over the last few months.\\n\\nThis post [revisits the Cwtch Stable roadmap update](/blog/cwtch-stable-roadmap-update) we provided back in March, and provides an overview of the next steps on our journey towards Cwtch Stable.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Update on the Cwtch Stable Roadmap\\n\\nBack in March we extended and updated several goals from [our January roadmap](https://docs.cwtch.im/blog/path-to-cwtch-stable) that we would have to hit on our way to Cwtch Stable, and the timelines for achieving them. Now that we have reached target date of many of these goals, we can look back and see how work is progressing.\\n\\n(\u2705 means complete, \ud83d\udfe1 means in-progress, \ud83d\udd52 reprioritized)\\n\\n- By **30th April 2023** the Cwtch team will have written the remaining outstanding documentation from the January roadmap including:\\n - A Cwtch Release Process Document \u2705 - [Release Process](https://docs.cwtch.im/developing/release/#official-releases)\\n - A Cwtch Packaging Document \u2705 - [Packaging Documentation](https://docs.cwtch.im/developing/release/)\\n - Completion of documentation of existing Cwtch features, including relevant screenshots. \ud83d\udfe1 - new features are documented to the standards outlined in new [documentation style guide](/docs/contribute/documentation), and many older feature documentation features have been updated to that standard. Work is ongoing to refine the standard.\\n- By **30th April 2023** the Cwtch team will have also released developer-centric documentation including:\\n - A guide to building Cwtch-apps using official libraries \u2705 - [Building a Cwtch App](https://docs.cwtch.im/developing/category/building-a-cwtch-app)\\n - Automatically generated API documentation for libCwtch \ud83d\udd52 - this effort has been delayed pending other higher priority work. \\n- By **30th June 2023** the Cwtch team will have released new Cwtch Beta releases (1.12+) featuring:\\n - An implementation of [Conversation Search](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/129) \ud83d\udfe1 - currently in [active development](https://git.openprivacy.ca/cwtch.im/cwtch/pulls/518)\\n - [Profile statuses](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/27) and other associated information \u2705 - released in [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12)\\n - An update to the network handling code to allow for [better Protocol Engine management](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/593) \ud83d\udfe1\ud83d\udd52 - new Network Management code was released in [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12). We now believe these changes will be complete in Cwtch Beta 1.13.\\n- By **31st July 2023** the Cwtch team will have completed several infrastructure upgrades including:\\n - Extended reproducible builds to cover the Cwtch UI, or document where the blockers to achieving this exist. \ud83d\udfe1 - we have recently made a few updates to [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) to support this work, and expect to begin in-depth examination of build artifacts in the next couple of weeks.\\n - Integration of automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team \ud83d\udd52 - after some initial explorations into new Go fuzzing tools we reached the conclusion that it would be better to replace this effort with other assurance work (see below).\\n - New testing environments for F-droid, Whonix, Raspberry Pi and other [partially supported systems](/docs/getting-started/supported_platforms) \ud83d\udfe1 - we have already launched an environment for testing [Tails](/docs/platforms/tails). Other platforms are underway.\\n- By **31st August 2023** the Cwtch team will have a released Cwtch Stable Release Candidate:\\n - At this point we expect that the Cwtch application and existing documentation will be robust and complete enough to be labeled as stable.\\n - Along with this label comes a higher standard for how we consider all aspects of Cwtch development. The work we have done up to this point reflects a much stronger development pipeline, and an ongoing commitment to security.\\n - **This does not mark an end to Cwtch development**, or new Cwtch features. But it does denote the point at which we consider Cwtch to be appropriate for wider use.\\n\\n\\n## Next Steps, Refinements, Additional Work\\n\\nAs you may have noticed above we have reprioritized some work after initial investigations forced us to reevaluate the expected cost/benefit trade-off. This has allowed us to move up timelines for tasks e.g. reproducible UI builds and testing environments. \\n\\nOther work has been reprioritized due to developer availability. Documentation work in particular has not progressed as fast as we would like.\\n\\nHowever, [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12) featured many new features alongside improved performance, more robust packaging, and several fixes impacting experimental features like file sharing.\\n\\nThe work that we have done on reproducible and automatically generated bindings has considerably reduced the maintenance burden associated with updates and adding new features, and has allowed us to also tackle long standing issues related to Tor process managements and Cwtch startup.\\n\\nWe are still on track for releasing a Cwtch Stable release candidate in August 2023, with an official Cwtch Stable release expected shortly afterwards.\\n\\nThis is not all we have planned for the upcoming months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Get Involved\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-1-12","metadata":{"permalink":"/blog/cwtch-nightly-1-12","source":"@site/blog/2023-06-16-cwtch-1.12.md","title":"Cwtch Beta 1.12","description":"Cwtch Beta 1.12 is now available for download","date":"2023-06-16T00:00:00.000Z","formattedDate":"June 16, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":2.455,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Beta 1.12","description":"Cwtch Beta 1.12 is now available for download","slug":"cwtch-nightly-1-12","tags":["cwtch","cwtch-stable","release"],"image":"/img/devlog1_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-june"},"nextItem":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","permalink":"/blog/cwtch-nightly-v.11-74"}},"content":"[Cwtch 1.12 is now available for download](https://cwtch.im/download)!\\n\\nCwtch 1.12 is the culmination of the last few months of effort by the Cwtch team, and includes many foundational changes that pave the way for [Cwtch Stable](/blog/path-to-cwtch-stable) including new features like [profile attributes](https://docs.cwtch.im/docs/profiles/profile-info), support for new platforms like [Tails](https://docs.cwtch.im/docs/platforms/tails), and multiple improvements to performance and stability.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic1.12.png)](/img/picnic1.12.png)\\n\\n
A screenshot of Cwtch 1.12
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Profile Attributes** - profiles can now be augmented with [additional public information](https://docs.cwtch.im/docs/profiles/profile-info)\\n - **Availability Status** - you can now notify contacts that you [are **away** or **busy**](https://docs.cwtch.im/docs/profiles/availability-status)\\n - **Five New Supported Localizations**: **Japanese**, **Korean**, **Slovak**, **Swahili** and **Swedish**\\n - **Support for Tails** - adds an [OnionGrater](https://docs.cwtch.im/docs/platforms/tails) configuration and a new `CWTCH_TAILS` environment variable that enables special Tor behaviour.\\n- **Bug Fixes / Improvements:**\\n - Based on Flutter 3.10\\n - Inter is now the main UI font\\n - New Font Scaling setting\\n - New Network Management code to better manage Tor on unstable networks\\n - File Sharing Experiment Fixes\\n \\t- Fix performance issues for file bubble\\n \\t- Allow restarting of file shares that have timed out\\n \\t- Fix NPE in FileBubble caused by deleting the underlying file\\n \\t- Move from RetVal to UpdateConversationAttributes to minimze UI thread issues\\n - Updates to Linux install scripts to support more distributions\\n - Add a Retry Peer connection to prioritize connection attempts for certain conversations\\n - Updates to `_FlDartProject` to allow custom setting of Flutter asset paths\\n- **Accessibility / UX:**\\n - Full translations for **Brazilian Portuguese**, **Dutch**, **French**, **German**, **Italian**, **Russian**, **Polish**, **Slovak**, **Spanish**, **Swahili**, **Swedish**, **Turkish**, and **Welsh**\\n - Core translations for **Danish** (75%), **Norwegian** (76%), and **Romanian** (75%)\\n - Partial translations for **Japanese** (29%), **Korean** (23%), **Luxembourgish** (22%), **Greek** (16%), and **Portuguese** (6%)\\n\\n## Reproducible Bindings\\n\\nCwtch 1.12 is based on libCwtch version `libCwtch-autobindings-2023-06-13-10-50-v0.0.5`. The [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source can be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5)\\n\\n## Download the New Version \\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-v.11-74","metadata":{"permalink":"/blog/cwtch-nightly-v.11-74","source":"@site/blog/2023-06-07-new-nightly.md","title":"New Cwtch Nightly (v1.11.0-74-g0406)","description":"In this development log we take a look at the new Cwtch Nightly","date":"2023-06-07T00:00:00.000Z","formattedDate":"June 7, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"}],"readingTime":1.845,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","description":"In this development log we take a look at the new Cwtch Nightly","slug":"cwtch-nightly-v.11-74","tags":["cwtch","cwtch-stable","nightly"],"image":"/img/devlog10_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Beta 1.12","permalink":"/blog/cwtch-nightly-1-12"},"nextItem":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","permalink":"/blog/cwtch-developer-documentation"}},"content":"We are getting close to a 1.12 release. This week we are drawing attention to the latest Cwtch Nightly (2023-06-05-17-36-v1.11.0-74-g0406) that is now available for wider testing.\\n\\nAs a reminder, the Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like ours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n![](/img/devlog10.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### New Nightly\\n\\nThere is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing is [2023-06-05-17-36-v1.11.0-74-g0406](https://build.openprivacy.ca/files/flwtch-2023-06-05-17-36-v1.11.0-74-g0406/).\\n\\nThis version has a large number of improvements and bug fixes including:\\n\\n* A new Font Scaling setting\\n* Several networking and connection management improvements including automatic detection and response to network changes, and several bug fixes that impacted time-to-connection after a resetting Tor.\\n* Updated UI font styles\\n* Dependency updates, including a new base of Flutter 3.10.\\n* A fix for stuck file downloading notifications on Android\\n* A fix for missing profile images in certain edge cases on Android\\n* Japanese, Swedish, and Swahili translation options\\n* A new retry peer connection button for prompting Cwtch to prioritize specific connections\\n* [Tails support](/docs/platforms/tails)\\n\\nIn addition, this nightly also includes a number of performance improvements that should fix reported rendering issues on less powerful devices.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-developer-documentation","metadata":{"permalink":"/blog/cwtch-developer-documentation","source":"@site/blog/2023-04-28-developer-docs.md","title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","description":"In this development log we take a look at the new Cwtch developer docs!","date":"2023-04-28T00:00:00.000Z","formattedDate":"April 28, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"developer-documentation","permalink":"/blog/tags/developer-documentation"}],"readingTime":2.595,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","description":"In this development log we take a look at the new Cwtch developer docs!","slug":"cwtch-developer-documentation","tags":["cwtch","cwtch-stable","developer-documentation"],"image":"/img/devlog9_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","permalink":"/blog/cwtch-nightly-v.11-74"},"nextItem":{"title":"Availability Status and Profile Attributes","permalink":"/blog/availability-status-profile-attributes"}},"content":"One of the larger remaining goals outlined in our [Cwtch Stable roadmap update](/blog/cwtch-stable-roadmap-update) is comprehensive developer documentation. We have recently spent some time writing the foundation for these documents. \\n\\nIn this devlog we will introduce some of them, and outline the next steps. We also have a new nightly Cwtch release available for testing!\\n\\nWe are very interested in getting feedback on these documents, and we encourage anyone who is excited to build a Cwtch Bot, or even an alternative UI, to read them over and reach out to us with comments, questions, and suggestions!\\n\\nAs a reminder, the Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like ours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n![](/img/devlog9.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Cwtch Development Handbook\\n\\nWe have created a new documentation section, [the developers handbook](/developing/intro). This new section is targeted towards to people working on Cwtch projects (e.g. the official Cwtch library or the Cwtch UI), as well as people who want to build new Cwtch applications (e.g. chat bots or custom clients).\\n\\n### Release and Packaging Process\\n\\nThe new handbook features a breakdown of [Cwtch release processes](/developing/release) - describing what, and how, build artifacts are created; the difference between nightly and official builds; how the official release process works; and how reproducible build scripts are created.\\n\\n### Cwtch Application Development and Cwtchbot v0.1.0!\\n\\nFor the first time ever we now have [comprehensive documentation on how to build a Cwtch Application](/developing/category/building-a-cwtch-app). This section of the development handbook covers everything from [choosing a Cwtch library](/developing/building-a-cwtch-app/intro#choosing-a-cwtch-library), to [building your first application](/developing/building-a-cwtch-app/building-an-echobot).\\n\\nTogether with this new documentation we have also [released version 0.1 of the Cwtchbot framework](https://git.openprivacy.ca/sarah/cwtchbot), updating calls to use the [new Cwtch Stable API](/blog/cwtch-stable-api-design).\\n\\n### New Nightly\\n\\nThere is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing is [2023-04-26-20-57-v1.11.0-33-gb4371](https://build.openprivacy.ca/files/flwtch-2023-04-26-20-57-v1.11.0-33-gb4371/).\\n\\nThis version has a number of fixes and updates to the file sharing and image previews/profile pictures experiment, and an update to the [in-development Tails support](/docs/platforms/tails). \\n\\nIn addition, this nightly also includes a number of performance improvements that should fix reported rendering issues on less powerful devices.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"availability-status-profile-attributes","metadata":{"permalink":"/blog/availability-status-profile-attributes","source":"@site/blog/2023-04-06-availability-and-profile-attributes.md","title":"Availability Status and Profile Attributes","description":"Two new Cwtch features are now available to test in nightly: Availability Status and Profile Information.","date":"2023-04-06T00:00:00.000Z","formattedDate":"April 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"}],"readingTime":1.445,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Availability Status and Profile Attributes","description":"Two new Cwtch features are now available to test in nightly: Availability Status and Profile Information.","slug":"availability-status-profile-attributes","tags":["cwtch","cwtch-stable","nightly"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","permalink":"/blog/cwtch-developer-documentation"},"nextItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update"}},"content":"Two new Cwtch features are now available to test in nightly: [Availability Status](/docs/profiles/availability-status) and [Profile Information](/docs/profiles/profile-info).\\n\\nAdditionally, we have also published draft guidance on [running Cwtch on Tails](/docs/platforms/tails) that we would like volunteers to test and report back on.\\n \\nThe Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like\\nours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n\x3c!--truncate--\x3e\\n\\n\\n## Availability Status\\n\\nNew in this nightly is the ability to notify your conversations that you are \\"Away\\" or \\"Busy\\".\\n\\n
\\n\\n[![](/img/profiles/status-tooltip-busy-set.png)](/img/profiles/status-tooltip-busy-set.png)\\n\\n
\\n
\\n\\nRead more: [Availability Status](/docs/profiles/availability-status)\\n\\n## Profile Attributes\\n\\nAlso new is the ability to augment your profile with a few small pieces of **public** information.\\n\\n
\\n\\n[![](/img/profiles/attributes-set.png)](/img/profiles/attributes-set.png)\\n\\n
\\n
\\n\\nRead more: [Profile Information](/docs/profiles/profile-info)\\n \\n## Downloading the Nightly\\n\\n[Nightly builds](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. Download links for **2023-04-05-18-28-v1.11.0-7-g0290** are available below.\\n\\n* Windows: [https://build.openprivacy.ca/files/flwtch-win-2023-04-05-18-28-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-win-2023-04-05-18-28-v1.11.0-7-g0290/)\\n* Linux: [https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/)\\n* Mac: [https://build.openprivacy.ca/files/flwtch-macos-2023-04-05-14-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-macos-2023-04-05-14-27-v1.11.0-7-g0290/)\\n* Android: [https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/)\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update","source":"@site/blog/2023-03-31-cwtch-stable-roadmap-update.md","title":"Cwtch Stable Roadmap Update","description":"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more","date":"2023-03-31T00:00:00.000Z","formattedDate":"March 31, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":5.61,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable Roadmap Update","description":"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more","slug":"cwtch-stable-roadmap-update","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Availability Status and Profile Attributes","permalink":"/blog/availability-status-profile-attributes"},"nextItem":{"title":"Cwtch Beta 1.11","permalink":"/blog/cwtch-nightly-1-11"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable. We have been working hard towards that goal over the last few months.\\n\\nThis post [revisits the Cwtch Stable roadmap](/blog/path-to-cwtch-stable) we introduced at the start of the year, and provides an overview of the next steps on our journey towards Cwtch Stable.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Update on the January Roadmap\\n\\nBack in January we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines for achieving them. Now that we have reached target date of the last of these goals, we can look back and see how we did:\\n\\n(\u2705 means complete, \ud83d\udfe1 means in-progress, \u274c not started.)\\n\\n- By **1st February 2023**, the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases). \u2705\\n- By **1st February 2023**, the Cwtch team will have [finalized a feature set that defines Cwtch Stable](/blog/cwtch-stable-api-design) and established a timeline for including these features in upcoming Cwtch Beta releases. \u2705\\n- By **1st February 2023**, the Cwtch team will have expanded the Cwtch Documentation website to include a section for:\\n - [Security and Design Documents](/security/intro) \u2705\\n - Infrastructure and [Support](/docs/getting-started/supported_platforms) \ud83d\udfe1\\n - in addition to a new development blog. \u2705\\n- By **31st March 2023**, the Cwtch team will have created:\\n - a [style guide for documentation](/docs/contribute/documentation), and \u2705\\n - have used it to ensure that all Cwtch features have consistent documentation available, \ud83d\udfe1\\n - with at least one screenshot (where applicable). \ud83d\udfe1\\n- By **31st March 2023** the Cwtch team will have published: \\n - a Cwtch [Interface Specification Document](/blog/cwtch-stable-api-design) \u2705\\n - a Cwtch Release Process Document \ud83d\udfe1\\n - a Cwtch [Support Plan document](/blog/cwtch-platform-support) \u2705\\n - a Cwtch Packaging Document \ud83d\udfe1\\n - a document describing the [Reproducible Builds Process](/blog/cwtch-bindings-reproducible) \u2705\\n - These documents will be available on the newly expanded Cwtch Documentation website \ud83d\udfe1\\n- By **31st March 2023** the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository. \u2705\\n- By **31st March 2023** the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team \u274c\\n- By **31st March 2023** the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable \u2705 (this post!)\\n\\nWhile we didn\'t hit all of our goals, we did make progress on nearly all of them, and in addition also made progress in a few other key areas:\\n\\n* [Cwtch Autobindings](/blog/autobindings) with [compile-time optional experiments](/blog/autobindings-ii)\\n* [Cwtch 1.11](/blog/cwtch-nightly-1-11) - with support for reproducible bindings, two new localizations (Slovak and Korean), in addition to a myriad of bug fixes and performance improvements.\\n* [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) - a tool for testing and confirming reproducible builds processes based on Qemu, and a Debian Cloud image.\\n\\n## A Timeline for Cwtch Stable\\n\\nNow for the big news, we plan on releasing a candidate Cwtch Stable release during **Summer 2023**. Here is our plan for getting there:\\n\\n- By **30th April 2023** the Cwtch team will have written the remaining outstanding documentation from the January roadmap including:\\n - A Cwtch Release Process Document\\n - A Cwtch Packaging Document\\n - Completion of documentation of existing Cwtch features, including relevant screenshots.\\n- By **30th April 2023** the Cwtch team will have also released developer-centric documentation including:\\n - A guide to building Cwtch-apps using official libraries\\n - Automatically generated API documentation for libCwtch\\n- By **30th June 2023** the Cwtch team will have released new Cwtch Beta releases (1.12+) featuring:\\n - An implementation of [Conversation Search](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/129)\\n - [Profile statuses](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/27) and other associated information\\n - An update to the network handling code to allow for [better Protocol Engine management](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/593)\\n- By **31st July 2023** the Cwtch team will have completed several infrastructure upgrades including:\\n - Extended reproducible builds to cover the Cwtch UI, or document where the blockers to achieving this exist.\\n - Integration of automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team\\n - New testing environments for F-droid, Whonix, Raspberry Pi and other [partially supported systems](/docs/getting-started/supported_platforms)\\n- By **31st August 2023** the Cwtch team will have a released Cwtch Stable Release Candidate:\\n - At this point we expect that the Cwtch application and existing documentation will be robust and complete enough to be labelled as stable.\\n - Along with this label comes a higher standard for how we consider all aspects of Cwtch development. The work we have done up to this point reflects a much stronger development pipeline, and an ongoing commitment to security.\\n - **This does not mark an end to Cwtch development**, or new Cwtch features. But it does denote the point at which we consider Cwtch to be appropriate for wider use.\\n\\nThis is not all we have planned for the upcoming months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Get Involved\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-1-11","metadata":{"permalink":"/blog/cwtch-nightly-1-11","source":"@site/blog/2023-03-29-cwtch-1.11.md","title":"Cwtch Beta 1.11","description":"Cwtch Beta 1.11 is now available for download","date":"2023-03-29T00:00:00.000Z","formattedDate":"March 29, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":2.365,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Beta 1.11","description":"Cwtch Beta 1.11 is now available for download","slug":"cwtch-nightly-1-11","tags":["cwtch","cwtch-stable","release"],"image":"/img/devlog12_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update"},"nextItem":{"title":"Updates to Cwtch Documentation","permalink":"/blog/cwtch-documentation"}},"content":"[Cwtch 1.11 is now available for download](https://cwtch.im/download)!\\n\\nCwtch 1.11 is the culmination of the last few months of effort by the Cwtch team, and includes many foundational changes that pave the way for [Cwtch Stable](/blog/path-to-cwtch-stable) including new [reproducible](https://docs.cwtch.im/blog/cwtch-bindings-reproducible) and [automatically generated](https://docs.cwtch.im/blog/autobindings) bindings, as well as support for two new languages (Slovak and Korean), in addition to several performance improvements and bug fixes.\\n\\n![](/img/devlog12.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic.png)](/img/picnic.png)\\n\\n
A screenshot of Cwtch 1.11
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Based on new Reproducible Cwtch Stable Autobuilds** - this is the first release of cwtch based on [reproducible Cwtch bindings](https://docs.cwtch.im/blog/cwtch-bindings-reproducible) in addition to our new [automatically generated](https://docs.cwtch.im/blog/autobindings)\\n - **Two New Supported Localizations**: **Slovak** and **Korean**\\n- **Bug Fixes / Improvements:**\\n - When preserving a message draft, quoted messages are now also saved\\n - Layout issues caused by pathological unicode are now prevented\\n - Improved performance of message row rendering\\n - Clickable Links: Links in replies are now selectable\\n - Clickable Links: Fixed error when highlighting certain URIs \\n - File Downloading: Fixes for file downloading and exporting on 32bit Android devices\\n - Server Hosting: Fixes for several layout issues\\n - Build pipeline now runs automated UI tests\\n - Fix issues caused by scrollbar controller overriding\\n - Initial support for the Blodeuwedd Assistant (currently compile-time disabled)\\n - Cwtch Library:\\n - [New Stable Cwtch Peer API](/blog/cwtch-stable-api-design)\\n - Ported File Downloading and Image Previews experiments into Cwtch\\n- **Accessibility / UX:**\\n - Full translations for **Brazilian Portuguese**, **Dutch**, **French**, **German**, **Italian**, **Russian**, **Polish**, **Spanish**, **Turkish**, and **Welsh**\\n - Core translations for **Danish** (75%), **Norwegian** (76%), and **Romanian** (75%)\\n - Partial translations for **Luxembourgish** (22%), **Greek** (16%), and **Portuguese** (6%)\\n\\n\\n\\n## Reproducible Bindings\\n\\nCwtch 1.11 is based on libCwtch version `2023-03-16-15-07-v0.0.3-1-g50c853a`. The [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source can be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.3-1-g50c853a](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.3-1-g50c853a)\\n\\n## Download the New Version \\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-documentation","metadata":{"permalink":"/blog/cwtch-documentation","source":"@site/blog/2023-03-10-cwtch-documentation.md","title":"Updates to Cwtch Documentation","description":" In this development log we will highlight some of the major documentation updates over the last few weeks.","date":"2023-03-10T00:00:00.000Z","formattedDate":"March 10, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"documentation","permalink":"/blog/tags/documentation"},{"label":"security-handbook","permalink":"/blog/tags/security-handbook"}],"readingTime":2.57,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Updates to Cwtch Documentation","description":" In this development log we will highlight some of the major documentation updates over the last few weeks.","slug":"cwtch-documentation","tags":["cwtch","cwtch-stable","documentation","security-handbook"],"image":"/img/devlog9_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Beta 1.11","permalink":"/blog/cwtch-nightly-1-11"},"nextItem":{"title":"Compile-time Optional Application Experiments (Autobindings)","permalink":"/blog/autobindings-ii"}},"content":"One of the main streams of work in the lead up to Cwtch Stable has been improving all aspects of Cwtch Documentation. In this development log we will highlight some of the major updates over the last few weeks.\\n\\n![](/img/devlog9.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Cwtch Secure Development Handbook\\n \\nOne of the earliest compendiums of Cwtch documentation was the Cwtch Secure Development Handbook. This handbook provided an overview of the various parts of the Cwtch ecosystem, the known risks, and any existing mitigations. The handbook was designed to serve as a guide to developers who were building or extending Cwtch, and over the years it also served as a permanent home for documenting long-standing design decisions.\\n\\nWe have [now ported the the handbook to this documentation site](/security/intro), along with updating some of the contents. Over the next few months we will be expanding this section to include new sections on fuzzing, plugins, and client implementation. \\n\\n## Volunteer Development\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Next Steps\\n\\nWe still have more work to do on the documentation front:\\n\\n* Ensuring all pages [implement the new documentation style guide](/docs/contribute/documentation), and include appropriate screenshots and descriptions.\\n* Expanding the security handbook to provide information on [reproducible builds](/blog/cwtch-bindings-reproducible), [the new Cwtch Stable API](/blog/cwtch-stable-api-design) and upcoming improvements around fuzz testing.\\n* Creating new documentation sections on the [libCwtch autobindings API](/blog/autobindings) and building applications on top of Cwtch.\\n\\nAs these changes are made, and these goals met we will be posting about them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"autobindings-ii","metadata":{"permalink":"/blog/autobindings-ii","source":"@site/blog/2023-03-03-autobindings-optional-experiments.md","title":"Compile-time Optional Application Experiments (Autobindings)","description":"In this development log we document how we added compile-time optional application-level experiments to Cwtch autobindings.","date":"2023-03-03T00:00:00.000Z","formattedDate":"March 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"autobindings","permalink":"/blog/tags/autobindings"},{"label":"libcwtch","permalink":"/blog/tags/libcwtch"}],"readingTime":4.655,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Compile-time Optional Application Experiments (Autobindings)","description":"In this development log we document how we added compile-time optional application-level experiments to Cwtch autobindings.","slug":"autobindings-ii","tags":["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],"image":"/img/devlog8_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Updates to Cwtch Documentation","permalink":"/blog/cwtch-documentation"},"nextItem":{"title":"Autogenerating Cwtch Bindings","permalink":"/blog/autobindings"}},"content":"[Last time we looked at autobindings](https://docs.cwtch.im/blog/autobindings) we mentioned that one of the next steps was introducing support for **[Application-level experiments](https://docs.cwtch.im/blog/cwtch-stable-api-design#application-experiments)**. In this development log we will explore what application-level experiments are (technically), and how we added (optional) autobindings support for them.\\n\\n![](/img/devlog8.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## The Structure of an Application Experiment\\n\\nAn application-level experiment consists of:\\n\\n1. A set of top-level APIs, e.g. `CreateServer`, `LoadServer`, `DeleteServer` - these are the APIs that we want to expose to calling applications.\\n2. An encapsulating structure for the set of APIs, e.g. `ServersFunctionality` - it is much easy to manage a cohesive set of functionality if it is wrapped up in a single entity.\\n3. A global variable that exists at the top level of libCwtch, e.g. `var serverExperiment *servers.ServersFunctionality servers` - our single pointer to the underlying functionality.\\n4. A set of management-related APIs, e.g. `Init`, `UpdateSettings`, `OnACNEvent` - in the case of the server hosting experiment we need to perform specific actions when we start up (e.g. loading unencrypted hosted servers), and when settings are\\nchanged (e.g. if the server hosting experiment is disabled we need to tear down all active servers).\\n5. Management code within `_startCwtch` and `_reconnectCwtch` that calls the management APIs on the global variable.\\n\\nFrom a code generation perspective we already have most of the functionality is place to support (1) - the one major difference being that we need to wrap function calls on the global variable associated with the experiment, instead\\nof on `application` or a specific `profile`.\\n\\nMost of the effort required to support optional experiments was focused on optionally weaving experiment management code within the template.\\n\\n### New Required Management APIs\\n\\nTo achieve this weaving, we now require application-level experiments to implement an `EventHandlerInterface` interface and expose itself via an\\ninitialize constructor `Init(acn, appDir) -> EventHandlerInterface`, and `Enable(app, acn)`.\\n\\nFor now this interface is rather minimal, and has been mapped almost exactly to how the server hosting experiment already worked. If, or when, a new application experiment is required we will likely revisit this interface.\\n\\nWe can then generate, and optionally include blocks of code like:\\n\\n\\t\\t = .Init(&globalACN, appDir)\\n\\t\\teventHandler.AddModule()\\n\\t\\t.Enable(application, &globalACN)\\n\\nand place them at specific points in the code. `EventHandler` has also been extended to maintain a collection of `modules` so that it can\\npass on interesting events.\\n\\n### Adding Support for Application Experiments in the Spec File\\n\\nWe have introduced a new `!` operator which can be used to gate APIs behind a configured experiment. Along with a new\\ntemplating option `exp` which will call the function on the configured experiment, and `global` to allow the setting up\\nof a global functionality within the library.\\n\\n\\t\\t# Server Hosting Experiment\\n\\t\\t!serverExperiment import \\"git.openprivacy.ca/cwtch.im/cwtch-autobindings/experiments/servers\\"\\n\\t\\t!serverExperiment global serverExperiment *servers.ServersFunctionality servers\\n\\t\\t!serverExperiment exp CreateServer application password string:description bool:autostart\\n\\t\\t!serverExperiment exp SetServerAttribute application string:handle string:key string:val\\n\\t\\t!serverExperiment exp LoadServers application acn password\\n\\t\\t!serverExperiment exp LaunchServers application acn\\n\\t\\t!serverExperiment exp LaunchServer application string:handle\\n\\t\\t!serverExperiment exp StopServer application string:handle\\n\\t\\t!serverExperiment exp StopServers application\\n\\t\\t!serverExperiment exp DestroyServers\\n\\t\\t!serverExperiment exp DeleteServer application string:handle password\\n\\n### Generation-Time Inclusion\\n\\n Without any arguments provided `generate-bindings` will not generate code for any experiments.\\n\\n In order to determine what experimental code to generate, `generate-bindings` now interprets arguments as enabled compile time experiments, e.g. `generate-bindings serverExperiment` will turn on\\n generation of server hosting code, per the spec file above.\\n\\n### Cwtch UI Integration\\n\\nThe UI, and other downstream applications, can now check for support for server hosting by simply checking if the loaded library provides the expected symbols, e.g. `c_LoadServers` - if it doesn\'t then the UI is safe to assume the\\nfeature is not available.\\n\\n
\\n\\n![](/img/dev9-host-disabled.png)\\n\\n
A screenshot of the Cwtch UI Settings Pane demonstrating how the Server Hosting experiment option looks when the UI is pointed to a libCwtch compiled without server hosting support.
\\n
\\n\\n## Nightlies & Next Steps\\n\\nWe are now publishing [nightlies](https://build.openprivacy.ca/files/libCwtch-autobindings-v0.0.2/) of autobinding derived libCwtch-go, along with [Repliqate scripts](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.2) for reproducibility.\\n\\nWith application experiments supported, this phase of autobindings comes to a close. The immediate next steps involve extensive testing and release candidates proving out the new bindings to ensure that no bugs have been introduced\\nin the migration from libCwtch-go. These candidates will form the basis for Cwtch Beta 1.11.\\n\\nHowever, there is still more work to do, and we expect to make progress on a few areas over the next few months, including:\\n\\n* **Dart Library generation**: since we now have a formal description of the bindings interface, we can move ahead with also autogenerating the [Dart side](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/lib/cwtch) of the bindings interface, giving a boost to UI integration of new features, and allowing us to generate tailored versions of the UI interface, e.g. one compiled without experiment support. We can also extend the same logic to other downstream interfaces, e.g. [libcwtch-rs](https://git.openprivacy.ca/cwtch.im/libcwtch-rs).\\n * **Documentation generation**: as another benefit of a formal description of the bindings interface, we can easily generate documentation compatible with [docs.cwtch.im](https://cwtch.im).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"autobindings","metadata":{"permalink":"/blog/autobindings","source":"@site/blog/2023-02-24-autogenerating-cwtch-bindings.md","title":"Autogenerating Cwtch Bindings","description":"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.","date":"2023-02-24T00:00:00.000Z","formattedDate":"February 24, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"autobindings","permalink":"/blog/tags/autobindings"},{"label":"libcwtch","permalink":"/blog/tags/libcwtch"}],"readingTime":4.545,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Autogenerating Cwtch Bindings","description":"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.","slug":"autobindings","tags":["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],"image":"/img/devlog8_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Compile-time Optional Application Experiments (Autobindings)","permalink":"/blog/autobindings-ii"},"nextItem":{"title":"Notes on Cwtch UI Testing (II)","permalink":"/blog/cwtch-testing-ii"}},"content":"The C-bindings for Cwtch evolved as part of Cwtch UI development. After two years of prototyping, development, new features, and revisiting first-implementations we have reached the point where we have a good understanding of\\nwhat the bindings need to do, and how they should do it. To that end we have produced a first-cut of a workflow to **automatically generate** these bindings: [cwtch-autobindings](https://git.openprivacy.ca/cwtch.im/autobindings).\\n\\nThis this development log we will introduced autobindings, the motivation behind them, and how we plan to use them on the [path to Cwtch Stable](https://docs.cwtch.im/blog/path-to-cwtch-stable).\\n\\n![](/img/devlog8.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## A Brief History of Cwtch Bindings\\n\\nPrior to the modern Flutter-based UI application, the first Cwtch UI prototype was based on Qt, with the bindings automatically generated by [therecipe/qt](https://github.com/therecipe/qt). However, after encountering numerous\\ncrash-bugs on the compiled Arm version for Android, and a few weeks of prototyping different approaches, we settled on Flutter as a replacement UI framework.\\n\\nAs part of early prototyping efforts for Flutter we built out a first version of [libCwtch-go](https://git.openprivacy.ca/cwtch.im/libcwtch-go), and over the two years of beta development we have evolved that prototype into a functional set of Cwtch bindings.\\n\\nThis approach has not been without side effects. There is still code from those early prototypes floating around in libCwtch-go, inconsistencies in how functions - in particular [experimental features](https://docs.cwtch.im/blog/cwtch-stable-api-design#the-cwtch-experiment-landscape) - handle settings, [duplication of logic between Cwtch and libCwtch-go](https://docs.cwtch.im/blog/cwtch-stable-api-design#bindings), and [special behaviour in libCwtch-go that better belongs in the core Cwtch library](https://docs.cwtch.im/blog/cwtch-stable-api-design#appendix-a-special-behaviour-defined-by-libcwtch-go).\\n\\nAs part of a broader effort to [refine the Cwtch API in preparation for Cwtch Stable](https://docs.cwtch.im/blog/cwtch-stable-api-design) we have taken the opportunity to fix many of these problems.\\n\\n## Cwtch Autobindings\\n\\nThe current `lib.go` file that encapsulates the vast majority of libCwtch-go currently sits at 1500+ lines of code. However, much of that code is boilerplate calling conventions e.g. the `BlockContact` API implementation is:\\n\\n\\t//export c_BlockContact\\n\\tfunc c_BlockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) {\\n\\t\\tBlockContact(C.GoStringN(profilePtr, profileLen), int(conversation_id))\\n\\t}\\n\\n\\tfunc BlockContact(profileOnion string, conversationID int) {\\n\\t\\tprofile := application.GetPeer(profileOnion)\\n\\t\\tif profile != nil {\\n\\t\\t\\tprofile.BlockConversation(conversationID)\\n\\t\\t}\\n\\t}\\n\\nAll that code is doing is defining a C-compatible API, performing some basic checking of parameters, and passing the result into the core Cwtch library. The two functions themselves support the C-bindings and Java-bindings respectively.\\n\\nIn the new [cwtch-autobindings](https://git.openprivacy.ca/cwtch.im/autobindings) we reduce these multiple lines to [a single one](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec#L19):\\n\\n\\tprofile BlockConversation conversation\\n\\nDefining a `profile`-level function, called `BlockConversation` which takes in a single parameter of type `conversation`.\\n\\nUsing a similar boilerplate-reduction for the reset of `lib.go` yields [5-basic function prototypes](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/README.md#spec-file-format):\\n\\n* Application-level functions e.g. `CreateProfile`\\n* Profile-level functions e.g. `BlockConversation`\\n* Profile-level functions that return data e.g. `GetMessage`\\n* Experimental Profile-level feature functions e.g. `DownloadFile`\\n* Experimental Profile-level feature functions that return data e.g. `ShareFile`\\n\\nOnce aggregated and itemized the full set of bindings for Cwtch applications, profile interactions, and experiments can be [described in fewer than 50 lines, including comments](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec). Even including the code necessary to generate the bindings from this specification file (~400 lines), and the code needed to initialize the bindings themselves (~300 lines). This cuts the amount of coded needed by 60%, and eliminates many classes of error and inconsistencies associated with maintaining bindings (e.g. regularizing function calls / checking experiment status / handling error conditions etc.).\\n\\n## Next Steps\\n\\nCwtch autobindings work today, are API-compatible with the existing libCwtch-go implements, and can be fully integrated into an existing Cwtch application with minimal effort. However, there are a few areas which need to be addressed prior to a full rollout:\\n\\n * **[Application-level experiments](https://docs.cwtch.im/blog/cwtch-stable-api-design#application-experiments)** (of which there is only one: Desktop Server Hosting) are not currently supported. This functionality is only tangentially related to the rest of the Cwtch bindings, and necessarily introduces additional dependencies (e.g. on `cwtch-server`). In the coming weeks we will allow optional application experiments to be enabled at compile time, to allow us to produce smaller bindings for platforms that don\'t support the experiment, and to allow us to build new kinds of platform-targeted experiments that can take advantage of platform specific features.\\n* **Dart Library generation**: since we now have a formal description of the bindings interface, we can move ahead with also autogenerating the [Dart-side](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/lib/cwtch) of the bindings interface, giving a boost to UI integration of new features, and allowing us to generate tailored versions of the UI interface e.g. one compiled without experiment support. We can also extend the same logic to other downstream interfaces e.g. [libcwtch-rs](https://git.openprivacy.ca/cwtch.im/libcwtch-rs)\\n * **Documentation generation**: another benefit of a formal description of the bindings interface, we can easily generate documentation compatible with [docs.cwtch.im](https://cwtch.im).\\n * **Cwtch API**: This first cut of autobindings is based on an unreleased version of the core Cwtch library that implements much of the [Cwtch Stable API redesign](https://docs.cwtch.im/blog/cwtch-stable-api-design). In a short while we will be merging these features into Cwtch, in preparation for Cwtch 1.11, and beyond.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-testing-ii","metadata":{"permalink":"/blog/cwtch-testing-ii","source":"@site/blog/2023-02-17-cwtch-testing-ii.md","title":"Notes on Cwtch UI Testing (II)","description":"In this development log we provide more updates on automated UI integration testing!","date":"2023-02-17T00:00:00.000Z","formattedDate":"February 17, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"},{"label":"testing","permalink":"/blog/tags/testing"}],"readingTime":1.75,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Notes on Cwtch UI Testing (II)","description":"In this development log we provide more updates on automated UI integration testing!","slug":"cwtch-testing-ii","tags":["cwtch","cwtch-stable","support","testing"],"image":"/img/devlog7_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Autogenerating Cwtch Bindings","permalink":"/blog/autobindings"},"nextItem":{"title":"Making Cwtch Android Bindings Reproducible","permalink":"/blog/cwtch-android-reproducibility"}},"content":"In this development log, we investigate some text-based UI bugs encountered by [Fuzzbot](https://docs.cwtch.im/docs/contribute/testing#running-fuzzbot), add more [automated UI tests](/blog/cwtch-testing-i) to the pipeline, and announce a new release of the Cwtchbot library.\\n\\n![](/img/devlog7.png)\\n\\n\x3c!--truncate--\x3e\\n\\n\\n## Constraining Cwtch UI Fields\\n\\nFuzzbot identified a few bugs relating to UI layout and text clipping. Certain strings would violate the bounds of their containers and overlap with other UI elements. While this\\ndoesn\'t pose a safety issue, it is unsightly.\\n\\n
\\n\\n[![](/img/dl7-before.png)](/img/dl7-before.png)\\n\\n
Screenshot demonstrating how certain strings would violate the bounds of their containers.
\\n
\\n\\nThese cases were fixed by parenting impacted elements in a `Container` with `clip: hardEdge` and `decoration:BoxDecoration()` (note that both of these are required as Container widgets in Flutter cannot set clipping logic\\nwithout an associated decoration).\\n\\n
\\n\\n[![](/img/dl7-after.png)](/img/dl7-after.png)\\n\\n
Now these clipped strings are tightly constrained to their container bounds.
\\n
\\n\\nThese fixes are available in the [latest Cwtch Nightly](/docs/contribute/testing#cwtch-nightlies), and will be officially released in Cwtch 1.11.\\n\\n## More Automated UI Tests\\n\\nWe have added two new sets of automated UI tests to our pipeline:\\n\\n- *02: Global Settings* - these tests check that certain global settings like languages, theme, unknown contacts blocking, and streamer mode work as expected. ([PR: 628](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/628))\\n- *04: Profile Management* - these tests check that creating, unlocking, and deleting a profile work as expected. ([PR: 632](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/632))\\n\\n## New Release of Cwtchbot\\n\\n[Cwtchbot](https://git.openprivacy.ca/sarah/cwtchbot) has been updated to use the latest Cwtch 0.18.10 API.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-android-reproducibility","metadata":{"permalink":"/blog/cwtch-android-reproducibility","source":"@site/blog/2023-02-10-android-reproducibility.md","title":"Making Cwtch Android Bindings Reproducible","description":"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible","date":"2023-02-10T00:00:00.000Z","formattedDate":"February 10, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":2.92,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Making Cwtch Android Bindings Reproducible","description":"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible","slug":"cwtch-android-reproducibility","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog6_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Notes on Cwtch UI Testing (II)","permalink":"/blog/cwtch-testing-ii"},"nextItem":{"title":"Notes on Cwtch UI Testing","permalink":"/blog/cwtch-testing-i"}},"content":"In this development log, we continue our previous work on [reproducible Cwtch bindings](https://docs.cwtch.im/blog/cwtch-bindings-reproducible), uncovering the final few sources of variation between our [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) scripts and our docker/drone builds, leading to fully reproducible builds for Cwtch Android bindings!\\n\\n![](/img/devlog6.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Changes Necessary for Reproducible Android Bindings\\n\\nAfter a thorough investigation of the build artifacts produced by Repliqate and Drone we uncovered three additional sources of variation:\\n\\n- **Insufficient path stripping introduced by Android NDK tools** - it turns out that Android builds using NDK versions below 22 are not reproducible as they produce randomized artifacts (through unstripped temporary directory paths appearing in compiled binares). NDK 22 [changed the binutils and default linker](https://github.com/android/ndk/wiki/Changelog-r22) to versions that correctly strip such paths from build artifacts. As such it was necessary for us to update the NDK version we used. We chose the technically outdated NDK 22 rather than the more modern NDK 25 to minimize Android OS compatibility changes during this switch. However, per our [long term support plan](https://docs.cwtch.im/blog/cwtch-platform-support), we will be moving towards adopting the latest NDK in the future.\\n- **Paths in DWARF entries** - while we have been unable to track down exactly where these are being introduced, we did track the final difference in the produced bindings to DWARF debug lines embedded in compiled ELF binaries. These entries encoded the actual location of the NDK on the disk of the build machine, instead of the symbolic link that we believed should have been followed. By physically placing the NDK at same location in repliqate as in our Docker container we were able to get these entries to be consistent - however there is still work to do to understand exactly why they are being introduced at all.\\n\\n
\\n\\n[![](/img/aar-diff.png)](/img/aar-diff.png)\\n\\n
Vimdiff comparing the decoded (readelf --debug-dump=line) DWARF debug section of Drone-produced Android bindings v.s. Repliqate-produced. The difference in paths is highlighted.
\\n
\\n\\n- **Go Compiler Acquisition** - our Docker container was compiling the Go compiler from source, while Repliqate was downloading a pre-compiled version. During debugging we changed the Dockerfile to also download the pre-compiled version in order to eliminate the difference as a potential reproducibility issue. Our tests indicated that there *was* a difference between artifacts produced by the precompiled compiler v.s. one built from source - this is likely explained by introduced environmental differences caused by the compilation of the compiler itself e.g. the contents/versions of modules in the Go package cache which we have seen as having an impact on other produced binaries.\\n\\n## Repliqate Scripts\\n\\nWith those issues now fixed, Cwtch Android bindings are **officially reproducible!** The first version that officially met this requirement was 1.10.5, and you can find the Repliqate script under [cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script) in the [Cwtch Repliqate scripts repository](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/).\\n\\nThis is another big milestone towards our ultimate goal of full reproducibility for Cwtch releases.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-testing-i","metadata":{"permalink":"/blog/cwtch-testing-i","source":"@site/blog/2023-02-03-cwtch-testing-i.md","title":"Notes on Cwtch UI Testing","description":"In this development log we provide an update on automated UI integration testing!","date":"2023-02-03T00:00:00.000Z","formattedDate":"February 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"},{"label":"testing","permalink":"/blog/tags/testing"}],"readingTime":4.74,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Notes on Cwtch UI Testing","description":"In this development log we provide an update on automated UI integration testing!","slug":"cwtch-testing-i","tags":["cwtch","cwtch-stable","support","testing"],"image":"/img/devlog5_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Making Cwtch Android Bindings Reproducible","permalink":"/blog/cwtch-android-reproducibility"},"nextItem":{"title":"Cwtch UI Platform Support","permalink":"/blog/cwtch-platform-support"}},"content":"We first [introduced UI tests last January](https://openprivacy.ca/discreet-log/23-cucumber-testing/). At the time we had developed a suite of UI tests that could be run manually in a development environment. However, we faced a number of issues consistently running these tests in our automated pipelines.\\n\\nOne of the main threads of work that needs to be complete early in the [Cwtch Stable roadmap](https://docs.cwtch.im/blog/path-to-cwtch-stable) is integrating UI tests into our CI pipelines, in addition to expanding their scope. Now that Flutter 3 has stabilized desktop support, and we have invested effort in improving Cwtch performance, it is time to ensure these tests are running on every build.\\n\\n![](/img/devlog5.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Current Limitations of Flutter Gherkin\\n\\nThe original [flutter_gherkin](https://pub.dev/packages/flutter_gherkin) is under semi-active development; however, the latest published versions don\'t support using it with `flutter test`.\\n\\n- **Flutter Test** was originally intended to run single widget/unit tests for a Flutter project.\\n- **Flutter Drive** was originally intended to run integration tests *on a device or an emulator*.\\n\\nHowever, in recent releases these lines have become blurred. The new [integration_test](https://docs.flutter.dev/testing/integration-tests) package that comes built into newer Flutter releases has support for both `flutter drive` and `flutter test`. This was a great change because it decreases the required overhead to run larger integration tests (`flutter drive` sets up a host-controller model that requires a dedicated control channel to be setup, whereas `flutter test` can take advantage of the knowledge that it is being run in the same process, and is noticeably faster - very important when the goal is to run tests as often as possible).\\n\\nThere is thankfully code in the `flutter_gherkin` repository that supports running tests with `flutter test`, however this code currently has a few issues:\\n\\n- The test code generation produces code that doesn\'t compile without minor changes.\\n- Certain functionality like \\"take a screenshot\\" does not work on desktop.\\n\\nAdditionally, there are a few limitations in built-in flutter_gherkin steps that we noticed our tests running into:\\n\\n- Certain tests that fail with async timeouts will cause Flutter exceptions instead of a failed test.\\n- Certain Flutter widgets like `DropdownButton` are not compatible with built-in steps like `tap` because they internally contain multiple copies of the same widget.\\n\\nBecause of the above issues we have chosen to [fork flutter_gherkin](https://git.openprivacy.ca/openprivacy/flutter_gherkin) to fix some of these issues, with the intent of contributing significant fixes upstream, while allowing us to iterate faster on Flutter UI testing.\\n\\n## Integrating Tests into the Pipeline\\n\\nOne of the major limitations of `flutter test` is the lack of a headless mode. In order to successfully run tests in our pipeline we need a headless mode, as most of the containers we use do not have any kind of active display.\\n\\nThankfully it is possible to use [Xfvb](https://en.wikipedia.org/wiki/Xvfb) to create a virtual framebuffer, and set `DISPLAY` to render to that buffer:\\n\\n export DISPLAY=:99\\n Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &\\n\\nThis allows us to neutralize our main issue with `flutter test`, and efficiently run tests in our pipeline.\\n\\n## Catching Bugs!\\n\\nThis small amount of integration work has already caught its first bug.\\n\\nOnce we had fixed most of the issues outlined above, we were still seeing failures on what should have been a very basic scenario. [02_save_load.feature](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/integration_test/features/01_general/02_save_load.feature) simply turns a set of experiments on and checks that the state is saved. This test runs perfectly fine on\\ndevelopment environments, but when uploaded to our build pipeline it always failed in the same place - turning on the file sharing experiment.\\n\\nThe cause of this was an actual bug in Cwtch UI. The file sharing experiment failed to turn on if the directory `$USER_HOME/Downloads` didn\'t exist. This is rarely the case on most real world systems, but is the case in our build pipelines. We have since fixed this behaviour to allow file sharing to be turned on even if the usual Download directories are not available.\\n\\nAs we enable more of our UI tests in our pipeline, and across more platforms, we expect to catch more subtle issues like the above - a big win for people who use Cwtch!\\n\\n## Next Steps\\n\\n- **More automated tests:** We have a nice collection of pre-written tests that we can begin to automatically run within pipelines. We have already begun this work, and anticipate finishing it before Cwtch 1.11.\\n- **More platforms:** Right now UI tests only run on Linux. In order to fully take advantage of these tests we need to be able to run them across [our target platforms](https://docs.cwtch.im/docs/getting-started/supported_platforms). We expect to start this work soon; expect more news in a future Cwtch Testing update!\\n\\n- **More steps:** One of our longer-term goals with UI testing was to produce a language around Cwtch testing that went beyond widgets. We had begun to explore this last year with the `expect to see the message` step. As we grow our test library we will be looking for opportunities to build out additional higher-level and Cwtch-specific constructs, e.g. `send a file` or `set profile picture`.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-platform-support","metadata":{"permalink":"/blog/cwtch-platform-support","source":"@site/blog/2023-01-27-platform-support.md","title":"Cwtch UI Platform Support","description":"This development log captures the current state of Cwtch platform support, and how we plan to make platform support decisions going forward are we move towards Cwtch Stable.","date":"2023-01-27T00:00:00.000Z","formattedDate":"January 27, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"}],"readingTime":10.535,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch UI Platform Support","description":"This development log captures the current state of Cwtch platform support, and how we plan to make platform support decisions going forward are we move towards Cwtch Stable.","slug":"cwtch-platform-support","tags":["cwtch","cwtch-stable","support"],"image":"/img/devlog4_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Notes on Cwtch UI Testing","permalink":"/blog/cwtch-testing-i"},"nextItem":{"title":"Making Cwtch Bindings Reproducible","permalink":"/blog/cwtch-bindings-reproducible"}},"content":"One of the [tenets for Cwtch Stable is **Universal Availability and Cohesive Support**](https://docs.cwtch.im/blog/path-to-cwtch-stable#tenets-of-cwtch-stable):\\n\\n> \\"People who use Cwtch understand that if Cwtch is available for a platform then that means all features will work as expected, that there are no surprise limitations, and any differences are well documented. People should not have to go out of their way to install Cwtch.\\"\\n\\nThis development log seeks to capture the current state of Cwtch platform support, and how we plan to make platform support decisions going forward as we move towards Cwtch Stable.\\n\\nThe questions we aim to answer in this post are: \\n\\n- What systems do we currently support?\\n- How do we decide what systems are supported?\\n- How do we handle new OS versions?\\n- How does application support differ from library support?\\n- What blockers exist for systems we wish to support, but currently cannot e.g ios?\\n\\n![](/img/devlog4.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Constraints on support\\n\\nFrom CPU architecture, to app store policies, there are a large number of constraints that restrict what platforms Cwtch can target, and how usable Cwtch may be on those systems. \\n\\nIn this section we will highlight the restrictions that we are aware of, and provide a summary of the major external forces that impact our ability to support Cwtch across various platforms.\\n\\n### Limitations on general-purpose computing \\n\\nIn order for Cwtch to work, and be useful, it needs the ability to launch and manage long-lived onion services (in addition to Tor connections to *other* onion services). \\n\\nOn desktop platforms this is usually a given, but the ability to do that kind of activity on mobile operating systems is severely limited or, in many cases, **blocked entirely**. \\n\\nThis is the core reason why Cwtch is not available on iOS, and the main reason why Android support often lags behind.\\n\\nWhile we expect that [Arti](https://gitlab.torproject.org/tpo/core/arti) will improve the management of onion services and connections, there is no way around the need to have an active process managing such services. \\n\\nAs Appstore restrictions are tightened, and mobile operating systems are likewise restricted, we expect that Cwtch on mobile will have to move to a light-client model, requiring the aid of a companion desktop application to be usable.\\n\\nWe encourage you to support mobile operating system vendors who understand the value of general purpose computing, and who don\'t place restrictions on what you can do with your own device.\\n\\n### Constraints introduced by the Flutter SDK\\n\\nThe Cwtch UI is based on Flutter, and as such we have some hard boundaries driven by [platforms that are supported by the Flutter SDK](https://docs.flutter.dev/development/tools/sdk/release-notes/supported-platforms).\\n\\nTo summarize, as of writing this document those platforms are:\\n\\n- Android API 16 and above (arm, arm64, and amd64)\\n- Debian-based Linux Distributions (64-bit only)\\n- macOS El Capitan (10.11) and above\\n- Windows 7 & above (64-bit only)\\n\\nTo put it plainly, without porting Cwtch UI to a different UI platform **we cannot support a 32-bit desktop version**.\\n\\n### Constraints introduced by Appstore Policy \\n\\nAs of writing, [Google is pushing applications to target API 31 or above](https://developer.android.com/google/play/requirements/target-sdk). This target API version is increased on a regular cadence and usually packaged with greater restrictions on what applications can do. To put it another way, even if our minimum theoretical supported Android version is 16, we are practically limited to a subset of tolerated functionality.\\n\\n### CPU Architecture and Cwtch Bindings\\n\\nWe currently build the Cwtch UI and Cwtch Bindings for a wide variety of platform/architecture combinations (see the table below). Our ability to support a given architecture is driven primarily by the overlap of Go Compiler support, Flutter SDK support, and what architectures the underling operating system is available for.\\n\\nIt is worth noting that there is an explicit dependency between the Bindings and the UI. If we cannot build Cwtch Bindings for a given architecture (i.e. if the Go Compiler does not support a given architectures), then we also cannot offer the Cwtch UI for that architecture.\\n\\n| Architecture / Platform | Windows | Linux | macOS | Android |\\n|--------------------------|---------|-----|-------| -------------|\\n| arm | \u274c | \u274c | \u274c | \u2705\ufe0f| \\n| arm64 | \u274c | \ud83d\udfe1 | \u2705 | \u2705\ufe0f | \\n| x86-64 / amd64 | \u2705 | \u2705 | \u2705\ufe0f | \u2705\ufe0f |\\n\\n\\"\ud83d\udfe1\\" - indicates that support is possible, but not yet official e.g. arm64 linux (Raspberry Pi).\\n\\n### Testing and official support\\n\\nAs a non-profit, and an open source software project, we are limited in the resources we have to invest. We rely on the [Cwtch Release Candidate Testers](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group) to do much of the heavy lifting when it comes to Cwtch support on various platforms. This is especially true when it comes to Android variants where, even after testing across the spread of devices available to the Cwtch team, testers still encounter major issues.\\n\\nWe officially only perform full scale automated tests on Linux. With minimal platform regression tests on Windows, Android and OSX. Prior to Cwtch Stable we plan to have support for running automated regression tests across Linux, Windows and Android instances.\\n\\n### End-of-life platforms\\n\\nOperating Systems are never supported indefinitely. The Flutter SDK may allow support for Windows 7, but Microsoft no longer does. [Windows 7 fell out of support on January 14, 2020](https://www.microsoft.com/en-us/windows/end-of-support), Windows 8 followed early this month, on January 10th. 2023. Windows 10 will no longer be support after October 14, 2025.\\n\\nLikewise, while the Flutter SDK official supports OSX versions back to El Capitan (version 10.11), the oldest OSX version currently supported by Apple is Big Sur (version 11). While it may be possible for us to build different versions of Cwtch targeting different OSX versions, we would be doing so against unsupported SDK versions - incurring not only a support cost, but a possible security one also.\\n\\nThe same fundamental restrictions also impact Linux based distributions. While Flutter supports Ubuntu 18.04, and the platform still receiving updates until April 2023, the Cwtch team does not, because of the outdated version of libc installed on the platform would require a distinct build process. [Cwtch currently requires libc 2.31+](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#linux-specific-considerations).\\n\\nAndroid versions prior to Android 10 are no longer officially support, and the requirement to target the most recent versions of Android for inclusion on the Google Playstore mean that long term support for Android versions is driven almost entirely by Google. While Flutter technically has support for Android 16 and above (and we target that as a minimum SDK version), because we have to target the most recent SDK for inclusion on Google Playstore, we cannot make guarantees that these SDKs are fully backwards compatible. We encourage volunteers interested in Cwtch Android to join our [Cwtch Release Candidate Testers groups](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group) to help us understand the limitations of Android support across different API versions.\\n\\n## How we decide to officially support a platform\\n\\nTo help make decisions on what platforms we target for official builds, the Cwtch team have developed four key tenets:\\n\\n1. **The target platform needs to be officially supported by our development tools** - We do not have the resources to maintain forks of the Go compiler or the Flutter SDK that target other operating systems or architectures. The one exception to this rule are non-Debian Linux distributions which while not officially supported by Flutter, are unlikely to have major blockers to official support.\\n2. **The target operating system needs to be supported by the Vendor** - We cannot support a platform that is no longer receiving security updates. Nor do we have the resources to maintain distinct build environments that target out-of-support operating systems. While Cwtch may run on these platforms without additional assistance, we will not schedule work to fix broken support on such platforms. (We may, however, accept Pull Requests from volunteers).\\n3. **The target platform must be backwards compatible with the most recent version in general use** - Even if a system is technically supported by our development tools, and still receives security updates from the vendor, we may still be unbale to officially support it if doing so requires maintaining a separate build environment (because SDK or APIs of dependent libraries are no longer backwards compatible). Like above, Cwtch *may* run on these platforms without additional assistance, but we will not schedule work to fix broken support on such platforms. (we may, however, accept Pull Requests from volunteers).\\n4. **People want to use Cwtch on that platform** - We will generally only consider new platform support if people ask us about it. If Cwtch isn\'t available for a platform you want to use it on, then please get in touch and ask us about it!\\n\\n## Summary of official support\\n\\nThe table below represents our current understanding of Cwtch support across various operating systems and architectures (as of Cwtch 1.10 and January 2023). \\n\\nIn many cases we are looking for testers to confirm that various functionality works. A version of this table will be [maintained as part of the Cwtch Handbook](/docs/getting-started/supported_platforms).\\n\\n**Legend:**\\n\\n- \u2705: **Officially Supported**. Cwtch should work on these platforms without issue. Regressions are treated as high priority.\\n- \ud83d\udfe1: **Best Effort Support**. Cwtch should work on these platforms but there may be documented or unknown issues. Testing may be needed. Some features may require additional work. Volunteer effort is appreciated.\\n- \u274c: **Not Supported**. Cwtch is unlikely to work on these systems. We will probably not accept bug reports for these systems.\\n\\n\\n\\n| Platform | Official Cwtch Builds | Source Support | Notes |\\n|-----------------------------|-----------------------|--------------------|-----------------------------------------------------------------------------------------------------------------------------------|\\n| Windows 11 | \u2705 | \u2705 | 64-bit amd64 only. |\\n| Windows 10 |\u2705 | \u2705 | 64-bit amd64 only. Not officially supported, but official builds may work. |\\n| Windows 8 and below | \u274c | \ud83d\udfe1 | Not supported. Dedicated builds from source may work. Testing Needed. |\\n| OSX 10 and below | \u274c | \ud83d\udfe1 | 64-bit Only. Official builds have been reported to work on Catalina but not High Sierra |\\n| OSX 11 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| OSX 12 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| OSX 13 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| Debian 11 | \u2705 | \u2705 | 64-bit amd64 Only. |\\n| Debian 10 | \ud83d\udfe1 | \u2705 | 64-bit amd64 Only. |\\n| Debian 9 and below | \ud83d\udfe1 | \u2705 | 64-bit amd64 Only. Builds from source should work, but official builds may be incompatible with installed dependencies. |\\n| Ubuntu 22.04 | \u2705 | \u2705 | 64-bit amd64 Only. |\\n| Other Ubuntu | \ud83d\udfe1 | \u2705 | 64-bit Only. Testing needed. Builds from source should work, but official builds may be incompatible with installed dependencies. | \\n| CentOS | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Gentoo | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Arch | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Whonix | \ud83d\udfe1 | \ud83d\udfe1 | [Known Issues. Specific changes to Cwtch are required for support. ](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/550) |\\n| Raspian (arm64) | \ud83d\udfe1 | \u2705 | Builds from source work. |\\n| Other Linux Distributions | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Android 9 and below | \ud83d\udfe1 | \ud83d\udfe1 | Official builds may work. |\\n| Android 10 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 11 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 12 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 13 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| LineageOS | \ud83d\udfe1 | \ud83d\udfe1 | [Known Issues. Specific changes to Cwtch are required for support.](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/607) |\\n| Other Android Distributions | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-bindings-reproducible","metadata":{"permalink":"/blog/cwtch-bindings-reproducible","source":"@site/blog/2023-01-20-reproducible-builds-bindings.md","title":"Making Cwtch Bindings Reproducible","description":"How Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible.","date":"2023-01-20T00:00:00.000Z","formattedDate":"January 20, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":7.915,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Making Cwtch Bindings Reproducible","description":"How Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible.","slug":"cwtch-bindings-reproducible","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog3_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch UI Platform Support","permalink":"/blog/cwtch-platform-support"},"nextItem":{"title":"Cwtch Stable API Design","permalink":"/blog/cwtch-stable-api-design"}},"content":"From the start of the Cwtch project, the source code for all components making up Cwtch has been freely available for anyone to inspect, use, and modify.\\n\\nBut open source code is only one defense against malicious actors who might seek to undermine your privacy and security. This is why, as part of our ongoing Cwtch Stable work, we are working towards making all parts of the Cwtch chain reproducible and verifiable.\\n\\nThe whole point of reproducible builds is that you no longer have to trust binaries provided by the Cwtch Team because you can **independently verify** that the binaries we release are built from the Cwtch source code.\\n\\nIn this devlog we will talk about how Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible. This will be useful to anyone who is looking to reproduce Cwtch bindings specifically, and to anyone who wants to start implementing reproducible builds in their own project.\\n\\n\x3c!--truncate--\x3e\\n\\n## How Cwtch Bindings are Built\\n\\nSince we launched Cwtch Beta we have used Docker containers as part of our continuous build process.\\n\\nWhen a new change is merged into the repository it kicks off the Cwtch bindings build pipeline which result in the new source tree being downloaded, inspected, compiled, tested, and eventually packaged for different platforms.\\n\\nThe Cwtch Bindings build pipeline results in four compiled libraries:\\n\\n- **libcwtch.so** \u2013 For Linux Platforms, built using the [official golang:1.19.X Docker Image](https://hub.docker.com/_/golang)\\n- **libcwtch.dll** \u2013 For Windows Platforms, built using our own [mingw-go Docker Image](https://git.openprivacy.ca/openprivacy/mingw-go)\\n- **libcwtch.ld** \u2013 For OSX Platforms, built using our dedicated OSX build server (Big Sur 11.6.1)\\n- **cwtch.aar** \u2013 For Android Platforms, built using our own [Android/GoMobile Docker Image](https://git.openprivacy.ca/openprivacy/android-go-mobile)\\n\\nThese compiled libraries eventually make their way into Cwtch-based applications, like the Cwtch UI.\\n\\n## Making libCwtch Reproducible\\n\\nDocker containers alone aren\'t enough to guarantee reproducibility. On inspection of several builds of the same source tree, we noticed a few elements that were distinct to each build:\\n\\n* **Go Build ID**: By default, Go includes a build ID as part of compiled binaries. When using CGO this build ID is non-deterministic and differs for every build. We made the decision to override this build ID for all outputs, setting it to the version of the code being built.\\n* **Build Paths and Go Environment Variables**: By default, Go includes full filesystem paths, and many Go-specific environment variables in the compiled binary \u2013 ostensibly to aid with debugging. These can be removed using the `trimPath` option, which we now specify for all bindings builds.\\n\\n### Linux Specific Considerations\\n\\nAfter the general fixes for Go builds are applied, the main variable input that impacts reproducibility is the version of libc that the bindings are compiled against.\\n\\nOur Drone/Docker build environments are based on [Debian Bullseye](https://www.debian.org/releases/bullseye/) which provides [libc6-dev version 2.31](https://packages.debian.org/bullseye/i386/libc6-dev). Other development setups will likely link libc-dev 2.34+.\\n\\nlibc6-dev 2.34 is notable [because it removed dependencies on libpthread and libdl](https://developers.redhat.com/articles/2021/12/17/why-glibc-234-removed-libpthread) \u2013 neither are used in libCwtch, but they are currently referenced \u2013 which increases the number of sections (and thus the virtual addresses of those sections) defined in the produced ELF file.\\n\\nThis means that in order to reproduce libCwtch Linux bindings it is necessary to have a development environment that will link libc 2.31. We have provided a small, standalone environment which can be used for this purpose (see the section on [Next Steps](#next-steps) for more information).\\n\\n### Windows Specific Considerations\\n\\nThe headers of PE files technically contain a timestamp field. In recent years an [effort has been made to use this field for other purposes](https://devblogs.microsoft.com/oldnewthing/20180103-00/?p=97705), but by default `go build` will still include the timestamp of the file when producing a DLL file (at least when using CGO).\\n\\nFortunately this field can be zeroed out through passing `-Xlinker \u2013no-insert-timestamp` into the `mingw32-gcc` process.\\n\\nWith that, and the universal Go fixes outlined above, Windows bindings are now reproducible using the same standalone Linux environment.\\n\\n\\n### Android Specific Considerations\\n\\nWith the above universal Go fixes, Android build artifacts become almost repeatable. And on certain setups they appear to be reproducible. However,achieving full reproducibility for Android builds requires a number of specific environment dependencies, and considerations:\\n\\n* Cwtch makes use of [GoMobile](https://github.com/golang/mobile) for compiling Android libraries. We pin to a specific version `43a0384520996c8376bfb8637390f12b44773e65` in our Docker containers. Unlike `go build`, the `trimpPath` parameter passed to GoMobile does not strip all development environment paths. This means that the build environment needs consistent directory structures. We have noticed inconsistencies in the detail stripped between setups e.g. cwtch.aar files build by our Docker and Repliqate builds still contain randomized `/tmp/go-build*` references that developer builds do not. We are still in the process of tracking down how these inconsistencies are introduced.\\n* We still use [sdk-tools](https://developer.android.com/studio/releases/sdk-tools) instead of the new [commandline-tools](https://developer.android.com/studio/command-line). The latest version of sdk-tools is `4333796` and available from: [https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip](https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip). As part of our plans for Cwtch Stable we will be updating this dependency.\\n* Cwtch Android builds currently use OpenJDK 8, unchanged from the earliest prototypes when Android development required Java 8. There is no nice way of obtaining this JDK version anymore, our Docker Containers are based on the now deprecated `openjdk:8` image. As with sdk-tooks, as part of our plans for Cwtch Stable we will be updating this dependency. \\n\\nAll of the above mean that we cannot consider Android builds to be reproducible yet, but we believe this is an achievable goal within the next couple of release cycles.\\n\\n### OSX Specific Considerations\\n\\nPerhaps surprisingly, OSX builds present the biggest reproducibility challenge. Unlike Linux, Windows, and Android builds we do not have a Dockerized build environment for OSX builds - relying instead on a dedicated machine to perform the builds.\\n\\nAs with Linux above, the general fixes for setting Go build id and trimming paths are enough to ensure repeatability on the same machine.\\n\\nIn order to fully guarantee reproducibility, OSX libraries need to be built on the same version of OSX with the same version of Xcode. For reference our current build system uses: Big Sur 11.6.1 with Xcode version 13.2.1.\\n\\nIn an ideal world we would be able to cross-compile OSX libraries on Linux the same way we do for Windows and Android. While there are no technical limits, compiling for OSX is dependent on a [proprietary SDK](https://www.apple.com/legal/sla/docs/xcode.pdf). There is no way to trustfully obtain this SDK from anyone except Apple, and the license appears to strictly prohibit transferring the SDK to non-Apple hardware.\\n\\nBecause of these limitations we cannot yet offer a way to automatically verify OSX builds, in the same way that we can for Linux, Windows, and Android. We will continue to look for ways to bring OSX builds to the same level as the rest of our Windows and Linux distributions.\\n\\n## Introducing Repliqate!\\n\\nWith all the above changes, **Cwtch Bindings for Linux and Windows are fully reproducible!**\\n\\nThat alone is great, but we also want to make it easier for **you** to check the reproducibility of our builds yourself! As we noted in the introduction, the whole point of reproducible builds is that you no longer have to trust binaries provided by the Cwtch Team.\\n\\nTo make this process accessible we are releasing a new tool called [repliqate](https://git.openprivacy.ca/openprivacy/repliqate).\\n\\nRepliqate makes it easy to construct isolated build environments, powered by Qemu and a standard Debian Cloud Image distribution.\\n\\nRepliqate runs [build-scripts](https://git.openprivacy.ca/openprivacy/repliqate#writing-a-build-script) to perform actions like downloading the specific versions of Go used in Cwtch official builds, grabbing a copy of the source code for Cwtch bindings, compiling the latest tagged version, and checking the hash against the same version that is available from [builds.openprivacy.ca](https://build.openprivacy.ca/files/).\\n\\nWe now provide [Repliqate build-scripts](https://git.openprivacy.ca/cwtch.im/repliqate-scripts) for reproducible both [Linux libCwtch.so builds](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-linux.script), [Windows libCwtch.dll builds](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-windows.script)!\\n\\nWe also have a partially repeatable [Android cwtch.aar build](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-android.script) script that reproduces the official build environment, which we will be using to complete Android reproducible builds as detailed in the last section.\\n\\nYou can (and I want to highly encourage you to) perform all these steps yourself (either via Repliqate, or a setup with the same specifications) and report back. We want to know if there are any other barriers to reproducing Cwtch bindings, and anything that we can do to make the process easier.\\n\\n## Next Steps\\n\\nReproducible bindings are a big achievement, but there is obviously much more to do. In the coming weeks we are committed to undertaking the same process with our Cwtch UI builds to determine what needs to be done to make this as reproducible as bindings.\\n\\nAs we go through this process we also expect to add additional functionality to Repliqate. If you have any feedback or would like to contribute to Repliqate development then please get in touch!\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-api-design","metadata":{"permalink":"/blog/cwtch-stable-api-design","source":"@site/blog/2023-01-13-cwtch-stable-api-design.md","title":"Cwtch Stable API Design","description":"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ","date":"2023-01-13T00:00:00.000Z","formattedDate":"January 13, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"},{"label":"api","permalink":"/blog/tags/api"}],"readingTime":17.28,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable API Design","description":"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ","slug":"cwtch-stable-api-design","tags":["cwtch","cwtch-stable","planning","api"],"image":"/img/devlog2_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Making Cwtch Bindings Reproducible","permalink":"/blog/cwtch-bindings-reproducible"},"nextItem":{"title":"Path to Cwtch Stable","permalink":"/blog/path-to-cwtch-stable"}},"content":"Cwtch grew out of a prototype and has been allowed to evolve over time as we discovered better ways of implementing safe and secure metadata resistant communications. \\n\\nAs we grew, we inserted experimental functionality where it was most accessible to place - not, necessarily, where it was ultimately best to place it - this has led to some degree of overlapping, and inconsistent, responsibilities across Cwtch software packages.\\n\\nAs we move out of Beta and [towards Cwtch Stable](https://docs.cwtch.im/blog/path-to-cwtch-stable) it is time to revisit these previous decisions with both the benefit of hindsight, and years of real-world testing.\\n\\nIn this post we will outline our plans for the Cwtch API that realign responsibilities, and explicitly enable new functionality to be built in a modular, controlled, and secure way. In preparation for Cwtch Stable, and beyond.\\n\\n![](/img/devlog2.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### Clarifying Terminology\\n\\nOver the years we have evolved how we talk about the various parts of the Cwtch ecosystem. To make this document clear we have revised and clarified some terms:\\n\\n- **Cwtch** refers to the overall ecosystem including all the component libraries, bindings, and the flagship Cwtch application. \\n- **Cwtchlib** refers to the [reference implementation of the Cwtch Protocol](https://git.openprivacy.ca/cwtch.im/cwtch) / Application framework, currently written in Go.\\n- **Bindings** refers to C/Java/Kotlin/Rust bindings (primarily [libcwtch-go](https://git.openprivacy.ca/cwtch.im/libcwtch-go)) that act as an interface between Cwtchlib and downstream applications.\\n- `CwtchPeer` is where the reference Cwtch API is defined. It is responsible for managing the state of a single Cwtch Profile, persistence (e.g. storing messages), and automatically reacting to certain messages like message acknowledgements and providing public profile attributes (e.g. profile display name).\\n- `ProtocolEngine` is responsible for maintaining networking resources like listening threads, peer connections, ephemeral server connections. At present, `ProtocolEngine` is also responsible for automatically responding to certain kinds of messages like providing file chunks for shared files.\\n\\n\\n### Tenets of the Cwtch API Design\\n\\nBased on the tenets we have laid out for the Path to Cwtch Stable, we have adopted the following guiding principles for a new API design:\\n\\n- **Robustness** - new features and functionality can be implemented in Cwtch without adding new functions or dependencies to existing Cwtch interfaces.\\n- **Completeness** - all behaviour is either defined in the official library, or explicitly deferred to applications, no special behaviour is implemented by intermediate wrappers.\\n- **Security** \u2013 experiments should not compromise existing Cwtch functionality - and should be able to be turned on/off at any time without issue.\\n\\n### The Cwtch Experiment Landscape\\n\\nA summary of the experiments that are currently implements or in design, and the changes to the code that were required to support them.\\n\\n- **Groups** \u2013 the very first prototypes of Cwtch were designed around group messaging and, as such, multi-party chats are the most integrated experiment within Cwtch sharing interfaces with P2P chat and requiring specialized `ProtocolEngine` functionality to manage ephemeral connections and antispam tokens, including the introduction of new peer events like NewMessageFromGroup. \\n - **Hybrid Groups** - we have plans to upgrade the Groups experience to a more flexible \u201chybrid-groups\u201d protocol which requires additional custom hook-response that needs to be tightly controlled and isolated from other parts of the system.\\n- **Filesharing** \u2013 like Groups, Filesharing is a cross-cutting feature that required new APIs, new Hooks into Peer Events, and additional capability in `ProtocolEngine`.\\n- **Profile Images** \u2013 based on Filesharing and the core get/val functionality, there are only a few small parts of the codebase that are explicitly dedicated to profile images, and these are all event-based reactions that currently reside in the event-decoration module of licwtch-go, but could easily be moved to a standalone module if a hook-based API was available.\\n- **Server Hosting** \u2013 the only example of an Application-level experiment in Cwch at present. This functionality requires no changes to the cwtchlib module, but is mainly implemented in the libcwtch-go bindings themselves. Ideally this functionality would be moved into a standalone package.\\n- **Message Formatting** \u2013 notable as the the main example of a former experimental-functionality that was promoted to an optional feature, but because it is entirely UI based in implementation there are few insights that can be gained from its history\\n- **Search / Microblogging** \u2013 proposed features that would require database access/changes in order to implement fully and efficiently, any proposed changes to the Cwtch API should allow for the possibility of new functionality at all layers of the Cwtch stack, including storage.\\n- **Status / Profile Metadata** \u2013 proposed features that only require specific APIs / hooks for saving requested information for the purposes of caching.\\n\\n### The Problem with Experiments\\n\\nWe have done some work in past to limit the impact an experimental feature can have on the rest of Cwtch, mainly through providing restricted sets of public Cwtch APIs e.g. the `SendMessages` interface that only allows callers to send messages.\\n\\nWe have also worked to package experimental functionality into so-called **Gated Functionalities** that are only available if a given experiment is turned on.\\n\\nTogether, these form the current basis for implementing to Cwtch features in the official libraries, but they are not without problems:\\n\\n- The scope of a functionality is rather broad, and can only be passed a complete Cwtch profile or a denoted subset of functionality e.g. `SendMessages` \u2013 there is no current way to scope a function to a specific conversation, or to a given zone (e.g. filesharing code is technically able to update attributes unrelated to filesharing).\\n- The implementation of experiments has mostly been delegated to bindings and, as such, the gating inside CwtchLib is limited, often relying on state to be passed into it by the bindings, or relying on the bindings explicitly disable the functionality.\\n- This lack of ownership over experiments by the official CwtchLib means that libraries based on CwtchLib instead of bindings do not have access to the safeguards provided by the bindings.\\n\\n### Restricting Powerful Cwtch APIs\\n\\nTo carefully expand Cwtch out using additional experimental APIs we must work to limit the impact further e.g. restricting actions to a given type of conversation, or only executing actions at registered times. To do this we require three separate but related strands of work:\\n\\n- Assume responsibility for experiments and features in Cwtch itself so that Cwtchlib has direct access to which experiments are enabled at any given time. Doing this allows changes to settings to always flow through `Application` and, (as currently happens with Anonymous Communication Network (ACN) state), provides a natural point at which to interface those changes into a Cwtch Profile.\\n- Finer-grained Interfaces that allow restricting actions to preregistered conversation types e.g. a `RestrictedCwtchConversationInterface` which decorates a Cwtch Profile interface such that it can only interact with a single conversation \u2013 these can then be passed into hooks and interface functions to limit their impact.\\n- Registered Hooks at pre-specified points with restricted capabilities \u2013 to allow experimental functionality to register interest in certain events, and act on them at the correct time, and to allow `CwtchPeer` to control which experiments get access to which events at a given time.\\n\\n#### Pre-Registered Hooks\\n\\nIn order to implement certain functionality actions need to take place in-between events handled by `CwtchPeer`. As a motivating example consider a new group membership protocol overlayed above the existing messages. Such a protocol may require checking against group permission settings after receiving a new message, but before inserting it into into the database (e.g. the message author needs to be confirmed against the list of current members authorized to post to the group).\\n\\nThis is currently only possible with invasive changes to the `CwtchPeer` interface, explicitly inserting a hook point and acting on it. In an ideal design we would be able to register such hooks for most likely events without additional development effort.\\n\\nWe are introducing a new set of Cwtch APIs designed for this purpose:\\n\\n- `OnNewPeerMessage` - hooked prior to inserting the message into the database.\\n- `OnPeerMessageConfirmed` \u2013 hooked after a peer message has been inserted into the database.\\n- `OnEncryptedGroupMessage` \u2013 hooked after receiving an encrypted message from a group server.\\n- `OnGroupMessageReceived` \u2013 hooked after a successful decryption of a group message, but before inserting it into the database.\\n- `OnContactRequestValue` \u2013 hooked on request of a scoped (the permission level of the attribute e.g. `public` or `conversation` level attributes), zoned ( relating to a specific feature e.g. `filesharing` or `chat`), and keyed (the name of the attribute e.g. `name` or `manifest`) value from a contact.\\n- `OnContactReceiveValue` \u2013 hooked on receipt of a requested scoped,zoned, and keyed value from a contact.\\n\\nIncluding the following APIs for managing hooked functionality:\\n\\n- `RegisterEvents` - returns a set of events that the extension is interested processing.\\n- `RegisterExperiments` - returns a set of experiments that the extension is interested in being notified about\\n- `OnEvent` - to be called by `CwtchPeer` whenever an event registered with `RegisterEvents` is called (assuming all experiments registered through `RegisterExperiments` is active)\\n\\n#### `ProtocolEngine` Subsystems\\n\\nAs mentioned in our experiment summary, some functionality needs to be implemented directly in the `ProtocolEngine`. The `ProtocolEngine` is responsible for managing networking clients, and sending/receiving packets from those clients to/from a CwtchPeer (via the event bus).\\n\\nSome types of data are too costly to send over the event bus e.g. requested chunks from shared files, and as such we need to delegate the handling of such data to a `ProtocolEngine`.\\n\\nAt the moment is this done through the concept of informal \u201csubsystems\u201d, modular add-ons to `ProtocolEngine` that process certain events. The current informal nature of this design means that there are not hard-and-fast rules regarding what functionality lives in a subsystem, and how subsystems interact with the wider `ProtocolEngine` ecosystem. \\n\\nWe are formalizing this subsystem into an interface, similar to the hooked functionality in `CwtchPeer`:\\n\\n- `RegisterEvents` - returns a set of events that the subsystem needs to consume to operate.\\n- `OnEvent` \u2013 to be called by `ProtocolEngine` whenever an event registered with `RegisterEvents` is called (when all the experiments registered through `RegisterExperiments` are active)\\n- `RegisterContexts` - returns the set of contexts that the subsystem implements e.g. `im.cwtch.filesharing`\\n\\nThis also requires a formalization of two *engine specific* events (for use on the event bus):\\n\\n- `SendCwtchMessage` \u2013 encapsulating the existing `CwtchPeerMessage` that is used internally in `ProtocolEngine` for messages between subsystems.\\n- `CwtchMessageReceived` \u2013 encapsulating the existing `handlePeerMessage` function which effectively already serves this purpose, but instead of using an Observer pattern, is implemented as an increasingly unwieldy set of if/else blocks.\\n\\nAnd the introduction of three **additional** `ProtocolEnine` specific events:\\n\\n- `StartEngineSubsystem` \u2013 replaces subsystem specific start event, can be driven by functionalities to (re)start protocol specific handling.\\n- `StopEngineSubsystem` \u2013 replaces subsystem specific stop event mechanisms, can be driven by functionalities to stop all protocol specific handling.\\n- `SubsystemStatus` \u2013 a generic event that can be published by subsystems with a collection of fields useful for debugging\\n\\nThis will allow us to move the following functionality, currently part of `ProtocolEngine` itself, into generic subsystems:\\n\\n- **Attribute Lookup Handling** - this functionality is currently part of the overloaded `handlePeerMessage` function, filtered using the `Context` parameter of the `CwtchPeerMessage`. As such it can be entirely delegated to a subsystem. \\n- **Filesharing Chunk Request Handling** \u2013 this is also part of handlePeerMessage, also filtered using the `Context` parameter, and is already almost entirely implementing in a standalone subsystem (only routing is handled by `handlePeerMessage`)\\n- **Filesharing Start File Share/Stop File Share** \u2013 this is currently part of the `handleEvent` behaviour of `ProtocolEngine` and can be moved into an `OnEvent` handler of the file sharing subsystem (where such events are already processed).\\n\\nThe introduction of pre-registered hooks in combination with the formalizations of `ProtocolEngine` subsystems will allow the follow functionality, currently implemented in `CwtchPeer` or libcwtch-go to be moved to standalone packages:\\n\\n- **Filesharing** makes heavy use of the getval/retval functionality, we can move all of this into a hooked-based functionality extension. \\n - Filesharing also depends on the file sharing subsystem to be enabled in a `ProtocolEngine`. This subsystem is responsible for processing chunk requests.\\n- **Profile Images** \u2013 we treat profile images as a specialization of the file sharing function, as such the experiment can operate entirely over apis provided by the filesharing experiment. (Right now this specialization lives in libcwtch-go as hooks into the relevant functions)\\n- **Legacy Groups** \u2013 while groups themselves are a first-class consideration for Cwtch, the actual process of constructing and receiving group messages relies heavily on processing of events, or interpreting generic conversation attributes, and as such this functionality can be moved entirely to hooked-based functionality. By doing this we also open the path towards introducing new group protocols based on the same interface.\\n- **Status/Profile Metadata** \u2013 status depends entirely on OnPeerRequestValue / OnPeerReceiveValue and requires little Cwtch Peer interaction other than saving the result.\\n \\n#### Impact on Enabling (Powerful) New Functionality\\n\\nNone of the above restricts our ability to introduce new functionality in to Cwtch that is dependent on more invasive changes (e.g. direct database access / updates), but they do allow us to structure such changes into discrete modules:\\n\\n- **Search** \u2013 a fulltext search feature requires new indexes to be created in Cwtch Storage (likely using the sqlite FT5 module). As an experiment SearchFunctionality would need access to a hook after database setup in order to create and populate those indexes. This is a far more powerful feature than most as it requires direct database access.\\n- **Non Chat Conversation Contexts** - the storage backend work we implemented last year had a long-term goal of enabling non-chat contexts like microblogging. Like search, these kinds of experiments will require deeply integrated access to the Cwtch database.\\n\\n## Application Experiments\\n\\nOne kind of experiment we haven\u2019t touched on yet is additional application functionality, at present we have one main example: Embedded Server Hosting \u2013 this allows a Cwtch desktop client to setup and manage Cwtch Servers.\\n\\nThis kind of functionality doesn\u2019t belong in Cwtchlib \u2013 as it would necessarily introduce unrelated dependencies into the core library.\\n\\nThis functionality also doesn\u2019t belong in the bindings either. They should be as minimal as possible. To that end, we will be moving this functionality out of the bindings and into dedicated repositories which can be managed via an Application Experiment interface.\\n\\n## Bindings\\n\\nThe last problem to be solved is how to interface experiments with the bindings (libcwtch-go) and ultimately downstream applications.\\n\\nWe can split the bindings into four core areas:\\n\\n- **Application Management** - functionality necessary to manage the core Cwtch application e.g. StartCwtch, ReconnectCwtchForeground, Shutdown, CreateProfile etc. This category also include FreePointer which is necessary for safe memory management.\\n- **Application Experiments** - auxiliary functionality that augments the Cwtch application with new features e.g. Server Hosting etc.\\n- **Core Profile Management** - core non-experimental functionality that requires a profile e.g. ImportBundle, SendMessage etc. These apis take a handle in addition to the parameters needed to call the underlying function.\\n- **Experimental Profile Features** \u2013 auxiliary functionality that augments profiles with additional features e.g. ShareFile, SetProfileImage etc. These apis also take a handle.\\n\\nThe flip side of the bindings is the event bus handing which is responsible for maintaining a queue for the downstream application. This queue provides some filtering and enhancement of events to improve performance. This queue can be moved entirely into Application with only GetAppBusEvent defined and exposed in the bindings.\\n\\nIn an ideal future, all of these bindings could be **generated automatically** from the Cwtchlib interface definitions i.e. there should be no special functionality in the bindings themselves. The generation would need to include C bindings (untyped with automatic checks) and the Dart library calling convention (type safe)\\n\\nWe can define three types of C/Java/Kotlin interface function templates:\\n\\n- `ProfileMethodName(profilehandle String, args...)` \u2013 which directly resolves the Cwtch Profile and calls the function.\\n- `ProfileExperimentalMethodName(profilehandle String, args...)` \u2013 which checks the current application settings to see if the experiment is enabled, and then resolves the CwtchProfile and calls the function - else errors.\\n- `ApplicationExperimentalMethodName(args...)` \u2013 which checks the current application settings to see if the experiment is enabled, and if so, calls the experimental application functionality.\\n\\nAll we need to know from CwtchLib is what methods to export to C bindings, and what template they should use. This can be automatically derived from the context `ProfileInterface` for the first, exported methods of the various `Functionalities` for the second, and `ApplicationExperiment` definitions for the third.\\n\\n## Timelines and Next Actions\\n\\n- **Freeze any changes to the bindings interface** - we have made minimal changes to the bindings in the Cwtch 1.9 and 1.10 \u2013 until we have implemented the proposed changes into cwtchlib.\\n- As part of Cwtch 1.11 and 1.12 Release Cycles\\n - Implement the `ProtocolEngine` Subsystem Design as outlined above.\\n - Implement the Hooks API.\\n - Move all special behaviour / extra functionalities in the libcwtch-go bindings into cwtchlib \u2013 with the exception of behaviour related to Application Experiments (i.e. Server Hosting).\\n - Move event handling from the bindings into Application.\\n - Move Application Experiments defined in bindings into their own libraries (or integrate them into existing libraries like cwtch-server) \u2013 keeping the existing interface definitions.\\n- Once Automated UI Tests have been integrated into the Cwtch UI Repository:\\n - Write a generate-cwtch-bindings tool that auto generates the libcwtch-go C/Android bindings **and** a dart calling convention library from cwtchlib and any configured application experiments libraries\\n - Port the existing UI app to use the newly generated dart Cwtch library (this must wait until we have automated UI testing as part of the build process to ensure that there are no regressions during this process).\\n - At this point the bindings are based off of the generated library and libcwtch-go is deprecated / replaced with automatically generated and versioned bindings.\\n\\nAs these changes are made, and these goals met we will be posting about them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)\\n\\n## Appendix A: Special Behaviour Defined by libcwtch-go\\n\\nThe following is an exhaustive list of functionality currently provided by libcwtch-go bindings instead of the cwtchlib:\\n\\n- Application Settings\\n - Including Enabling / Disabling Experiment\\n- ACN Process Management - starting/stopping/restarting/configuring Tor.\\n- Notification Handling - augmenting/suppressing/augmenting interesting event notifications (primarily for Android)\\n- Logging Levels - configuring appropriate logging levels (e.g. `INFO` or `DEBUG`)\\n- Profile Images Helper Functions - handling default profile images for contacts and groups, in addition to looking up custom profile images if the experiment is enabled.\\n- UI Contact Structures - aggregating contact information for the main Cwtch UI.\\n- Group Experiment Functionality\\n - Experiment Gating\\n - GetServerInfoList\\n - GetServerInfo\\n - UI Server Struct Definition\\n- Server Hosting Experiment Functionality - creating/deleting/managing the server hosting experiment for desktop Cwtch clients.\\n- \\"Unencrypted\\" Profile Handling - replacing a blank password with a default password where the underlying API expects a password but the profile has been designated \\"unencrypted\\".\\n- Image Previews Experiment Handling - automatically starting the downloading of certain file types (when the experiment is enabled).\\n- Cwtch UI Reconnection Handling (for Android) - restarting various Cwtch subsystems when the UI attempts to reconnect in circumstances where the Android kernel has killed the underlying process.\\n- Cwtch Profile Engine Activation - starting/stopping a `ProtocolEngine` when requested by the UI, or in response to changes in ACN state.\\n- UI Profile Aggregation - aggregating information related to Profiles for the UI (e.g. network connection status / unread messages) into a single event.\\n- File sharing restarts \\n- UI Event Augmentation - augmenting various internal Cwtch events with information that the UI needs but that isn\'t directly embedded within the event (e.g. converting `handle` to a `conversation id`). Much of this augmentation is legacy, implemented before recent changes to internal Cwtch structs, and likely can either be removed entirely, or delegated into Cwtch itself.\\n- Debug Information - special information available to Cwtch debug builds (memory use / active goroutines etc.)"},{"id":"path-to-cwtch-stable","metadata":{"permalink":"/blog/path-to-cwtch-stable","source":"@site/blog/2023-01-06-path-to-cwtch-stable.md","title":"Path to Cwtch Stable","description":"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.","date":"2023-01-06T00:00:00.000Z","formattedDate":"January 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":9.995,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Path to Cwtch Stable","description":"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.","slug":"path-to-cwtch-stable","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable API Design","permalink":"/blog/cwtch-stable-api-design"}},"content":"As of December 2022 we have released 10 versions of Cwtch Beta since the [initial launch, 18 months ago, in June 2021](https://openprivacy.ca/discreet-log/10-cwtch-beta-and-beyond/).\\n\\nThere is a consensus among the team that the next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable.\\n\\nThis post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview of the next steps and our timeline for tackling them.\\n\\n![](/img/devlog1.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### Tenets of Cwtch Stable\\n\\nIt is important to state that Cwtch Stable **does not mean an end to Cwtch development**. Rather, it establishes a baseline at which point Cwtch is considered to be a fully supported project. The Cwtch Team have set the following tenets that guide our decision-making and priorities:\\n\\n1. **Consistent Interface** \u2013 each new Cwtch release should be accompanied by consistent releases to all support libraries. This requires a stable and documented API so that we can be clear when upgrading a library will result in breaking change for downstream projects. We should not, as a general rule, have to make breaking changes to this API interface in order to support new experimental features.\\n2. **Universal Availability and Cohesive Support** \u2013 people who use Cwtch understand that if Cwtch is available for a platform then that means all features will work as expected, that there are no surprise limitations, and any differences are well documented. People should not have to go out of their way to install Cwtch.\\n3. **Reproducible Builds** \u2013 Cwtch builds should be trivially reproducible, including the ability to reproduce all bundled assets. Reproducibility should not rely on containerization, but all containers used in our build process should be reproducible.\\n4. **Proven Security** \u2013 we can demonstrate that Cwtch provides first class security through well documented design, testing, and audit procedures. We should be able to do this for Cwtch in addition to all functional dependencies.\\n\\n### Known Problems\\n\\nTo begin, let\'s outline the current state of Cwtch and lay out the issues that stand in the way of Cwtch Stable.\\n\\n1. **Lack of a Stable API for future feature development** \u2013 while the core Cwtch API has remained fairly unchanged in recent releases we understand that the addition of new features e.g. cohesive group support likely requires new API hooks that allow safe manipulation of Cwtch Profile (transactional semantics and post-event hooks). Before we can even consider a stable release we need to define what this API should look like, and implement it. (Tenet 1)\\n2. **Special functionality in libCwtch-go** \u2013 our C-API bridge (libCwtch-go) currently implements a lot of special functionality in support for both experimental features (e.g. profile images) and UI settings. This special behaviour makes it difficult to track feature responsibility. This behaviour must either be pushed back into the main Cwtch library, or defined to be the responsibility of a downstream application e.g. Cwtch UI. (Tenet 1)\\n3. **libCwtch-rs partial support** - we currently do not officially consider [libCwtch-rs](https://lib.rs/crates/libcwtch) when updating libCwtch-go as part of our release schedule. Before we can consider a Cwtch Stable release we should have multiple beta releases where libCwtch-rs has full support for any and all new Cwtch features. (Tenet 1, Tenet 2)\\n4. **Lack of Reproducible Pipelines** - while the vast majority of our build pipeline is automated, containerized, and reproducible, there remain bundled assets that cannot be trivially constructed, and assets that have non-reproducible elements (e.g. build-time injected via git tags, and go binaries including build user information). (Tenet 3)\\n5. **Lack of up to date, and translated, Security Documentation** \u2013 the [Cwtch security handbook](https://docs.openprivacy.ca/cwtch-security-handbook/) is currently isolated from the rest of our documentation and doesn\u2019t benefit from cross-linking, or translations. (Tenet 4)\\n6. **No Automated UI Tests** \u2013 we put a lot of work into [building out a testing framework for the UI](https://openprivacy.ca/discreet-log/23-cucumber-testing/), but it currently sits mostly unused, and unexercised in our build pipelines. We should revisit that work. (Tenet 4)\\n7. **Code Signing Provider** \u2013 our previous code signing certificate provider had support issues, and we have not yet decided on a replacement. ( Tenet 4)\\n8. **Second-class Android Support** - while we have put [a lot of effort behind Android support](https://openprivacy.ca/discreet-log/27-android-improvements/) across the Beta timeline, it still clearly suffers from additional issues that desktop editions do not. In order to consider Cwtch stable we must resolve all major bugs impacting Android usability. (Tenet 2)\\n9. **Lack of Fuzzing** \u2013 while [Fuzzbot](https://openprivacy.ca/discreet-log/07-fuzzbot/) sets a standard high above most other secure communication applications, we can and should do better. Fuzzbot currently only targets user-endpoint messages, which are the most likely to result in real-world risk, but we should strive to have the same coverage for internal events at both the network level, the internal Cwtch App level, and the event bus level. (Tenet 4)\\n10. **Lack of Formal Release Acceptance Process** \u2013 currently the features and experiments that get included in each release are determined in an ad-hoc consensus. This occasionally means that some features are left unsupported on certain platforms, and bugs occasionally arise in platforms (Android in particular) due to \u201cunrelated\u201d changes. In order for Cwtch to be declared stable, a formal acceptance process must ensure that new changes do not break existing features, and that they work across all platforms. (Tenet2, Tenet 4)\\n11. **Inconsistent Cwtch Information Discovery** \u2013 our current documentation is split between docs.cwtch.im, cwtch.im and docs.openprivacy.ca, in additional to blogs on Discreet Log. This makes it difficult for people to learn about Cwtch, and also means that our own explanations often must link across multiple different sites. (Tenet 2)\\n12. **Incomplete Documentation** \u2013 docs.cwtch.im was very well received. However, it still suffers from incomplete sections, missing links, and an overall lack of screenshots. What screenshots there are lack consistency in sizing, style, and feel. (Tenet 2)\\n\\n### Plan of Action\\n\\nOutside of the problems that have standalone solutions (e.g. find a new code signing provider, or fix all Android issues), there are a number of higher level activities that need to be completed before we can be confident in a Cwtch Stable release:\\n\\n1. **Define, Publish, and Implement a Cwtch Interface Specification Documentation** \u2013 this should include examples of how new (experimental) behaviour might be implemented from finer-grained composition. Must include moving all special functionality out of libCwtch-go. Should be followed up by implementing the proposed design. (Tenet 1, Tenet 4)\\n2. **Define, Publish, and Implement a Cwtch Release Process** \u2013 this document should outline the criteria for publishing a new release, the difference between major and minor versions, how features are tested, how regressions are caught before release, and who is responsible for different parts of the process. (Tenet 2)\\n3. **Define, Publish, and Implement a Cwtch Support Document** - including answers to the questions: what systems do we support, how do we decide what systems are supported, how do we handle new OS versions, and how does application support differ from library support. This should also include a list of blockers for systems we wish to support, but currently cannot e.g ios. (Tenet 2)\\n4. **Define, Publish, and Implement a Cwtch Packaging Document** - as a supplement to the Support document we need to define what packaging we support, in addition to what app stores and managers for which we provide official releases. ( Tenet 2)\\n5. **Define, Publish, and Implement a Reproducible Builds Document** \u2013 this should cover not only Cwtch binaries, but also Docker containers, and included assets (e.g. Tor binaries). Followed up by implementing the plan into our build pipeline. ( Tenet 3)\\n6. **Expand the Cwtch Documentation Site** \u2013 to include the Security Handbook, development blogs, design documentation, and support plans. This should be our only publishing platform, outside of a landing page, and downloads on cwtch.im. This expansion should include a style guide for documentation and screenshots to ensure that we maintain consistent language and visuals when talking about a feature (e.g. we should use the same profile image style, theme, profile names, message style etc.) (Tenet 1, Tenet 2, Tenet 3, Tenet 4)\\n7. **Expand our Automated Testing to include UI and Fuzzing** - integrate UI automated tests into our build pipeline. Expand our fuzzing to include the event bus, and PeerApp packets. Finally, integrate automated fuzzing into the build pipeline, so that all new features are fuzzed to the same level. (Tenet 4)\\n8. **Re-evaluate all Issues across all Cwtch related repositories** \u2013 issues are either bugs that need to be fixed before stable (i.e. they are in service of one of the Tenets), new feature ideas that should be scheduled around stable work (i.e. they don\u2019t align with a specific Tenet), or support requests for systems that need input from the Support and Packaging Plans.\\n9. **Define a Stable Feature Set** \u2013 there are still a few features which do not exist in Cwtch Beta which would be required for a stable release, such as chat search. Following on from the Cwtch Interface Specification Document, the team should decide what features Cwtch Stable will target, and these features should be prioritized for inclusion in Cwtch 1.11, Cwtch 1.12 and any future Beta releases. (Tenet 1)\\n\\n### Goals and Timelines\\n\\nWith all of that laid out, we are now ready to introduce a timeline for resolving some of these problems, and moving us towards a state where we can launch Cwtch Stable:\\n\\n1. By **1st February 2023**, the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases).\\n2. By **1st February 2023**, the Cwtch team will have finalized a feature set that defines Cwtch Stable and established a timeline for including these features in upcoming Cwtch Beta releases.\\n3. By **1st February 2023**, the Cwtch team will have expanded the Cwtch Documentation website to include a section for Security, Design Documents, Infrastructure and Support, in addition to a new development blog.\\n4. By **31st March 2023**, the Cwtch team will have created a style guide for documentation and have used it to ensure that all Cwtch features have consistent documentation available, with at least one screenshot (where applicable).\\n5. By **31st March 2023** the Cwtch team will have published a Cwtch Interface Specification Document, a Cwtch Release Process Document, a Cwtch Support Plan document, a Cwtch Packaging Document, and a document describing the Reproducible Builds Process. These documents will be available on the newly expanded Cwtch Documentation website.\\n6. By **31st March 2023** the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository.\\n7. By **31st March 2023** the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team.\\n8. By **31st March 2023** the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable.\\n\\nAs these documents are written, and these goals met we will be posting them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, Cwtch development.\\n\\n### Help us get there!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"}]}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/b2f554cd.f51eff8b.js b/build-staging/assets/js/b2f554cd.f51eff8b.js deleted file mode 100644 index 5e617e89..00000000 --- a/build-staging/assets/js/b2f554cd.f51eff8b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1477],{10:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"path-to-hybrid-groups","metadata":{"permalink":"/blog/path-to-hybrid-groups","source":"@site/blog/2024-01-05-path-to-hybrid-groups.md","title":"Path to Hybrid Groups","description":"A look at how we plan on implementing the next generation of Cwtch multi-party messaging","date":"2024-01-05T00:00:00.000Z","formattedDate":"January 5, 2024","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"hybrid-groups","permalink":"/blog/tags/hybrid-groups"}],"readingTime":5.14,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Path to Hybrid Groups","description":"A look at how we plan on implementing the next generation of Cwtch multi-party messaging","slug":"path-to-hybrid-groups","tags":["cwtch","hybrid-groups"],"image":"/img/hybridgroups.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"nextItem":{"title":"Cwtch 1.13 Stable Release Candidate","permalink":"/blog/cwtch-1-13"}},"content":"Back in [September 2023 we released Cwtch 1.13](/blog/cwtch-1-13), the first version of Cwtch to be labelled as **stable**, \\nand a major milestone in Cwtch development. \\n\\nWith the Cwtch interface now stable, we are in a position to begin a new phase in Cwtch development: a Path towards\\n**Hybrid Groups**.\\n\\n![](/img/hybridgroups.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## The Problem with Cwtch Groups\\n\\nOne of the unique features of Cwtch is that [groups](/docs/groups/introduction) are dependent on [untrusted infrastructure](/security/components/cwtch/server).\\n\\nBecause of this, at their most basic, a Cwtch group is simply an agreement between a set of peers on a common\\ncryptographic key, and a common (set of) untrusted server(s).\\n\\nThis provides Cwtch Groups with very nice properties such as anonymity to anyone not in the group, but it does mean\\nthat certain other nice properties like member flexibility, and credential rotation are difficult to achieve.\\n\\nWe want to allow people to make the right trade-off when it comes to their own risk models, i.e. to be able to trade\\nefficiency for trust when that decision makes sense.\\n\\nTo do that we need to introduce a new class of group into Cwtch, something we are calling **Hybrid Groups**.\\n\\n## What Are Hybrid Groups?\\n\\nThe goal of hybrid groups is to balance the security properties of Cwtch peer-to-peer communication with the\\nproperties of untrusted infrastructure. \\n\\nThis is done by augmenting existing Cwtch Groups with an additional layer of peer-to-peer communication in order to provide\\nefficient participant management, key rotation, and other useful features.\\n\\n### Levels of Hybrid Groups\\n\\nIn practice, we imagine there will be a few different levels of Hybrid Group, reflecting different trade-offs between inter-peer trust,\\ncommunication efficiency, and group security.\\n\\nThere are **Traditional Groups**, these have similar properties to the existing Cwtch Groups. Highly inefficient, but essentially \\nrequire zero-trust on behalf of participants other than an expectation that the key is kept secret.\\n\\nWe plan to introduce **Managed Groups**: A new kind of group where all participants explicitly trust a given always-online peer (e.g. a bot) with group operations. These \\nwill be highly efficient, at the cost of that explicit trust (if that peer behaves maliciously then certain properties are broken). Managed groups will\\nbe the first Cwtch groups to allow **Contractable** and **Expandable** groups, and more efficient **Key Rotation**.\\n\\nAnd finally a category of **Augmented Groups**: An extension of Managed Groups that places configurable restrictions of the trust given to \\nthe peer e.g. by requiring participants to take part in a meta-protocol that confirms certain actions before they are carried out (preventing\\nthe trusted-peer from harming properties like **Participant Consistency**.\\n\\n## Group Messaging Metadata\\n\\nAs with the rest of Cwtch, our ultimate goal is that no metadata (and specifically as part of this work, no group metadata e.g. membership, message timing) be\\navailable to a party outside of the group.\\n\\nTraditional Cwtch Groups take this to the extreme, and the expense of long syncing times, and a high possibility of disruption. Managed Groups\\nand Augmented groups will allow communities to make the right trade-offs allowing for greater resilience and faster syncing.\\n\\n## A Rough Timeline (Q1: Week 0 - Week 10 2024)\\n\\n- **Week 0** - Planning Q1 Cwtch Timeline (this devlog), minor bug fixes and other small UI-focused work originating from reports and feedback\\nfrom [Cwtch testers](/docs/contribute/testing).\\n- **Week 1** - Work begins on exposing **Enhanced Permissions** in the Cwtch library. These are essential to implementing many of the aspects\\nof the new group design, as well as improving other parts of contact management. (Expect more about this in a future devlog). Also, a formal model for Managed Groups will be created and documented. \\nThis will form the basis of the implementation.\\n- **Week 2** - At this point we should be able to begin designing the Managed Group Extension to Cwtch. This will use the Cwtch Event Hooks API\\nto respond to Peer events to manage groups. During this work, we also expect to migrate the legacy group code into it\'s own similar extension to make\\nbest use of the APIs. \\n- **Week 3** - Towards the end of January we expect to have a complete formal model of Managed Groups and to be able to start integrating the new extensions into the\\nCwtch-UI. We also expect to be in the process of releasing a new 1.14 version of Cwtch that supports Enhanced Permissions.\\n- **Weeks 4 - Week 6** - February marks the 6th anniversary of the founding of Open Privacy Research Society, and our organizational year end. During this\\ntime core members of the Cwtch team are often involved in administrative tasks that need to be done during this time, as such we are not planning to make too much progress on Cwtch during this time.\\n- **Weeks 7 - Week 10** - As we approach March, we will be formally integrating Managed Groups in Cwtch, and planning a Cwtch 1.15 release which will feature the new group type. During this time we will also be updating\\nCwtch [Group Documentation](https://docs.cwtch.im/docs/category/groups) .\\n\\nOnce Managed Groups have been rolled out, we will assess what we have learned and proceed with similar steps for \\nAugmented Groups in Q2 (more on that in a later devlog!).\\n\\n## Stay up to date!\\n\\nAs always, we will be regularly updating this devlog [and other channels](https://fosstodon.org/@cwtch) as we continue to make progress towards\\nsurveillance resistant infrastructure!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-1-13","metadata":{"permalink":"/blog/cwtch-1-13","source":"@site/blog/2023-09-27-cwtch-1.13-nightly.md","title":"Cwtch 1.13 Stable Release Candidate","description":"Cwtch 1.13 (Stable Release Candidate)","date":"2023-09-27T00:00:00.000Z","formattedDate":"September 27, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":5.74,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch 1.13 Stable Release Candidate","description":"Cwtch 1.13 (Stable Release Candidate)","slug":"cwtch-1-13","tags":["cwtch","cwtch-stable","release"],"image":"/img/picnic1.13.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Path to Hybrid Groups","permalink":"/blog/path-to-hybrid-groups"},"nextItem":{"title":"September Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-sept"}},"content":"[Cwtch 1.13 is now available for download](https://cwtch.im/download)!\\n\\nCwtch is a communication application (and associated libraries) that uses Tor v3 Onion Services to establish surveillance resistant channels between people. Cwtch has been designed to be \\nsecure, private, and resilient.\\n\\nCwtch 1.13 is the culmination of the last few years of effort by the Cwtch team, and is the first release that meets our bar to be labelled a [Cwtch Stable](/blog/path-to-cwtch-stable) candidate.\\n\\nWhile much more work remains, we are now very confident in the state of the Cwtch library, and the Cwtch UI. We are prepared to make certain commitments regarding peer-to-peer messaging, the UI,\\nand experimental interfaces. In this post we will chart the journey that got us to this point, highlight what is in this new release, and talk about our next steps.\\n\\n![](/img/devlog14.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Cwtch Stable and Beyond!\\n\\nOver five years ago, on the 28th June 2018, we published the first official announcement of Cwtch. Throughout 2019 we published various Alpha releases of Cwtch. The original plan was to release a Cwtch Beta in 2020.\\n\\nLike so many other projects in 2020, Cwtch Beta was delayed, and towards the end of 2020 it became clear that our original approach to a cross-platform UI was not sustainable long term.\\n\\nFinally, in June 2021 we launched Cwtch Beta 1.0. We have spent the years since refining beta, adding features, and responding to feedback.\\n\\nWe have now reached a pivotal moment in Cwtch, one that the team has been working towards for many years. We now believe that Cwtch has reached a point where people can use core features, and enable\\nexperimental features, with a confidence that any risks are well understood and appropriately mitigated. As such we are dropping the \\"beta\\" label.\\n\\nSome features, like automatically downloading and displaying images, will always carry some risk - as such these will always remain off-by-default in Cwtch. \\n\\nHowever, if approporate precautions are taken (like never accepting conversations from untrusted entities) then these features can be turned on and used without additional considerable risk.\\n\\nFurther, we believe that the API presented by libCwtch has reached a point where its core design is unlikely to require changes - and as such are prepared to make additional committements to the stability\\nof that API going forward. Any new functionality will be provided by new interfaces, or otherwise be handled behind the scenes.\\n\\nThis is certainly not the end of Cwtch development. We have big plans for the future including the long-anticipated Hybrid Groups\\nimplementation, a light client for restricted mobile operating systems, a return of the bulletin boards overlay, and much more.\\n\\nWe want to extend a huge thank you to everyone who helped Cwtch get this far. We could not have done it without you. If you\\nhave helped in any way and would like to be listed in the contributor credits [please reach out](https://docs.cwtch.im/blog/cwtch-stable-call-for-credits).\\n\\n## A Big Thank You\\n\\nOn a personal note, as Executive Director of Open Privacy, and lead of the Cwtch project. I want to take this opportunity to thank the Cwtch core team across time: Dan Ballard, Erinn Atwater and Marcia D\xedaz Agudelo - this work isn\u2019t glamorous, and doesn\u2019t pay well, \\nthere is no profit to be made in decentralizing power. A lack of funding means we don\'t all work together any more, but you all still contribute so much to this project.\\n\\nIt takes a special kind of person to be willing to spend a significant fraction of their lives devoted to working on something for the benefit of other people. \\nThank you for believing in this mission.\\n\\nI also want to say thank you to all the people who tested Cwtch over the years and provided invaluable feedback, bug reports and critique. \\nYou have made Cwtch what it is today, and I am sure you will be making it even better in the coming weeks, months, and years.\\n\\nLast, but certainly not least, I want to extend a big thank you to all of the supporters of Open Privacy around the world - without your donations\\n and continued enthusiasm for the work that we do, none of this would be possible.\\n\\n## Download Cwtch 1.13\\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic1.13.png)](/img/picnic1.13.png)\\n\\n
A screenshot of Cwtch 1.13
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Conversation Search** - Cwtch can now find messages based on their content.\\n - **Appear Offline Mode** - in this mode Cwtch does not launch a listening service for inbound contacts, and allows a profile to be more selective in the contacts they connect to.\\n - **Whonix Support** - new runtime flags make changes that allow Cwtch to [run on Whonix](https://docs.cwtch.im/docs/platforms/whonix)\\n - **Save History Global Setting** - by default Cwtch deletes all messages on shutdown unless a conversation is otherwise configured. This change allows a user to change this default behaviour.\\n- **Bug Fixes / Improvements:**\\n - Based on Flutter 3.13.4\\n - Updated Android Target to 33\\n - Profile Status Menu now has many more options, including offline status, edit profile and enabling/disabling profile\\n - File Sharing Bug Fixes\\n - Manage shared files now supports re-enabling older file shares\\n - Improvements towards [UI Reproducible Builds](https://docs.cwtch.im/blog/cwtch-ui-reproducible-builds-linux)\\n - Server Info now propagates to the UI consistently\\n - Prevent DBus Exceptions on platforms where it is unsupported\\n - Packaged Emoji Font\\n - Fixes to retry manager which have greater improved (re)connection efficacy\\n - Allow deleting server info in Manage Servers\\n- **Accessibility / UX:**\\n - Core translations for **Brazilian Portuguese**, **Danish** , **Dutch**, **French**, **German**, **Italian**, **Norwegian** , **Romanian** , **Russian**, **Polish**, **Slovak**, **Spanish**, **Swahili**, **Swedish**, **Turkish**, and **Welsh**\\n - Partial translations for **Korean** (37%), **Japanese** (27%), , **Luxembourgish** (20%), **Greek** (15%), **Uzbek** (10%), and **Portuguese** (5%)\\n - Font Scaling improvements on several screens\\n\\n## Reproducible Bindings\\n\\nCwtch 1.13 is based on libCwtch version `libCwtch-autobindings-2023-09-26-13-15-v0.0.10`. \\nThe [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source \\ncan be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.10](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.10)\\n\\n\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update-sept","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update-sept","source":"@site/blog/2023-09-06-cwtch-stable-roadmap-update.md","title":"September Cwtch Stable Roadmap Update","description":"Back in July we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","date":"2023-09-06T00:00:00.000Z","formattedDate":"September 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":3.265,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"September Cwtch Stable Roadmap Update","description":"Back in July we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","slug":"cwtch-stable-roadmap-update-sept","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch 1.13 Stable Release Candidate","permalink":"/blog/cwtch-1-13"},"nextItem":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","permalink":"/blog/cwtch-nightly-preview-whonix-save-history"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider \\nCwtch to be secure and usable. We have been working hard towards that goal over the last year.\\n\\nToday, as we approach the release of Cwtch Stable we would like to provide another update on the ongoing work, and the remaining blockers to certifying a Cwtch Stable release. We also have a new nightly to\\ntest out!\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stable Blocker and Timelines\\n\\nBack in January we set the ambitious goal of launching a Cwtch Stable in the Summer of 2023. We had planned to finish all of the work\\nprior to the end of August. The vast majority of that work has now been completed - what remains is captured in [Stable Blockers](https://git.openprivacy.ca/cwtch.im/cwtch-ui/projects/15) project which tracks the current state\\nof work that we have marked as being critical to a Cwtch Stable release.\\n\\nDespite there being a large number of remaining issues, many of the outstanding work is inter-related, relies on common implementations or\\n are tightly coupled together.\\n\\n In summary the final few areas of concern are:\\n\\n - The ability to delete or purge group conversation history. (For historical reasons storing group history was once considered necessary\\n but this is no longer the case. We plan on enabling this feature in the coming weeks)\\n - Appropriate handling of less common system configurations. Cwtch current emits non-fatal exceptions if certain services are not available\\n e.g. dbus. This is related to former 3rd party code for managing networking and notification.\\n - A final UI pass. We have designs for better ways to convey certain information and functionality. We would like to implement these\\n prior to a stable release.\\n\\nBecause of this, we have set a goal of labelling a Cwtch Stable Release Candidate by **30th September 2023**.\\n\\n## A New Nightly\\n\\nThere is a [new nightly version of Cwtch available for testing (2023-09-06-21-25-v1.12.0-33-g05b1)](https://build.openprivacy.ca/files/flwtch-2023-09-06-21-25-v1.12.0-33-g05b1/). This version contains a few bug fixes related to file share management,\\nin addition to a significant improvement in the connection management code.\\n\\nAdditionally, thanks to volunteer testers [and contributors](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/715) the installation instructions\\nand packaged configurations for Whonix have been much improved. See [running Cwtch on Whonix](https://docs.cwtch.im/docs/platforms/whonix) for more information.\\n\\n## Get Involved\\n\\nStaff and volunteer shortages have slightly extended our original estimates. In particular we are bottle-necked on review effort for new code. This is\\nwhy we would like to encourage people to test out the latest nightlies and report any bugs/issues/improvements.\\n\\nIn order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-preview-whonix-save-history","metadata":{"permalink":"/blog/cwtch-nightly-preview-whonix-save-history","source":"@site/blog/2023-08-18-whonix-nightly-preview.md","title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","description":"A new Cwtch Nightly contains a first cut of support for Whonix, Default Save History, Bug Fixes","date":"2023-08-18T00:00:00.000Z","formattedDate":"August 18, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"},{"label":"whonix","permalink":"/blog/tags/whonix"},{"label":"preview","permalink":"/blog/tags/preview"}],"readingTime":1.04,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","description":"A new Cwtch Nightly contains a first cut of support for Whonix, Default Save History, Bug Fixes","slug":"cwtch-nightly-preview-whonix-save-history","tags":["cwtch","cwtch-stable","nightly","whonix","preview"],"image":"/img/devlog10_small.png","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"September Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-sept"},"nextItem":{"title":"Nightly Preview: Conversation Search","permalink":"/blog/cwtch-nightly-preview-conversation-search"}},"content":"There is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing \\nis [2023-08-22-23-27-v1.12.0-25-ge019f](https://build.openprivacy.ca/files/flwtch-2023-08-22-23-27-v1.12.0-25-ge019f/).\\n\\nThis nightly contains a first cut of [support for Whonix](https://docs.cwtch.im/docs/platforms/whonix), a new global setting for managing how conversation\\nhistory is preserved, in addition to several bug fixes reported in the last nightly.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n![](/img/devlog10.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-preview-conversation-search","metadata":{"permalink":"/blog/cwtch-nightly-preview-conversation-search","source":"@site/blog/2023-08-03-nightly-preview-conversation-search.md","title":"Nightly Preview: Conversation Search","description":"A new Cwtch Nightly contains a first cut of Conversation Search.","date":"2023-08-03T00:00:00.000Z","formattedDate":"August 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"},{"label":"search","permalink":"/blog/tags/search"},{"label":"preview","permalink":"/blog/tags/preview"}],"readingTime":1.12,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Nightly Preview: Conversation Search","description":"A new Cwtch Nightly contains a first cut of Conversation Search.","slug":"cwtch-nightly-preview-conversation-search","tags":["cwtch","cwtch-stable","nightly","search","preview"],"image":"/img/devlog10_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Nightly Preview: Whonix Support, Default Save History, Bug Fixes","permalink":"/blog/cwtch-nightly-preview-whonix-save-history"},"nextItem":{"title":"Cwtch Call for Contributor Credits","permalink":"/blog/cwtch-stable-call-for-credits"}},"content":"There is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing \\nis [2023-08-02-20-24-v1.12.0-19-g75b7](https://build.openprivacy.ca/files/flwtch-2023-08-02-20-24-v1.12.0-19-g75b7/).\\n\\nThis nightly contains a first cut of Conversation Search, in addition to several bug fixes impacting effectiveness of the contact retry plugin when combined with a large contact list, and an unstable network\\nconnection. Finally we have made a few tweaks to the font scaling based on feedback.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n![](/img/search-nightly.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-call-for-credits","metadata":{"permalink":"/blog/cwtch-stable-call-for-credits","source":"@site/blog/2023-07-26-cwtch-stable-call-for-credits.md","title":"Cwtch Call for Contributor Credits","description":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed to Cwtch over the years have the optiont to be credited.","date":"2023-07-26T00:00:00.000Z","formattedDate":"July 26, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"contributors","permalink":"/blog/tags/contributors"},{"label":"community","permalink":"/blog/tags/community"}],"readingTime":2.91,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Call for Contributor Credits","description":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed to Cwtch over the years have the optiont to be credited.","slug":"cwtch-stable-call-for-credits","tags":["cwtch","cwtch-stable","contributors","community"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Nightly Preview: Conversation Search","permalink":"/blog/cwtch-nightly-preview-conversation-search"},"nextItem":{"title":"Progress Towards Reproducible UI Builds","permalink":"/blog/cwtch-ui-reproducible-builds-linux"}},"content":"As we journey ever closer to a Cwtch Stable candidate we would like to take this opportunity to ensure that those who have contributed\\nto Cwtch over the years have the option to be credited in some way.\\n\\nIf you have participated in the development process in any way e.g. protocol design, writing code, UI design, writing tests, testing release candidates, reporting issues,\\ntranslating the application or documentation, promoting metadata resistant applications or any other meaningful contribution to the Cwtch ecosystem we want\\nto offer you the option to have your name or handle credited in both the source code repository and the application itself.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## A History of Cwtch Contibutions and Anonmymity \\n\\nIn the early days of Cwtch we made the explicit decision to not include credits anywhere in the application, and to accept contributions\\nanonymously over a variety of channels, including Cwtch itself.\\n\\nDue to the nature of the application, and the privacy and metadata resistant space in general, we have always had a policy of\\nevaluating contributions based on merit, and not on identity. This approach means that, while we do have contributors whose identity\\nis known to us in some way, we have many who we know only by writing style, contribution type, or cwtch address.\\n\\nWe understand that many people much prefer it this way, and have no desire to have any identity linked to the Cwtch project. To those\\npeople we offer our deep gratitude. Thank you. You have made Cwtch what it is. (And if you ever want Cwtch Stickers - please let us know!)\\n\\nHowever, it would not be right of us to release Cwtch Stable without at least one final offer to all contributors. If you want\\nto be credited for your contributions to Cwtch then, please, reach out to us and let us know of a way to appropriately credit\\nyou. \\n\\n## Getting in Touch\\n\\nYou can ask for credit via email (team@cwtch.im), or via Cwtch (either publicly via the [Cwtch Release Candidate Testers groups](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group), or privately\\nin a message to Sarah: `icyt7rvdsdci42h6si2ibtwucdmjrlcb2ezkecuagtquiiflbkxf2cqd`).\\n\\nYou can also [open an issue](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/new).\\n\\nWhen asking, please provide a name or handle, and if desired, a rough description of the contribution (e.g. development, design, documentation, translating, funding). Anyone who does\\nnot provide a description will be grouped under a general thanks section.\\n\\nThis is an open offer. If at any time you change your mind and wish to have credit added (or removed) please let us know.\\n\\nI want to take another opporunity to say, regardless of whether you wish to be publicly credited for your work on Cwtch, **thank you**.\\n\\n## Stay up to date!\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-ui-reproducible-builds-linux","metadata":{"permalink":"/blog/cwtch-ui-reproducible-builds-linux","source":"@site/blog/2023-07-14-cwtch-ui-reproducible-builds.md","title":"Progress Towards Reproducible UI Builds","description":"","date":"2023-07-14T00:00:00.000Z","formattedDate":"July 14, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":4.16,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Progress Towards Reproducible UI Builds","description":"","slug":"cwtch-ui-reproducible-builds-linux","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Call for Contributor Credits","permalink":"/blog/cwtch-stable-call-for-credits"},"nextItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-june"}},"content":"Earlier this year we talked about the changes we have made to make [Cwtch Bindings Reproducible](https://docs.cwtch.im/blog/cwtch-bindings-reproducible).\\n\\nIn this devlog we will talk about how the Cwtch UI are currently built, the changes we have made to Cwtch UI to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible. \\n\\nThis will be useful to anyone who is looking to reproduce Cwtch UI builds specifically, and to anyone who wants to start implementing reproducible builds in their own project.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Building the Cwtch UI\\n\\nThe official Cwtch UI project uses the FLutter framework. The Cwtch UI deliberately tracks the `stable` channel.\\n\\nAll builds are conducted through the `flutter` tool e.g. `flutter build`. We inject two build flags as part of the official build `VERSION` and `COMMIT_DATE`:\\n\\n\\t\\tflutter build linux --dart-define BUILD_VER=`cat VERSION` --dart-define BUILD_DATE=`cat COMMIT_DATE`\\n\\nThese flags are defined to be identical to Cwtch Bindings. `VERSION` is the latest git tag: `git describe --tags --abbrev=1` and `COMMIT_DATE` is the date of the latest commit on the branch ``echo `git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M` > COMMIT_DATE``\\n\\nAll Cwtch UI builds also depend on two external dependencies not managed directly by the flutter project: Tor (implicit as part of the fetchTor scripts) and libCwtch (defined in `LIBCWTCH-GO.version`, and fetched via the fetch-libcwtch scripts).\\n\\nThe binaries are downloaded via their respective scripts prior to the build, and managed via a separate update process.\\n\\n## Changes we made for reproducible builds\\n\\nFor reproducible linux builds we had to modify the generated `linux/CMakeLists.txt` file to include the following compiler and linker flags:\\n\\n* `-fno-ident` - suppresses compiler identifying information from compiled artifacts. Without this small changes in compiler versions will result in different binaries.\\n* `--hash-style=gnu` - asserts a standard hashing scheme to use across all compiled artifacts. Without this compilers that have been compiled with different default schemes will produce different artifacts\\n* `--build-id=none` - suppresses build id generation. Without this each compiled artifact will have a section of effectively randomized data.\\n\\nWe have also defined a new [linker script](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/commit/3148a8e0642e51bc59d9eb00ca2b319a7097285a/elf_x86_64.x) that differs from the default by removing all `.comment` sections from object files. We do this because the linking process links in non-project artifacts like `crtbeginS.o` which, in most systems, us compiled with a `.comment` section (the default linking script already removes the `.note.gnu*` sections.\\n\\n### Tar Archives\\n\\nFinally, following the [guide at reproducible-builds.org](https://reproducible-builds.org/docs/archives/) we have defined standard metadata for the generated Tar archives to make them also reproducible.\\n\\n## Limitations and Next Steps\\n\\nThe above changes mean that official linux builds of the same commit will now result in identical artifacts.\\n\\nThe next step is to roll these changes into [repliqate](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) as we have done with our bindings builds.\\n\\nHowever, because Repliqate is based on Debian images and our official UI builds are based on an Ubuntu distribution the resulting archives differ by a single instruction at the start of a few sections - introduced because Ubuntu compiles and provides C Runtime (CRT) artifacts (e.g. `crti.o` with full branch protection enabled. On 64-bit systems this results in an `endcr64` instruction being inserted at the start of the `.init` and `.fini` sections, among others.\\n\\nIn order to allow people to fully repliqate Cwtch builds in an isolated environment like repliqate, as we do for Cwtch Bindings, it will be necessary to provide instructions for setting up a hardened image that can work the same way in repliqate.\\n\\n### Pinned Dependencies\\n\\nAdditionally, while our repliqate scripts pin several major dependencies like flutter and go, and the dependencies managed by these systems are locked to specific versions, there are still a few dependencies within the ecosystems that are not strictly pinned. \\n\\nThe major one is libc. Operating systems rarely make big changes to packaged libc versions for a specific distribution (typically because doing so in a non-breaking way would be a major undertaking). \\n\\nHowever this does mean that Cwtch reproduciblility is implicitly tied to operating system practices - this is something we would like to begin decoupling ourselves from going forward.\\n\\n## Stay up to date!\\n\\nWe expect to make additional progress on this in the coming weeks and months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update-june","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update-june","source":"@site/blog/2023-07-05-cwtch-stable-roadmap-update.md","title":"Cwtch Stable Roadmap Update","description":"Back in March we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","date":"2023-07-05T00:00:00.000Z","formattedDate":"July 5, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":5.26,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable Roadmap Update","description":"Back in March we provided an update on several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we provide a new update on those goals","slug":"cwtch-stable-roadmap-update-june","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Progress Towards Reproducible UI Builds","permalink":"/blog/cwtch-ui-reproducible-builds-linux"},"nextItem":{"title":"Cwtch Beta 1.12","permalink":"/blog/cwtch-nightly-1-12"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable. We have been working hard towards that goal over the last few months.\\n\\nThis post [revisits the Cwtch Stable roadmap update](/blog/cwtch-stable-roadmap-update) we provided back in March, and provides an overview of the next steps on our journey towards Cwtch Stable.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Update on the Cwtch Stable Roadmap\\n\\nBack in March we extended and updated several goals from [our January roadmap](https://docs.cwtch.im/blog/path-to-cwtch-stable) that we would have to hit on our way to Cwtch Stable, and the timelines for achieving them. Now that we have reached target date of many of these goals, we can look back and see how work is progressing.\\n\\n(\u2705 means complete, \ud83d\udfe1 means in-progress, \ud83d\udd52 reprioritized)\\n\\n- By **30th April 2023** the Cwtch team will have written the remaining outstanding documentation from the January roadmap including:\\n - A Cwtch Release Process Document \u2705 - [Release Process](https://docs.cwtch.im/developing/release/#official-releases)\\n - A Cwtch Packaging Document \u2705 - [Packaging Documentation](https://docs.cwtch.im/developing/release/)\\n - Completion of documentation of existing Cwtch features, including relevant screenshots. \ud83d\udfe1 - new features are documented to the standards outlined in new [documentation style guide](/docs/contribute/documentation), and many older feature documentation features have been updated to that standard. Work is ongoing to refine the standard.\\n- By **30th April 2023** the Cwtch team will have also released developer-centric documentation including:\\n - A guide to building Cwtch-apps using official libraries \u2705 - [Building a Cwtch App](https://docs.cwtch.im/developing/category/building-a-cwtch-app)\\n - Automatically generated API documentation for libCwtch \ud83d\udd52 - this effort has been delayed pending other higher priority work. \\n- By **30th June 2023** the Cwtch team will have released new Cwtch Beta releases (1.12+) featuring:\\n - An implementation of [Conversation Search](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/129) \ud83d\udfe1 - currently in [active development](https://git.openprivacy.ca/cwtch.im/cwtch/pulls/518)\\n - [Profile statuses](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/27) and other associated information \u2705 - released in [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12)\\n - An update to the network handling code to allow for [better Protocol Engine management](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/593) \ud83d\udfe1\ud83d\udd52 - new Network Management code was released in [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12). We now believe these changes will be complete in Cwtch Beta 1.13.\\n- By **31st July 2023** the Cwtch team will have completed several infrastructure upgrades including:\\n - Extended reproducible builds to cover the Cwtch UI, or document where the blockers to achieving this exist. \ud83d\udfe1 - we have recently made a few updates to [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) to support this work, and expect to begin in-depth examination of build artifacts in the next couple of weeks.\\n - Integration of automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team \ud83d\udd52 - after some initial explorations into new Go fuzzing tools we reached the conclusion that it would be better to replace this effort with other assurance work (see below).\\n - New testing environments for F-droid, Whonix, Raspberry Pi and other [partially supported systems](/docs/getting-started/supported_platforms) \ud83d\udfe1 - we have already launched an environment for testing [Tails](/docs/platforms/tails). Other platforms are underway.\\n- By **31st August 2023** the Cwtch team will have a released Cwtch Stable Release Candidate:\\n - At this point we expect that the Cwtch application and existing documentation will be robust and complete enough to be labeled as stable.\\n - Along with this label comes a higher standard for how we consider all aspects of Cwtch development. The work we have done up to this point reflects a much stronger development pipeline, and an ongoing commitment to security.\\n - **This does not mark an end to Cwtch development**, or new Cwtch features. But it does denote the point at which we consider Cwtch to be appropriate for wider use.\\n\\n\\n## Next Steps, Refinements, Additional Work\\n\\nAs you may have noticed above we have reprioritized some work after initial investigations forced us to reevaluate the expected cost/benefit trade-off. This has allowed us to move up timelines for tasks e.g. reproducible UI builds and testing environments. \\n\\nOther work has been reprioritized due to developer availability. Documentation work in particular has not progressed as fast as we would like.\\n\\nHowever, [Cwtch Beta 1.12](https://docs.cwtch.im/blog/cwtch-nightly-1-12) featured many new features alongside improved performance, more robust packaging, and several fixes impacting experimental features like file sharing.\\n\\nThe work that we have done on reproducible and automatically generated bindings has considerably reduced the maintenance burden associated with updates and adding new features, and has allowed us to also tackle long standing issues related to Tor process managements and Cwtch startup.\\n\\nWe are still on track for releasing a Cwtch Stable release candidate in August 2023, with an official Cwtch Stable release expected shortly afterwards.\\n\\nThis is not all we have planned for the upcoming months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Get Involved\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-1-12","metadata":{"permalink":"/blog/cwtch-nightly-1-12","source":"@site/blog/2023-06-16-cwtch-1.12.md","title":"Cwtch Beta 1.12","description":"Cwtch Beta 1.12 is now available for download","date":"2023-06-16T00:00:00.000Z","formattedDate":"June 16, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":2.455,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Beta 1.12","description":"Cwtch Beta 1.12 is now available for download","slug":"cwtch-nightly-1-12","tags":["cwtch","cwtch-stable","release"],"image":"/img/devlog1_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update-june"},"nextItem":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","permalink":"/blog/cwtch-nightly-v.11-74"}},"content":"[Cwtch 1.12 is now available for download](https://cwtch.im/download)!\\n\\nCwtch 1.12 is the culmination of the last few months of effort by the Cwtch team, and includes many foundational changes that pave the way for [Cwtch Stable](/blog/path-to-cwtch-stable) including new features like [profile attributes](https://docs.cwtch.im/docs/profiles/profile-info), support for new platforms like [Tails](https://docs.cwtch.im/docs/platforms/tails), and multiple improvements to performance and stability.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic1.12.png)](/img/picnic1.12.png)\\n\\n
A screenshot of Cwtch 1.12
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Profile Attributes** - profiles can now be augmented with [additional public information](https://docs.cwtch.im/docs/profiles/profile-info)\\n - **Availability Status** - you can now notify contacts that you [are **away** or **busy**](https://docs.cwtch.im/docs/profiles/availability-status)\\n - **Five New Supported Localizations**: **Japanese**, **Korean**, **Slovak**, **Swahili** and **Swedish**\\n - **Support for Tails** - adds an [OnionGrater](https://docs.cwtch.im/docs/platforms/tails) configuration and a new `CWTCH_TAILS` environment variable that enables special Tor behaviour.\\n- **Bug Fixes / Improvements:**\\n - Based on Flutter 3.10\\n - Inter is now the main UI font\\n - New Font Scaling setting\\n - New Network Management code to better manage Tor on unstable networks\\n - File Sharing Experiment Fixes\\n \\t- Fix performance issues for file bubble\\n \\t- Allow restarting of file shares that have timed out\\n \\t- Fix NPE in FileBubble caused by deleting the underlying file\\n \\t- Move from RetVal to UpdateConversationAttributes to minimze UI thread issues\\n - Updates to Linux install scripts to support more distributions\\n - Add a Retry Peer connection to prioritize connection attempts for certain conversations\\n - Updates to `_FlDartProject` to allow custom setting of Flutter asset paths\\n- **Accessibility / UX:**\\n - Full translations for **Brazilian Portuguese**, **Dutch**, **French**, **German**, **Italian**, **Russian**, **Polish**, **Slovak**, **Spanish**, **Swahili**, **Swedish**, **Turkish**, and **Welsh**\\n - Core translations for **Danish** (75%), **Norwegian** (76%), and **Romanian** (75%)\\n - Partial translations for **Japanese** (29%), **Korean** (23%), **Luxembourgish** (22%), **Greek** (16%), and **Portuguese** (6%)\\n\\n## Reproducible Bindings\\n\\nCwtch 1.12 is based on libCwtch version `libCwtch-autobindings-2023-06-13-10-50-v0.0.5`. The [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source can be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.5)\\n\\n## Download the New Version \\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-v.11-74","metadata":{"permalink":"/blog/cwtch-nightly-v.11-74","source":"@site/blog/2023-06-07-new-nightly.md","title":"New Cwtch Nightly (v1.11.0-74-g0406)","description":"In this development log we take a look at the new Cwtch Nightly","date":"2023-06-07T00:00:00.000Z","formattedDate":"June 7, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"}],"readingTime":1.845,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","description":"In this development log we take a look at the new Cwtch Nightly","slug":"cwtch-nightly-v.11-74","tags":["cwtch","cwtch-stable","nightly"],"image":"/img/devlog10_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Beta 1.12","permalink":"/blog/cwtch-nightly-1-12"},"nextItem":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","permalink":"/blog/cwtch-developer-documentation"}},"content":"We are getting close to a 1.12 release. This week we are drawing attention to the latest Cwtch Nightly (2023-06-05-17-36-v1.11.0-74-g0406) that is now available for wider testing.\\n\\nAs a reminder, the Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like ours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n![](/img/devlog10.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### New Nightly\\n\\nThere is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing is [2023-06-05-17-36-v1.11.0-74-g0406](https://build.openprivacy.ca/files/flwtch-2023-06-05-17-36-v1.11.0-74-g0406/).\\n\\nThis version has a large number of improvements and bug fixes including:\\n\\n* A new Font Scaling setting\\n* Several networking and connection management improvements including automatic detection and response to network changes, and several bug fixes that impacted time-to-connection after a resetting Tor.\\n* Updated UI font styles\\n* Dependency updates, including a new base of Flutter 3.10.\\n* A fix for stuck file downloading notifications on Android\\n* A fix for missing profile images in certain edge cases on Android\\n* Japanese, Swedish, and Swahili translation options\\n* A new retry peer connection button for prompting Cwtch to prioritize specific connections\\n* [Tails support](/docs/platforms/tails)\\n\\nIn addition, this nightly also includes a number of performance improvements that should fix reported rendering issues on less powerful devices.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-developer-documentation","metadata":{"permalink":"/blog/cwtch-developer-documentation","source":"@site/blog/2023-04-28-developer-docs.md","title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","description":"In this development log we take a look at the new Cwtch developer docs!","date":"2023-04-28T00:00:00.000Z","formattedDate":"April 28, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"developer-documentation","permalink":"/blog/tags/developer-documentation"}],"readingTime":2.595,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","description":"In this development log we take a look at the new Cwtch developer docs!","slug":"cwtch-developer-documentation","tags":["cwtch","cwtch-stable","developer-documentation"],"image":"/img/devlog9_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"New Cwtch Nightly (v1.11.0-74-g0406)","permalink":"/blog/cwtch-nightly-v.11-74"},"nextItem":{"title":"Availability Status and Profile Attributes","permalink":"/blog/availability-status-profile-attributes"}},"content":"One of the larger remaining goals outlined in our [Cwtch Stable roadmap update](/blog/cwtch-stable-roadmap-update) is comprehensive developer documentation. We have recently spent some time writing the foundation for these documents. \\n\\nIn this devlog we will introduce some of them, and outline the next steps. We also have a new nightly Cwtch release available for testing!\\n\\nWe are very interested in getting feedback on these documents, and we encourage anyone who is excited to build a Cwtch Bot, or even an alternative UI, to read them over and reach out to us with comments, questions, and suggestions!\\n\\nAs a reminder, the Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like ours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n![](/img/devlog9.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Cwtch Development Handbook\\n\\nWe have created a new documentation section, [the developers handbook](/developing/intro). This new section is targeted towards to people working on Cwtch projects (e.g. the official Cwtch library or the Cwtch UI), as well as people who want to build new Cwtch applications (e.g. chat bots or custom clients).\\n\\n### Release and Packaging Process\\n\\nThe new handbook features a breakdown of [Cwtch release processes](/developing/release) - describing what, and how, build artifacts are created; the difference between nightly and official builds; how the official release process works; and how reproducible build scripts are created.\\n\\n### Cwtch Application Development and Cwtchbot v0.1.0!\\n\\nFor the first time ever we now have [comprehensive documentation on how to build a Cwtch Application](/developing/category/building-a-cwtch-app). This section of the development handbook covers everything from [choosing a Cwtch library](/developing/building-a-cwtch-app/intro#choosing-a-cwtch-library), to [building your first application](/developing/building-a-cwtch-app/building-an-echobot).\\n\\nTogether with this new documentation we have also [released version 0.1 of the Cwtchbot framework](https://git.openprivacy.ca/sarah/cwtchbot), updating calls to use the [new Cwtch Stable API](/blog/cwtch-stable-api-design).\\n\\n### New Nightly\\n\\nThere is a [new Nightly build](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. The latest nightly we recommend testing is [2023-04-26-20-57-v1.11.0-33-gb4371](https://build.openprivacy.ca/files/flwtch-2023-04-26-20-57-v1.11.0-33-gb4371/).\\n\\nThis version has a number of fixes and updates to the file sharing and image previews/profile pictures experiment, and an update to the [in-development Tails support](/docs/platforms/tails). \\n\\nIn addition, this nightly also includes a number of performance improvements that should fix reported rendering issues on less powerful devices.\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"availability-status-profile-attributes","metadata":{"permalink":"/blog/availability-status-profile-attributes","source":"@site/blog/2023-04-06-availability-and-profile-attributes.md","title":"Availability Status and Profile Attributes","description":"Two new Cwtch features are now available to test in nightly: Availability Status and Profile Information.","date":"2023-04-06T00:00:00.000Z","formattedDate":"April 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"nightly","permalink":"/blog/tags/nightly"}],"readingTime":1.445,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Availability Status and Profile Attributes","description":"Two new Cwtch features are now available to test in nightly: Availability Status and Profile Information.","slug":"availability-status-profile-attributes","tags":["cwtch","cwtch-stable","nightly"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Developer Documentation, Cwtchbot v0.1.0 and New Nightly.","permalink":"/blog/cwtch-developer-documentation"},"nextItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update"}},"content":"Two new Cwtch features are now available to test in nightly: [Availability Status](/docs/profiles/availability-status) and [Profile Information](/docs/profiles/profile-info).\\n\\nAdditionally, we have also published draft guidance on [running Cwtch on Tails](/docs/platforms/tails) that we would like volunteers to test and report back on.\\n \\nThe Open Privacy Research Society have [also announced they are want to raise $60,000 in 2023](https://openprivacy.ca/discreet-log/38-march-2023/) to help move forward projects like Cwtch. Please help support projects like\\nours with a [one-off donations](https://openprivacy.ca/donate) or [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\n\x3c!--truncate--\x3e\\n\\n\\n## Availability Status\\n\\nNew in this nightly is the ability to notify your conversations that you are \\"Away\\" or \\"Busy\\".\\n\\n
\\n\\n[![](/img/profiles/status-tooltip-busy-set.png)](/img/profiles/status-tooltip-busy-set.png)\\n\\n
\\n
\\n\\nRead more: [Availability Status](/docs/profiles/availability-status)\\n\\n## Profile Attributes\\n\\nAlso new is the ability to augment your profile with a few small pieces of **public** information.\\n\\n
\\n\\n[![](/img/profiles/attributes-set.png)](/img/profiles/attributes-set.png)\\n\\n
\\n
\\n\\nRead more: [Profile Information](/docs/profiles/profile-info)\\n \\n## Downloading the Nightly\\n\\n[Nightly builds](https://docs.cwtch.im/docs/contribute/testing#cwtch-nightlies) are available from our build server. Download links for **2023-04-05-18-28-v1.11.0-7-g0290** are available below.\\n\\n* Windows: [https://build.openprivacy.ca/files/flwtch-win-2023-04-05-18-28-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-win-2023-04-05-18-28-v1.11.0-7-g0290/)\\n* Linux: [https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/)\\n* Mac: [https://build.openprivacy.ca/files/flwtch-macos-2023-04-05-14-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-macos-2023-04-05-14-27-v1.11.0-7-g0290/)\\n* Android: [https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/](https://build.openprivacy.ca/files/flwtch-2023-04-05-18-27-v1.11.0-7-g0290/)\\n\\nPlease see the contribution documentation for advice on [submitting feedback](/docs/contribute/testing#submitting-feedback)\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-roadmap-update","metadata":{"permalink":"/blog/cwtch-stable-roadmap-update","source":"@site/blog/2023-03-31-cwtch-stable-roadmap-update.md","title":"Cwtch Stable Roadmap Update","description":"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more","date":"2023-03-31T00:00:00.000Z","formattedDate":"March 31, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":5.61,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable Roadmap Update","description":"Back in january we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines to hit them. In this post we revisit those and announce some more","slug":"cwtch-stable-roadmap-update","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Availability Status and Profile Attributes","permalink":"/blog/availability-status-profile-attributes"},"nextItem":{"title":"Cwtch Beta 1.11","permalink":"/blog/cwtch-nightly-1-11"}},"content":"The next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable. We have been working hard towards that goal over the last few months.\\n\\nThis post [revisits the Cwtch Stable roadmap](/blog/path-to-cwtch-stable) we introduced at the start of the year, and provides an overview of the next steps on our journey towards Cwtch Stable.\\n\\n![](/img/devlog1.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Update on the January Roadmap\\n\\nBack in January we outlined several goals that we would have to hit on our way to Cwtch Stable, and the timelines for achieving them. Now that we have reached target date of the last of these goals, we can look back and see how we did:\\n\\n(\u2705 means complete, \ud83d\udfe1 means in-progress, \u274c not started.)\\n\\n- By **1st February 2023**, the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases). \u2705\\n- By **1st February 2023**, the Cwtch team will have [finalized a feature set that defines Cwtch Stable](/blog/cwtch-stable-api-design) and established a timeline for including these features in upcoming Cwtch Beta releases. \u2705\\n- By **1st February 2023**, the Cwtch team will have expanded the Cwtch Documentation website to include a section for:\\n - [Security and Design Documents](/security/intro) \u2705\\n - Infrastructure and [Support](/docs/getting-started/supported_platforms) \ud83d\udfe1\\n - in addition to a new development blog. \u2705\\n- By **31st March 2023**, the Cwtch team will have created:\\n - a [style guide for documentation](/docs/contribute/documentation), and \u2705\\n - have used it to ensure that all Cwtch features have consistent documentation available, \ud83d\udfe1\\n - with at least one screenshot (where applicable). \ud83d\udfe1\\n- By **31st March 2023** the Cwtch team will have published: \\n - a Cwtch [Interface Specification Document](/blog/cwtch-stable-api-design) \u2705\\n - a Cwtch Release Process Document \ud83d\udfe1\\n - a Cwtch [Support Plan document](/blog/cwtch-platform-support) \u2705\\n - a Cwtch Packaging Document \ud83d\udfe1\\n - a document describing the [Reproducible Builds Process](/blog/cwtch-bindings-reproducible) \u2705\\n - These documents will be available on the newly expanded Cwtch Documentation website \ud83d\udfe1\\n- By **31st March 2023** the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository. \u2705\\n- By **31st March 2023** the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team \u274c\\n- By **31st March 2023** the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable \u2705 (this post!)\\n\\nWhile we didn\'t hit all of our goals, we did make progress on nearly all of them, and in addition also made progress in a few other key areas:\\n\\n* [Cwtch Autobindings](/blog/autobindings) with [compile-time optional experiments](/blog/autobindings-ii)\\n* [Cwtch 1.11](/blog/cwtch-nightly-1-11) - with support for reproducible bindings, two new localizations (Slovak and Korean), in addition to a myriad of bug fixes and performance improvements.\\n* [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) - a tool for testing and confirming reproducible builds processes based on Qemu, and a Debian Cloud image.\\n\\n## A Timeline for Cwtch Stable\\n\\nNow for the big news, we plan on releasing a candidate Cwtch Stable release during **Summer 2023**. Here is our plan for getting there:\\n\\n- By **30th April 2023** the Cwtch team will have written the remaining outstanding documentation from the January roadmap including:\\n - A Cwtch Release Process Document\\n - A Cwtch Packaging Document\\n - Completion of documentation of existing Cwtch features, including relevant screenshots.\\n- By **30th April 2023** the Cwtch team will have also released developer-centric documentation including:\\n - A guide to building Cwtch-apps using official libraries\\n - Automatically generated API documentation for libCwtch\\n- By **30th June 2023** the Cwtch team will have released new Cwtch Beta releases (1.12+) featuring:\\n - An implementation of [Conversation Search](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/129)\\n - [Profile statuses](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/27) and other associated information\\n - An update to the network handling code to allow for [better Protocol Engine management](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/593)\\n- By **31st July 2023** the Cwtch team will have completed several infrastructure upgrades including:\\n - Extended reproducible builds to cover the Cwtch UI, or document where the blockers to achieving this exist.\\n - Integration of automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team\\n - New testing environments for F-droid, Whonix, Raspberry Pi and other [partially supported systems](/docs/getting-started/supported_platforms)\\n- By **31st August 2023** the Cwtch team will have a released Cwtch Stable Release Candidate:\\n - At this point we expect that the Cwtch application and existing documentation will be robust and complete enough to be labelled as stable.\\n - Along with this label comes a higher standard for how we consider all aspects of Cwtch development. The work we have done up to this point reflects a much stronger development pipeline, and an ongoing commitment to security.\\n - **This does not mark an end to Cwtch development**, or new Cwtch features. But it does denote the point at which we consider Cwtch to be appropriate for wider use.\\n\\nThis is not all we have planned for the upcoming months. Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Get Involved\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-nightly-1-11","metadata":{"permalink":"/blog/cwtch-nightly-1-11","source":"@site/blog/2023-03-29-cwtch-1.11.md","title":"Cwtch Beta 1.11","description":"Cwtch Beta 1.11 is now available for download","date":"2023-03-29T00:00:00.000Z","formattedDate":"March 29, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"release","permalink":"/blog/tags/release"}],"readingTime":2.365,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Beta 1.11","description":"Cwtch Beta 1.11 is now available for download","slug":"cwtch-nightly-1-11","tags":["cwtch","cwtch-stable","release"],"image":"/img/devlog12_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable Roadmap Update","permalink":"/blog/cwtch-stable-roadmap-update"},"nextItem":{"title":"Updates to Cwtch Documentation","permalink":"/blog/cwtch-documentation"}},"content":"[Cwtch 1.11 is now available for download](https://cwtch.im/download)!\\n\\nCwtch 1.11 is the culmination of the last few months of effort by the Cwtch team, and includes many foundational changes that pave the way for [Cwtch Stable](/blog/path-to-cwtch-stable) including new [reproducible](https://docs.cwtch.im/blog/cwtch-bindings-reproducible) and [automatically generated](https://docs.cwtch.im/blog/autobindings) bindings, as well as support for two new languages (Slovak and Korean), in addition to several performance improvements and bug fixes.\\n\\n![](/img/devlog12.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## In This Release\\n\\n
\\n\\n[![](/img/picnic.png)](/img/picnic.png)\\n\\n
A screenshot of Cwtch 1.11
\\n
\\n\\nA special thanks to the [amazing volunteer translators](https://docs.cwtch.im/docs/contribute/translate) and [testers](https://docs.cwtch.im/docs/contribute/testing) who made this release possible.\\n\\n- **New Features:**\\n - **Based on new Reproducible Cwtch Stable Autobuilds** - this is the first release of cwtch based on [reproducible Cwtch bindings](https://docs.cwtch.im/blog/cwtch-bindings-reproducible) in addition to our new [automatically generated](https://docs.cwtch.im/blog/autobindings)\\n - **Two New Supported Localizations**: **Slovak** and **Korean**\\n- **Bug Fixes / Improvements:**\\n - When preserving a message draft, quoted messages are now also saved\\n - Layout issues caused by pathological unicode are now prevented\\n - Improved performance of message row rendering\\n - Clickable Links: Links in replies are now selectable\\n - Clickable Links: Fixed error when highlighting certain URIs \\n - File Downloading: Fixes for file downloading and exporting on 32bit Android devices\\n - Server Hosting: Fixes for several layout issues\\n - Build pipeline now runs automated UI tests\\n - Fix issues caused by scrollbar controller overriding\\n - Initial support for the Blodeuwedd Assistant (currently compile-time disabled)\\n - Cwtch Library:\\n - [New Stable Cwtch Peer API](/blog/cwtch-stable-api-design)\\n - Ported File Downloading and Image Previews experiments into Cwtch\\n- **Accessibility / UX:**\\n - Full translations for **Brazilian Portuguese**, **Dutch**, **French**, **German**, **Italian**, **Russian**, **Polish**, **Spanish**, **Turkish**, and **Welsh**\\n - Core translations for **Danish** (75%), **Norwegian** (76%), and **Romanian** (75%)\\n - Partial translations for **Luxembourgish** (22%), **Greek** (16%), and **Portuguese** (6%)\\n\\n\\n\\n## Reproducible Bindings\\n\\nCwtch 1.11 is based on libCwtch version `2023-03-16-15-07-v0.0.3-1-g50c853a`. The [repliqate scripts](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#introducing-repliqate) to reproduce these bindings from source can be found at [https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.3-1-g50c853a](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.3-1-g50c853a)\\n\\n## Download the New Version \\n\\nYou can download Cwtch from [https://cwtch.im/download](https://cwtch.im/download).\\n\\nSubscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\nAlternatively we also provide a [releases-only RSS feed](https://cwtch.im/releases/index.xml).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-documentation","metadata":{"permalink":"/blog/cwtch-documentation","source":"@site/blog/2023-03-10-cwtch-documentation.md","title":"Updates to Cwtch Documentation","description":" In this development log we will highlight some of the major documentation updates over the last few weeks.","date":"2023-03-10T00:00:00.000Z","formattedDate":"March 10, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"documentation","permalink":"/blog/tags/documentation"},{"label":"security-handbook","permalink":"/blog/tags/security-handbook"}],"readingTime":2.57,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Updates to Cwtch Documentation","description":" In this development log we will highlight some of the major documentation updates over the last few weeks.","slug":"cwtch-documentation","tags":["cwtch","cwtch-stable","documentation","security-handbook"],"image":"/img/devlog9_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Beta 1.11","permalink":"/blog/cwtch-nightly-1-11"},"nextItem":{"title":"Compile-time Optional Application Experiments (Autobindings)","permalink":"/blog/autobindings-ii"}},"content":"One of the main streams of work in the lead up to Cwtch Stable has been improving all aspects of Cwtch Documentation. In this development log we will highlight some of the major updates over the last few weeks.\\n\\n![](/img/devlog9.png)\\n \\n\x3c!--truncate--\x3e\\n\\n## Cwtch Secure Development Handbook\\n \\nOne of the earliest compendiums of Cwtch documentation was the Cwtch Secure Development Handbook. This handbook provided an overview of the various parts of the Cwtch ecosystem, the known risks, and any existing mitigations. The handbook was designed to serve as a guide to developers who were building or extending Cwtch, and over the years it also served as a permanent home for documenting long-standing design decisions.\\n\\nWe have [now ported the the handbook to this documentation site](/security/intro), along with updating some of the contents. Over the next few months we will be expanding this section to include new sections on fuzzing, plugins, and client implementation. \\n\\n## Volunteer Development\\n\\nWe have noticed an uptick in the number of people reaching out interested in contributing to Cwtch development. In order to help people get acclimated to our development flow we have created a new section on the main documentation site called [Developing Cwtch](/docs/contribute/developing) - there you will find a collection of useful links and information about how to get started with Cwtch development, what libraries and tools we use, how pull requests are validated and verified, and how to choose an issue to work on.\\n\\nWe also also updated our guides on [Translating Cwtch](/docs/contribute/translate) and [Testing Cwtch](/docs/contribute/testing).\\n\\nIf you are interested in getting started with Cwtch development then please check it out, and feel free to reach out to `team@cwtch.im` (or open an issue) with any questions. All types of contributions [are eligible for stickers](/docs/contribute/stickers).\\n\\n## Next Steps\\n\\nWe still have more work to do on the documentation front:\\n\\n* Ensuring all pages [implement the new documentation style guide](/docs/contribute/documentation), and include appropriate screenshots and descriptions.\\n* Expanding the security handbook to provide information on [reproducible builds](/blog/cwtch-bindings-reproducible), [the new Cwtch Stable API](/blog/cwtch-stable-api-design) and upcoming improvements around fuzz testing.\\n* Creating new documentation sections on the [libCwtch autobindings API](/blog/autobindings) and building applications on top of Cwtch.\\n\\nAs these changes are made, and these goals met we will be posting about them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all aspects of Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"autobindings-ii","metadata":{"permalink":"/blog/autobindings-ii","source":"@site/blog/2023-03-03-autobindings-optional-experiments.md","title":"Compile-time Optional Application Experiments (Autobindings)","description":"In this development log we document how we added compile-time optional application-level experiments to Cwtch autobindings.","date":"2023-03-03T00:00:00.000Z","formattedDate":"March 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"autobindings","permalink":"/blog/tags/autobindings"},{"label":"libcwtch","permalink":"/blog/tags/libcwtch"}],"readingTime":4.655,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Compile-time Optional Application Experiments (Autobindings)","description":"In this development log we document how we added compile-time optional application-level experiments to Cwtch autobindings.","slug":"autobindings-ii","tags":["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],"image":"/img/devlog8_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Updates to Cwtch Documentation","permalink":"/blog/cwtch-documentation"},"nextItem":{"title":"Autogenerating Cwtch Bindings","permalink":"/blog/autobindings"}},"content":"[Last time we looked at autobindings](https://docs.cwtch.im/blog/autobindings) we mentioned that one of the next steps was introducing support for **[Application-level experiments](https://docs.cwtch.im/blog/cwtch-stable-api-design#application-experiments)**. In this development log we will explore what application-level experiments are (technically), and how we added (optional) autobindings support for them.\\n\\n![](/img/devlog8.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## The Structure of an Application Experiment\\n\\nAn application-level experiment consists of:\\n\\n1. A set of top-level APIs, e.g. `CreateServer`, `LoadServer`, `DeleteServer` - these are the APIs that we want to expose to calling applications.\\n2. An encapsulating structure for the set of APIs, e.g. `ServersFunctionality` - it is much easy to manage a cohesive set of functionality if it is wrapped up in a single entity.\\n3. A global variable that exists at the top level of libCwtch, e.g. `var serverExperiment *servers.ServersFunctionality servers` - our single pointer to the underlying functionality.\\n4. A set of management-related APIs, e.g. `Init`, `UpdateSettings`, `OnACNEvent` - in the case of the server hosting experiment we need to perform specific actions when we start up (e.g. loading unencrypted hosted servers), and when settings are\\nchanged (e.g. if the server hosting experiment is disabled we need to tear down all active servers).\\n5. Management code within `_startCwtch` and `_reconnectCwtch` that calls the management APIs on the global variable.\\n\\nFrom a code generation perspective we already have most of the functionality is place to support (1) - the one major difference being that we need to wrap function calls on the global variable associated with the experiment, instead\\nof on `application` or a specific `profile`.\\n\\nMost of the effort required to support optional experiments was focused on optionally weaving experiment management code within the template.\\n\\n### New Required Management APIs\\n\\nTo achieve this weaving, we now require application-level experiments to implement an `EventHandlerInterface` interface and expose itself via an\\ninitialize constructor `Init(acn, appDir) -> EventHandlerInterface`, and `Enable(app, acn)`.\\n\\nFor now this interface is rather minimal, and has been mapped almost exactly to how the server hosting experiment already worked. If, or when, a new application experiment is required we will likely revisit this interface.\\n\\nWe can then generate, and optionally include blocks of code like:\\n\\n\\t\\t = .Init(&globalACN, appDir)\\n\\t\\teventHandler.AddModule()\\n\\t\\t.Enable(application, &globalACN)\\n\\nand place them at specific points in the code. `EventHandler` has also been extended to maintain a collection of `modules` so that it can\\npass on interesting events.\\n\\n### Adding Support for Application Experiments in the Spec File\\n\\nWe have introduced a new `!` operator which can be used to gate APIs behind a configured experiment. Along with a new\\ntemplating option `exp` which will call the function on the configured experiment, and `global` to allow the setting up\\nof a global functionality within the library.\\n\\n\\t\\t# Server Hosting Experiment\\n\\t\\t!serverExperiment import \\"git.openprivacy.ca/cwtch.im/cwtch-autobindings/experiments/servers\\"\\n\\t\\t!serverExperiment global serverExperiment *servers.ServersFunctionality servers\\n\\t\\t!serverExperiment exp CreateServer application password string:description bool:autostart\\n\\t\\t!serverExperiment exp SetServerAttribute application string:handle string:key string:val\\n\\t\\t!serverExperiment exp LoadServers application acn password\\n\\t\\t!serverExperiment exp LaunchServers application acn\\n\\t\\t!serverExperiment exp LaunchServer application string:handle\\n\\t\\t!serverExperiment exp StopServer application string:handle\\n\\t\\t!serverExperiment exp StopServers application\\n\\t\\t!serverExperiment exp DestroyServers\\n\\t\\t!serverExperiment exp DeleteServer application string:handle password\\n\\n### Generation-Time Inclusion\\n\\n Without any arguments provided `generate-bindings` will not generate code for any experiments.\\n\\n In order to determine what experimental code to generate, `generate-bindings` now interprets arguments as enabled compile time experiments, e.g. `generate-bindings serverExperiment` will turn on\\n generation of server hosting code, per the spec file above.\\n\\n### Cwtch UI Integration\\n\\nThe UI, and other downstream applications, can now check for support for server hosting by simply checking if the loaded library provides the expected symbols, e.g. `c_LoadServers` - if it doesn\'t then the UI is safe to assume the\\nfeature is not available.\\n\\n
\\n\\n![](/img/dev9-host-disabled.png)\\n\\n
A screenshot of the Cwtch UI Settings Pane demonstrating how the Server Hosting experiment option looks when the UI is pointed to a libCwtch compiled without server hosting support.
\\n
\\n\\n## Nightlies & Next Steps\\n\\nWe are now publishing [nightlies](https://build.openprivacy.ca/files/libCwtch-autobindings-v0.0.2/) of autobinding derived libCwtch-go, along with [Repliqate scripts](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-autobindings-v0.0.2) for reproducibility.\\n\\nWith application experiments supported, this phase of autobindings comes to a close. The immediate next steps involve extensive testing and release candidates proving out the new bindings to ensure that no bugs have been introduced\\nin the migration from libCwtch-go. These candidates will form the basis for Cwtch Beta 1.11.\\n\\nHowever, there is still more work to do, and we expect to make progress on a few areas over the next few months, including:\\n\\n* **Dart Library generation**: since we now have a formal description of the bindings interface, we can move ahead with also autogenerating the [Dart side](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/lib/cwtch) of the bindings interface, giving a boost to UI integration of new features, and allowing us to generate tailored versions of the UI interface, e.g. one compiled without experiment support. We can also extend the same logic to other downstream interfaces, e.g. [libcwtch-rs](https://git.openprivacy.ca/cwtch.im/libcwtch-rs).\\n * **Documentation generation**: as another benefit of a formal description of the bindings interface, we can easily generate documentation compatible with [docs.cwtch.im](https://cwtch.im).\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"autobindings","metadata":{"permalink":"/blog/autobindings","source":"@site/blog/2023-02-24-autogenerating-cwtch-bindings.md","title":"Autogenerating Cwtch Bindings","description":"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.","date":"2023-02-24T00:00:00.000Z","formattedDate":"February 24, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"autobindings","permalink":"/blog/tags/autobindings"},{"label":"libcwtch","permalink":"/blog/tags/libcwtch"}],"readingTime":4.545,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Autogenerating Cwtch Bindings","description":"In this development log we describe a first-cut of a workflow to automatically generate Cwtch C and Java bindings from a high-level specification.","slug":"autobindings","tags":["cwtch","cwtch-stable","bindings","autobindings","libcwtch"],"image":"/img/devlog8_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Compile-time Optional Application Experiments (Autobindings)","permalink":"/blog/autobindings-ii"},"nextItem":{"title":"Notes on Cwtch UI Testing (II)","permalink":"/blog/cwtch-testing-ii"}},"content":"The C-bindings for Cwtch evolved as part of Cwtch UI development. After two years of prototyping, development, new features, and revisiting first-implementations we have reached the point where we have a good understanding of\\nwhat the bindings need to do, and how they should do it. To that end we have produced a first-cut of a workflow to **automatically generate** these bindings: [cwtch-autobindings](https://git.openprivacy.ca/cwtch.im/autobindings).\\n\\nThis this development log we will introduced autobindings, the motivation behind them, and how we plan to use them on the [path to Cwtch Stable](https://docs.cwtch.im/blog/path-to-cwtch-stable).\\n\\n![](/img/devlog8.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## A Brief History of Cwtch Bindings\\n\\nPrior to the modern Flutter-based UI application, the first Cwtch UI prototype was based on Qt, with the bindings automatically generated by [therecipe/qt](https://github.com/therecipe/qt). However, after encountering numerous\\ncrash-bugs on the compiled Arm version for Android, and a few weeks of prototyping different approaches, we settled on Flutter as a replacement UI framework.\\n\\nAs part of early prototyping efforts for Flutter we built out a first version of [libCwtch-go](https://git.openprivacy.ca/cwtch.im/libcwtch-go), and over the two years of beta development we have evolved that prototype into a functional set of Cwtch bindings.\\n\\nThis approach has not been without side effects. There is still code from those early prototypes floating around in libCwtch-go, inconsistencies in how functions - in particular [experimental features](https://docs.cwtch.im/blog/cwtch-stable-api-design#the-cwtch-experiment-landscape) - handle settings, [duplication of logic between Cwtch and libCwtch-go](https://docs.cwtch.im/blog/cwtch-stable-api-design#bindings), and [special behaviour in libCwtch-go that better belongs in the core Cwtch library](https://docs.cwtch.im/blog/cwtch-stable-api-design#appendix-a-special-behaviour-defined-by-libcwtch-go).\\n\\nAs part of a broader effort to [refine the Cwtch API in preparation for Cwtch Stable](https://docs.cwtch.im/blog/cwtch-stable-api-design) we have taken the opportunity to fix many of these problems.\\n\\n## Cwtch Autobindings\\n\\nThe current `lib.go` file that encapsulates the vast majority of libCwtch-go currently sits at 1500+ lines of code. However, much of that code is boilerplate calling conventions e.g. the `BlockContact` API implementation is:\\n\\n\\t//export c_BlockContact\\n\\tfunc c_BlockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) {\\n\\t\\tBlockContact(C.GoStringN(profilePtr, profileLen), int(conversation_id))\\n\\t}\\n\\n\\tfunc BlockContact(profileOnion string, conversationID int) {\\n\\t\\tprofile := application.GetPeer(profileOnion)\\n\\t\\tif profile != nil {\\n\\t\\t\\tprofile.BlockConversation(conversationID)\\n\\t\\t}\\n\\t}\\n\\nAll that code is doing is defining a C-compatible API, performing some basic checking of parameters, and passing the result into the core Cwtch library. The two functions themselves support the C-bindings and Java-bindings respectively.\\n\\nIn the new [cwtch-autobindings](https://git.openprivacy.ca/cwtch.im/autobindings) we reduce these multiple lines to [a single one](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec#L19):\\n\\n\\tprofile BlockConversation conversation\\n\\nDefining a `profile`-level function, called `BlockConversation` which takes in a single parameter of type `conversation`.\\n\\nUsing a similar boilerplate-reduction for the reset of `lib.go` yields [5-basic function prototypes](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/README.md#spec-file-format):\\n\\n* Application-level functions e.g. `CreateProfile`\\n* Profile-level functions e.g. `BlockConversation`\\n* Profile-level functions that return data e.g. `GetMessage`\\n* Experimental Profile-level feature functions e.g. `DownloadFile`\\n* Experimental Profile-level feature functions that return data e.g. `ShareFile`\\n\\nOnce aggregated and itemized the full set of bindings for Cwtch applications, profile interactions, and experiments can be [described in fewer than 50 lines, including comments](https://git.openprivacy.ca/cwtch.im/autobindings/src/branch/main/spec). Even including the code necessary to generate the bindings from this specification file (~400 lines), and the code needed to initialize the bindings themselves (~300 lines). This cuts the amount of coded needed by 60%, and eliminates many classes of error and inconsistencies associated with maintaining bindings (e.g. regularizing function calls / checking experiment status / handling error conditions etc.).\\n\\n## Next Steps\\n\\nCwtch autobindings work today, are API-compatible with the existing libCwtch-go implements, and can be fully integrated into an existing Cwtch application with minimal effort. However, there are a few areas which need to be addressed prior to a full rollout:\\n\\n * **[Application-level experiments](https://docs.cwtch.im/blog/cwtch-stable-api-design#application-experiments)** (of which there is only one: Desktop Server Hosting) are not currently supported. This functionality is only tangentially related to the rest of the Cwtch bindings, and necessarily introduces additional dependencies (e.g. on `cwtch-server`). In the coming weeks we will allow optional application experiments to be enabled at compile time, to allow us to produce smaller bindings for platforms that don\'t support the experiment, and to allow us to build new kinds of platform-targeted experiments that can take advantage of platform specific features.\\n* **Dart Library generation**: since we now have a formal description of the bindings interface, we can move ahead with also autogenerating the [Dart-side](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/lib/cwtch) of the bindings interface, giving a boost to UI integration of new features, and allowing us to generate tailored versions of the UI interface e.g. one compiled without experiment support. We can also extend the same logic to other downstream interfaces e.g. [libcwtch-rs](https://git.openprivacy.ca/cwtch.im/libcwtch-rs)\\n * **Documentation generation**: another benefit of a formal description of the bindings interface, we can easily generate documentation compatible with [docs.cwtch.im](https://cwtch.im).\\n * **Cwtch API**: This first cut of autobindings is based on an unreleased version of the core Cwtch library that implements much of the [Cwtch Stable API redesign](https://docs.cwtch.im/blog/cwtch-stable-api-design). In a short while we will be merging these features into Cwtch, in preparation for Cwtch 1.11, and beyond.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-testing-ii","metadata":{"permalink":"/blog/cwtch-testing-ii","source":"@site/blog/2023-02-17-cwtch-testing-ii.md","title":"Notes on Cwtch UI Testing (II)","description":"In this development log we provide more updates on automated UI integration testing!","date":"2023-02-17T00:00:00.000Z","formattedDate":"February 17, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"},{"label":"testing","permalink":"/blog/tags/testing"}],"readingTime":1.75,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Notes on Cwtch UI Testing (II)","description":"In this development log we provide more updates on automated UI integration testing!","slug":"cwtch-testing-ii","tags":["cwtch","cwtch-stable","support","testing"],"image":"/img/devlog7_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Autogenerating Cwtch Bindings","permalink":"/blog/autobindings"},"nextItem":{"title":"Making Cwtch Android Bindings Reproducible","permalink":"/blog/cwtch-android-reproducibility"}},"content":"In this development log, we investigate some text-based UI bugs encountered by [Fuzzbot](https://docs.cwtch.im/docs/contribute/testing#running-fuzzbot), add more [automated UI tests](/blog/cwtch-testing-i) to the pipeline, and announce a new release of the Cwtchbot library.\\n\\n![](/img/devlog7.png)\\n\\n\x3c!--truncate--\x3e\\n\\n\\n## Constraining Cwtch UI Fields\\n\\nFuzzbot identified a few bugs relating to UI layout and text clipping. Certain strings would violate the bounds of their containers and overlap with other UI elements. While this\\ndoesn\'t pose a safety issue, it is unsightly.\\n\\n
\\n\\n[![](/img/dl7-before.png)](/img/dl7-before.png)\\n\\n
Screenshot demonstrating how certain strings would violate the bounds of their containers.
\\n
\\n\\nThese cases were fixed by parenting impacted elements in a `Container` with `clip: hardEdge` and `decoration:BoxDecoration()` (note that both of these are required as Container widgets in Flutter cannot set clipping logic\\nwithout an associated decoration).\\n\\n
\\n\\n[![](/img/dl7-after.png)](/img/dl7-after.png)\\n\\n
Now these clipped strings are tightly constrained to their container bounds.
\\n
\\n\\nThese fixes are available in the [latest Cwtch Nightly](/docs/contribute/testing#cwtch-nightlies), and will be officially released in Cwtch 1.11.\\n\\n## More Automated UI Tests\\n\\nWe have added two new sets of automated UI tests to our pipeline:\\n\\n- *02: Global Settings* - these tests check that certain global settings like languages, theme, unknown contacts blocking, and streamer mode work as expected. ([PR: 628](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/628))\\n- *04: Profile Management* - these tests check that creating, unlocking, and deleting a profile work as expected. ([PR: 632](https://git.openprivacy.ca/cwtch.im/cwtch-ui/pulls/632))\\n\\n## New Release of Cwtchbot\\n\\n[Cwtchbot](https://git.openprivacy.ca/sarah/cwtchbot) has been updated to use the latest Cwtch 0.18.10 API.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-android-reproducibility","metadata":{"permalink":"/blog/cwtch-android-reproducibility","source":"@site/blog/2023-02-10-android-reproducibility.md","title":"Making Cwtch Android Bindings Reproducible","description":"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible","date":"2023-02-10T00:00:00.000Z","formattedDate":"February 10, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":2.92,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Making Cwtch Android Bindings Reproducible","description":"In this devlog we revisit reproducible builds and make Cwtch Android bindings reproducible","slug":"cwtch-android-reproducibility","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog6_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Notes on Cwtch UI Testing (II)","permalink":"/blog/cwtch-testing-ii"},"nextItem":{"title":"Notes on Cwtch UI Testing","permalink":"/blog/cwtch-testing-i"}},"content":"In this development log, we continue our previous work on [reproducible Cwtch bindings](https://docs.cwtch.im/blog/cwtch-bindings-reproducible), uncovering the final few sources of variation between our [Repliqate](https://git.openprivacy.ca/openprivacy/repliqate) scripts and our docker/drone builds, leading to fully reproducible builds for Cwtch Android bindings!\\n\\n![](/img/devlog6.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Changes Necessary for Reproducible Android Bindings\\n\\nAfter a thorough investigation of the build artifacts produced by Repliqate and Drone we uncovered three additional sources of variation:\\n\\n- **Insufficient path stripping introduced by Android NDK tools** - it turns out that Android builds using NDK versions below 22 are not reproducible as they produce randomized artifacts (through unstripped temporary directory paths appearing in compiled binares). NDK 22 [changed the binutils and default linker](https://github.com/android/ndk/wiki/Changelog-r22) to versions that correctly strip such paths from build artifacts. As such it was necessary for us to update the NDK version we used. We chose the technically outdated NDK 22 rather than the more modern NDK 25 to minimize Android OS compatibility changes during this switch. However, per our [long term support plan](https://docs.cwtch.im/blog/cwtch-platform-support), we will be moving towards adopting the latest NDK in the future.\\n- **Paths in DWARF entries** - while we have been unable to track down exactly where these are being introduced, we did track the final difference in the produced bindings to DWARF debug lines embedded in compiled ELF binaries. These entries encoded the actual location of the NDK on the disk of the build machine, instead of the symbolic link that we believed should have been followed. By physically placing the NDK at same location in repliqate as in our Docker container we were able to get these entries to be consistent - however there is still work to do to understand exactly why they are being introduced at all.\\n\\n
\\n\\n[![](/img/aar-diff.png)](/img/aar-diff.png)\\n\\n
Vimdiff comparing the decoded (readelf --debug-dump=line) DWARF debug section of Drone-produced Android bindings v.s. Repliqate-produced. The difference in paths is highlighted.
\\n
\\n\\n- **Go Compiler Acquisition** - our Docker container was compiling the Go compiler from source, while Repliqate was downloading a pre-compiled version. During debugging we changed the Dockerfile to also download the pre-compiled version in order to eliminate the difference as a potential reproducibility issue. Our tests indicated that there *was* a difference between artifacts produced by the precompiled compiler v.s. one built from source - this is likely explained by introduced environmental differences caused by the compilation of the compiler itself e.g. the contents/versions of modules in the Go package cache which we have seen as having an impact on other produced binaries.\\n\\n## Repliqate Scripts\\n\\nWith those issues now fixed, Cwtch Android bindings are **officially reproducible!** The first version that officially met this requirement was 1.10.5, and you can find the Repliqate script under [cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/cwtch-bindings-v1.10.5/libcwtch.v1.10.5-android.script) in the [Cwtch Repliqate scripts repository](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/).\\n\\nThis is another big milestone towards our ultimate goal of full reproducibility for Cwtch releases.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-testing-i","metadata":{"permalink":"/blog/cwtch-testing-i","source":"@site/blog/2023-02-03-cwtch-testing-i.md","title":"Notes on Cwtch UI Testing","description":"In this development log we provide an update on automated UI integration testing!","date":"2023-02-03T00:00:00.000Z","formattedDate":"February 3, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"},{"label":"testing","permalink":"/blog/tags/testing"}],"readingTime":4.74,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Notes on Cwtch UI Testing","description":"In this development log we provide an update on automated UI integration testing!","slug":"cwtch-testing-i","tags":["cwtch","cwtch-stable","support","testing"],"image":"/img/devlog5_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Making Cwtch Android Bindings Reproducible","permalink":"/blog/cwtch-android-reproducibility"},"nextItem":{"title":"Cwtch UI Platform Support","permalink":"/blog/cwtch-platform-support"}},"content":"We first [introduced UI tests last January](https://openprivacy.ca/discreet-log/23-cucumber-testing/). At the time we had developed a suite of UI tests that could be run manually in a development environment. However, we faced a number of issues consistently running these tests in our automated pipelines.\\n\\nOne of the main threads of work that needs to be complete early in the [Cwtch Stable roadmap](https://docs.cwtch.im/blog/path-to-cwtch-stable) is integrating UI tests into our CI pipelines, in addition to expanding their scope. Now that Flutter 3 has stabilized desktop support, and we have invested effort in improving Cwtch performance, it is time to ensure these tests are running on every build.\\n\\n![](/img/devlog5.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Current Limitations of Flutter Gherkin\\n\\nThe original [flutter_gherkin](https://pub.dev/packages/flutter_gherkin) is under semi-active development; however, the latest published versions don\'t support using it with `flutter test`.\\n\\n- **Flutter Test** was originally intended to run single widget/unit tests for a Flutter project.\\n- **Flutter Drive** was originally intended to run integration tests *on a device or an emulator*.\\n\\nHowever, in recent releases these lines have become blurred. The new [integration_test](https://docs.flutter.dev/testing/integration-tests) package that comes built into newer Flutter releases has support for both `flutter drive` and `flutter test`. This was a great change because it decreases the required overhead to run larger integration tests (`flutter drive` sets up a host-controller model that requires a dedicated control channel to be setup, whereas `flutter test` can take advantage of the knowledge that it is being run in the same process, and is noticeably faster - very important when the goal is to run tests as often as possible).\\n\\nThere is thankfully code in the `flutter_gherkin` repository that supports running tests with `flutter test`, however this code currently has a few issues:\\n\\n- The test code generation produces code that doesn\'t compile without minor changes.\\n- Certain functionality like \\"take a screenshot\\" does not work on desktop.\\n\\nAdditionally, there are a few limitations in built-in flutter_gherkin steps that we noticed our tests running into:\\n\\n- Certain tests that fail with async timeouts will cause Flutter exceptions instead of a failed test.\\n- Certain Flutter widgets like `DropdownButton` are not compatible with built-in steps like `tap` because they internally contain multiple copies of the same widget.\\n\\nBecause of the above issues we have chosen to [fork flutter_gherkin](https://git.openprivacy.ca/openprivacy/flutter_gherkin) to fix some of these issues, with the intent of contributing significant fixes upstream, while allowing us to iterate faster on Flutter UI testing.\\n\\n## Integrating Tests into the Pipeline\\n\\nOne of the major limitations of `flutter test` is the lack of a headless mode. In order to successfully run tests in our pipeline we need a headless mode, as most of the containers we use do not have any kind of active display.\\n\\nThankfully it is possible to use [Xfvb](https://en.wikipedia.org/wiki/Xvfb) to create a virtual framebuffer, and set `DISPLAY` to render to that buffer:\\n\\n export DISPLAY=:99\\n Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &\\n\\nThis allows us to neutralize our main issue with `flutter test`, and efficiently run tests in our pipeline.\\n\\n## Catching Bugs!\\n\\nThis small amount of integration work has already caught its first bug.\\n\\nOnce we had fixed most of the issues outlined above, we were still seeing failures on what should have been a very basic scenario. [02_save_load.feature](https://git.openprivacy.ca/cwtch.im/cwtch-ui/src/branch/trunk/integration_test/features/01_general/02_save_load.feature) simply turns a set of experiments on and checks that the state is saved. This test runs perfectly fine on\\ndevelopment environments, but when uploaded to our build pipeline it always failed in the same place - turning on the file sharing experiment.\\n\\nThe cause of this was an actual bug in Cwtch UI. The file sharing experiment failed to turn on if the directory `$USER_HOME/Downloads` didn\'t exist. This is rarely the case on most real world systems, but is the case in our build pipelines. We have since fixed this behaviour to allow file sharing to be turned on even if the usual Download directories are not available.\\n\\nAs we enable more of our UI tests in our pipeline, and across more platforms, we expect to catch more subtle issues like the above - a big win for people who use Cwtch!\\n\\n## Next Steps\\n\\n- **More automated tests:** We have a nice collection of pre-written tests that we can begin to automatically run within pipelines. We have already begun this work, and anticipate finishing it before Cwtch 1.11.\\n- **More platforms:** Right now UI tests only run on Linux. In order to fully take advantage of these tests we need to be able to run them across [our target platforms](https://docs.cwtch.im/docs/getting-started/supported_platforms). We expect to start this work soon; expect more news in a future Cwtch Testing update!\\n\\n- **More steps:** One of our longer-term goals with UI testing was to produce a language around Cwtch testing that went beyond widgets. We had begun to explore this last year with the `expect to see the message` step. As we grow our test library we will be looking for opportunities to build out additional higher-level and Cwtch-specific constructs, e.g. `send a file` or `set profile picture`.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-platform-support","metadata":{"permalink":"/blog/cwtch-platform-support","source":"@site/blog/2023-01-27-platform-support.md","title":"Cwtch UI Platform Support","description":"This development log captures the current state of Cwtch platform support, and how we plan to make platform support decisions going forward are we move towards Cwtch Stable.","date":"2023-01-27T00:00:00.000Z","formattedDate":"January 27, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"support","permalink":"/blog/tags/support"}],"readingTime":10.535,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch UI Platform Support","description":"This development log captures the current state of Cwtch platform support, and how we plan to make platform support decisions going forward are we move towards Cwtch Stable.","slug":"cwtch-platform-support","tags":["cwtch","cwtch-stable","support"],"image":"/img/devlog4_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Notes on Cwtch UI Testing","permalink":"/blog/cwtch-testing-i"},"nextItem":{"title":"Making Cwtch Bindings Reproducible","permalink":"/blog/cwtch-bindings-reproducible"}},"content":"One of the [tenets for Cwtch Stable is **Universal Availability and Cohesive Support**](https://docs.cwtch.im/blog/path-to-cwtch-stable#tenets-of-cwtch-stable):\\n\\n> \\"People who use Cwtch understand that if Cwtch is available for a platform then that means all features will work as expected, that there are no surprise limitations, and any differences are well documented. People should not have to go out of their way to install Cwtch.\\"\\n\\nThis development log seeks to capture the current state of Cwtch platform support, and how we plan to make platform support decisions going forward as we move towards Cwtch Stable.\\n\\nThe questions we aim to answer in this post are: \\n\\n- What systems do we currently support?\\n- How do we decide what systems are supported?\\n- How do we handle new OS versions?\\n- How does application support differ from library support?\\n- What blockers exist for systems we wish to support, but currently cannot e.g ios?\\n\\n![](/img/devlog4.png)\\n\\n\x3c!--truncate--\x3e\\n\\n## Constraints on support\\n\\nFrom CPU architecture, to app store policies, there are a large number of constraints that restrict what platforms Cwtch can target, and how usable Cwtch may be on those systems. \\n\\nIn this section we will highlight the restrictions that we are aware of, and provide a summary of the major external forces that impact our ability to support Cwtch across various platforms.\\n\\n### Limitations on general-purpose computing \\n\\nIn order for Cwtch to work, and be useful, it needs the ability to launch and manage long-lived onion services (in addition to Tor connections to *other* onion services). \\n\\nOn desktop platforms this is usually a given, but the ability to do that kind of activity on mobile operating systems is severely limited or, in many cases, **blocked entirely**. \\n\\nThis is the core reason why Cwtch is not available on iOS, and the main reason why Android support often lags behind.\\n\\nWhile we expect that [Arti](https://gitlab.torproject.org/tpo/core/arti) will improve the management of onion services and connections, there is no way around the need to have an active process managing such services. \\n\\nAs Appstore restrictions are tightened, and mobile operating systems are likewise restricted, we expect that Cwtch on mobile will have to move to a light-client model, requiring the aid of a companion desktop application to be usable.\\n\\nWe encourage you to support mobile operating system vendors who understand the value of general purpose computing, and who don\'t place restrictions on what you can do with your own device.\\n\\n### Constraints introduced by the Flutter SDK\\n\\nThe Cwtch UI is based on Flutter, and as such we have some hard boundaries driven by [platforms that are supported by the Flutter SDK](https://docs.flutter.dev/development/tools/sdk/release-notes/supported-platforms).\\n\\nTo summarize, as of writing this document those platforms are:\\n\\n- Android API 16 and above (arm, arm64, and amd64)\\n- Debian-based Linux Distributions (64-bit only)\\n- macOS El Capitan (10.11) and above\\n- Windows 7 & above (64-bit only)\\n\\nTo put it plainly, without porting Cwtch UI to a different UI platform **we cannot support a 32-bit desktop version**.\\n\\n### Constraints introduced by Appstore Policy \\n\\nAs of writing, [Google is pushing applications to target API 31 or above](https://developer.android.com/google/play/requirements/target-sdk). This target API version is increased on a regular cadence and usually packaged with greater restrictions on what applications can do. To put it another way, even if our minimum theoretical supported Android version is 16, we are practically limited to a subset of tolerated functionality.\\n\\n### CPU Architecture and Cwtch Bindings\\n\\nWe currently build the Cwtch UI and Cwtch Bindings for a wide variety of platform/architecture combinations (see the table below). Our ability to support a given architecture is driven primarily by the overlap of Go Compiler support, Flutter SDK support, and what architectures the underling operating system is available for.\\n\\nIt is worth noting that there is an explicit dependency between the Bindings and the UI. If we cannot build Cwtch Bindings for a given architecture (i.e. if the Go Compiler does not support a given architectures), then we also cannot offer the Cwtch UI for that architecture.\\n\\n| Architecture / Platform | Windows | Linux | macOS | Android |\\n|--------------------------|---------|-----|-------| -------------|\\n| arm | \u274c | \u274c | \u274c | \u2705\ufe0f| \\n| arm64 | \u274c | \ud83d\udfe1 | \u2705 | \u2705\ufe0f | \\n| x86-64 / amd64 | \u2705 | \u2705 | \u2705\ufe0f | \u2705\ufe0f |\\n\\n\\"\ud83d\udfe1\\" - indicates that support is possible, but not yet official e.g. arm64 linux (Raspberry Pi).\\n\\n### Testing and official support\\n\\nAs a non-profit, and an open source software project, we are limited in the resources we have to invest. We rely on the [Cwtch Release Candidate Testers](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group) to do much of the heavy lifting when it comes to Cwtch support on various platforms. This is especially true when it comes to Android variants where, even after testing across the spread of devices available to the Cwtch team, testers still encounter major issues.\\n\\nWe officially only perform full scale automated tests on Linux. With minimal platform regression tests on Windows, Android and OSX. Prior to Cwtch Stable we plan to have support for running automated regression tests across Linux, Windows and Android instances.\\n\\n### End-of-life platforms\\n\\nOperating Systems are never supported indefinitely. The Flutter SDK may allow support for Windows 7, but Microsoft no longer does. [Windows 7 fell out of support on January 14, 2020](https://www.microsoft.com/en-us/windows/end-of-support), Windows 8 followed early this month, on January 10th. 2023. Windows 10 will no longer be support after October 14, 2025.\\n\\nLikewise, while the Flutter SDK official supports OSX versions back to El Capitan (version 10.11), the oldest OSX version currently supported by Apple is Big Sur (version 11). While it may be possible for us to build different versions of Cwtch targeting different OSX versions, we would be doing so against unsupported SDK versions - incurring not only a support cost, but a possible security one also.\\n\\nThe same fundamental restrictions also impact Linux based distributions. While Flutter supports Ubuntu 18.04, and the platform still receiving updates until April 2023, the Cwtch team does not, because of the outdated version of libc installed on the platform would require a distinct build process. [Cwtch currently requires libc 2.31+](https://docs.cwtch.im/blog/cwtch-bindings-reproducible#linux-specific-considerations).\\n\\nAndroid versions prior to Android 10 are no longer officially support, and the requirement to target the most recent versions of Android for inclusion on the Google Playstore mean that long term support for Android versions is driven almost entirely by Google. While Flutter technically has support for Android 16 and above (and we target that as a minimum SDK version), because we have to target the most recent SDK for inclusion on Google Playstore, we cannot make guarantees that these SDKs are fully backwards compatible. We encourage volunteers interested in Cwtch Android to join our [Cwtch Release Candidate Testers groups](https://docs.cwtch.im/docs/contribute/testing#join-the-cwtch-release-candidate-testers-group) to help us understand the limitations of Android support across different API versions.\\n\\n## How we decide to officially support a platform\\n\\nTo help make decisions on what platforms we target for official builds, the Cwtch team have developed four key tenets:\\n\\n1. **The target platform needs to be officially supported by our development tools** - We do not have the resources to maintain forks of the Go compiler or the Flutter SDK that target other operating systems or architectures. The one exception to this rule are non-Debian Linux distributions which while not officially supported by Flutter, are unlikely to have major blockers to official support.\\n2. **The target operating system needs to be supported by the Vendor** - We cannot support a platform that is no longer receiving security updates. Nor do we have the resources to maintain distinct build environments that target out-of-support operating systems. While Cwtch may run on these platforms without additional assistance, we will not schedule work to fix broken support on such platforms. (We may, however, accept Pull Requests from volunteers).\\n3. **The target platform must be backwards compatible with the most recent version in general use** - Even if a system is technically supported by our development tools, and still receives security updates from the vendor, we may still be unbale to officially support it if doing so requires maintaining a separate build environment (because SDK or APIs of dependent libraries are no longer backwards compatible). Like above, Cwtch *may* run on these platforms without additional assistance, but we will not schedule work to fix broken support on such platforms. (we may, however, accept Pull Requests from volunteers).\\n4. **People want to use Cwtch on that platform** - We will generally only consider new platform support if people ask us about it. If Cwtch isn\'t available for a platform you want to use it on, then please get in touch and ask us about it!\\n\\n## Summary of official support\\n\\nThe table below represents our current understanding of Cwtch support across various operating systems and architectures (as of Cwtch 1.10 and January 2023). \\n\\nIn many cases we are looking for testers to confirm that various functionality works. A version of this table will be [maintained as part of the Cwtch Handbook](/docs/getting-started/supported_platforms).\\n\\n**Legend:**\\n\\n- \u2705: **Officially Supported**. Cwtch should work on these platforms without issue. Regressions are treated as high priority.\\n- \ud83d\udfe1: **Best Effort Support**. Cwtch should work on these platforms but there may be documented or unknown issues. Testing may be needed. Some features may require additional work. Volunteer effort is appreciated.\\n- \u274c: **Not Supported**. Cwtch is unlikely to work on these systems. We will probably not accept bug reports for these systems.\\n\\n\\n\\n| Platform | Official Cwtch Builds | Source Support | Notes |\\n|-----------------------------|-----------------------|--------------------|-----------------------------------------------------------------------------------------------------------------------------------|\\n| Windows 11 | \u2705 | \u2705 | 64-bit amd64 only. |\\n| Windows 10 |\u2705 | \u2705 | 64-bit amd64 only. Not officially supported, but official builds may work. |\\n| Windows 8 and below | \u274c | \ud83d\udfe1 | Not supported. Dedicated builds from source may work. Testing Needed. |\\n| OSX 10 and below | \u274c | \ud83d\udfe1 | 64-bit Only. Official builds have been reported to work on Catalina but not High Sierra |\\n| OSX 11 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| OSX 12 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| OSX 13 | \u2705 | \u2705 | 64-bit Only. Official builds supports both arm64 and x86 architectures. |\\n| Debian 11 | \u2705 | \u2705 | 64-bit amd64 Only. |\\n| Debian 10 | \ud83d\udfe1 | \u2705 | 64-bit amd64 Only. |\\n| Debian 9 and below | \ud83d\udfe1 | \u2705 | 64-bit amd64 Only. Builds from source should work, but official builds may be incompatible with installed dependencies. |\\n| Ubuntu 22.04 | \u2705 | \u2705 | 64-bit amd64 Only. |\\n| Other Ubuntu | \ud83d\udfe1 | \u2705 | 64-bit Only. Testing needed. Builds from source should work, but official builds may be incompatible with installed dependencies. | \\n| CentOS | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Gentoo | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Arch | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Whonix | \ud83d\udfe1 | \ud83d\udfe1 | [Known Issues. Specific changes to Cwtch are required for support. ](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/550) |\\n| Raspian (arm64) | \ud83d\udfe1 | \u2705 | Builds from source work. |\\n| Other Linux Distributions | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n| Android 9 and below | \ud83d\udfe1 | \ud83d\udfe1 | Official builds may work. |\\n| Android 10 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 11 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 12 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| Android 13 | \u2705 | \u2705 | Official SDK supprts arm, arm64, and amd64 architectures. |\\n| LineageOS | \ud83d\udfe1 | \ud83d\udfe1 | [Known Issues. Specific changes to Cwtch are required for support.](https://git.openprivacy.ca/cwtch.im/cwtch-ui/issues/607) |\\n| Other Android Distributions | \ud83d\udfe1 | \ud83d\udfe1 | Testing Needed. |\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-bindings-reproducible","metadata":{"permalink":"/blog/cwtch-bindings-reproducible","source":"@site/blog/2023-01-20-reproducible-builds-bindings.md","title":"Making Cwtch Bindings Reproducible","description":"How Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible.","date":"2023-01-20T00:00:00.000Z","formattedDate":"January 20, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"reproducible-builds","permalink":"/blog/tags/reproducible-builds"},{"label":"bindings","permalink":"/blog/tags/bindings"},{"label":"repliqate","permalink":"/blog/tags/repliqate"}],"readingTime":7.915,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Making Cwtch Bindings Reproducible","description":"How Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible.","slug":"cwtch-bindings-reproducible","tags":["cwtch","cwtch-stable","reproducible-builds","bindings","repliqate"],"image":"/img/devlog3_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch UI Platform Support","permalink":"/blog/cwtch-platform-support"},"nextItem":{"title":"Cwtch Stable API Design","permalink":"/blog/cwtch-stable-api-design"}},"content":"From the start of the Cwtch project, the source code for all components making up Cwtch has been freely available for anyone to inspect, use, and modify.\\n\\nBut open source code is only one defense against malicious actors who might seek to undermine your privacy and security. This is why, as part of our ongoing Cwtch Stable work, we are working towards making all parts of the Cwtch chain reproducible and verifiable.\\n\\nThe whole point of reproducible builds is that you no longer have to trust binaries provided by the Cwtch Team because you can **independently verify** that the binaries we release are built from the Cwtch source code.\\n\\nIn this devlog we will talk about how Cwtch bindings are currently built, the changes we have made to Cwtch bindings to make future distributions verifiable, and the next steps we will be taking to make all Cwtch builds reproducible. This will be useful to anyone who is looking to reproduce Cwtch bindings specifically, and to anyone who wants to start implementing reproducible builds in their own project.\\n\\n\x3c!--truncate--\x3e\\n\\n## How Cwtch Bindings are Built\\n\\nSince we launched Cwtch Beta we have used Docker containers as part of our continuous build process.\\n\\nWhen a new change is merged into the repository it kicks off the Cwtch bindings build pipeline which result in the new source tree being downloaded, inspected, compiled, tested, and eventually packaged for different platforms.\\n\\nThe Cwtch Bindings build pipeline results in four compiled libraries:\\n\\n- **libcwtch.so** \u2013 For Linux Platforms, built using the [official golang:1.19.X Docker Image](https://hub.docker.com/_/golang)\\n- **libcwtch.dll** \u2013 For Windows Platforms, built using our own [mingw-go Docker Image](https://git.openprivacy.ca/openprivacy/mingw-go)\\n- **libcwtch.ld** \u2013 For OSX Platforms, built using our dedicated OSX build server (Big Sur 11.6.1)\\n- **cwtch.aar** \u2013 For Android Platforms, built using our own [Android/GoMobile Docker Image](https://git.openprivacy.ca/openprivacy/android-go-mobile)\\n\\nThese compiled libraries eventually make their way into Cwtch-based applications, like the Cwtch UI.\\n\\n## Making libCwtch Reproducible\\n\\nDocker containers alone aren\'t enough to guarantee reproducibility. On inspection of several builds of the same source tree, we noticed a few elements that were distinct to each build:\\n\\n* **Go Build ID**: By default, Go includes a build ID as part of compiled binaries. When using CGO this build ID is non-deterministic and differs for every build. We made the decision to override this build ID for all outputs, setting it to the version of the code being built.\\n* **Build Paths and Go Environment Variables**: By default, Go includes full filesystem paths, and many Go-specific environment variables in the compiled binary \u2013 ostensibly to aid with debugging. These can be removed using the `trimPath` option, which we now specify for all bindings builds.\\n\\n### Linux Specific Considerations\\n\\nAfter the general fixes for Go builds are applied, the main variable input that impacts reproducibility is the version of libc that the bindings are compiled against.\\n\\nOur Drone/Docker build environments are based on [Debian Bullseye](https://www.debian.org/releases/bullseye/) which provides [libc6-dev version 2.31](https://packages.debian.org/bullseye/i386/libc6-dev). Other development setups will likely link libc-dev 2.34+.\\n\\nlibc6-dev 2.34 is notable [because it removed dependencies on libpthread and libdl](https://developers.redhat.com/articles/2021/12/17/why-glibc-234-removed-libpthread) \u2013 neither are used in libCwtch, but they are currently referenced \u2013 which increases the number of sections (and thus the virtual addresses of those sections) defined in the produced ELF file.\\n\\nThis means that in order to reproduce libCwtch Linux bindings it is necessary to have a development environment that will link libc 2.31. We have provided a small, standalone environment which can be used for this purpose (see the section on [Next Steps](#next-steps) for more information).\\n\\n### Windows Specific Considerations\\n\\nThe headers of PE files technically contain a timestamp field. In recent years an [effort has been made to use this field for other purposes](https://devblogs.microsoft.com/oldnewthing/20180103-00/?p=97705), but by default `go build` will still include the timestamp of the file when producing a DLL file (at least when using CGO).\\n\\nFortunately this field can be zeroed out through passing `-Xlinker \u2013no-insert-timestamp` into the `mingw32-gcc` process.\\n\\nWith that, and the universal Go fixes outlined above, Windows bindings are now reproducible using the same standalone Linux environment.\\n\\n\\n### Android Specific Considerations\\n\\nWith the above universal Go fixes, Android build artifacts become almost repeatable. And on certain setups they appear to be reproducible. However,achieving full reproducibility for Android builds requires a number of specific environment dependencies, and considerations:\\n\\n* Cwtch makes use of [GoMobile](https://github.com/golang/mobile) for compiling Android libraries. We pin to a specific version `43a0384520996c8376bfb8637390f12b44773e65` in our Docker containers. Unlike `go build`, the `trimpPath` parameter passed to GoMobile does not strip all development environment paths. This means that the build environment needs consistent directory structures. We have noticed inconsistencies in the detail stripped between setups e.g. cwtch.aar files build by our Docker and Repliqate builds still contain randomized `/tmp/go-build*` references that developer builds do not. We are still in the process of tracking down how these inconsistencies are introduced.\\n* We still use [sdk-tools](https://developer.android.com/studio/releases/sdk-tools) instead of the new [commandline-tools](https://developer.android.com/studio/command-line). The latest version of sdk-tools is `4333796` and available from: [https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip](https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip). As part of our plans for Cwtch Stable we will be updating this dependency.\\n* Cwtch Android builds currently use OpenJDK 8, unchanged from the earliest prototypes when Android development required Java 8. There is no nice way of obtaining this JDK version anymore, our Docker Containers are based on the now deprecated `openjdk:8` image. As with sdk-tooks, as part of our plans for Cwtch Stable we will be updating this dependency. \\n\\nAll of the above mean that we cannot consider Android builds to be reproducible yet, but we believe this is an achievable goal within the next couple of release cycles.\\n\\n### OSX Specific Considerations\\n\\nPerhaps surprisingly, OSX builds present the biggest reproducibility challenge. Unlike Linux, Windows, and Android builds we do not have a Dockerized build environment for OSX builds - relying instead on a dedicated machine to perform the builds.\\n\\nAs with Linux above, the general fixes for setting Go build id and trimming paths are enough to ensure repeatability on the same machine.\\n\\nIn order to fully guarantee reproducibility, OSX libraries need to be built on the same version of OSX with the same version of Xcode. For reference our current build system uses: Big Sur 11.6.1 with Xcode version 13.2.1.\\n\\nIn an ideal world we would be able to cross-compile OSX libraries on Linux the same way we do for Windows and Android. While there are no technical limits, compiling for OSX is dependent on a [proprietary SDK](https://www.apple.com/legal/sla/docs/xcode.pdf). There is no way to trustfully obtain this SDK from anyone except Apple, and the license appears to strictly prohibit transferring the SDK to non-Apple hardware.\\n\\nBecause of these limitations we cannot yet offer a way to automatically verify OSX builds, in the same way that we can for Linux, Windows, and Android. We will continue to look for ways to bring OSX builds to the same level as the rest of our Windows and Linux distributions.\\n\\n## Introducing Repliqate!\\n\\nWith all the above changes, **Cwtch Bindings for Linux and Windows are fully reproducible!**\\n\\nThat alone is great, but we also want to make it easier for **you** to check the reproducibility of our builds yourself! As we noted in the introduction, the whole point of reproducible builds is that you no longer have to trust binaries provided by the Cwtch Team.\\n\\nTo make this process accessible we are releasing a new tool called [repliqate](https://git.openprivacy.ca/openprivacy/repliqate).\\n\\nRepliqate makes it easy to construct isolated build environments, powered by Qemu and a standard Debian Cloud Image distribution.\\n\\nRepliqate runs [build-scripts](https://git.openprivacy.ca/openprivacy/repliqate#writing-a-build-script) to perform actions like downloading the specific versions of Go used in Cwtch official builds, grabbing a copy of the source code for Cwtch bindings, compiling the latest tagged version, and checking the hash against the same version that is available from [builds.openprivacy.ca](https://build.openprivacy.ca/files/).\\n\\nWe now provide [Repliqate build-scripts](https://git.openprivacy.ca/cwtch.im/repliqate-scripts) for reproducible both [Linux libCwtch.so builds](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-linux.script), [Windows libCwtch.dll builds](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-windows.script)!\\n\\nWe also have a partially repeatable [Android cwtch.aar build](https://git.openprivacy.ca/cwtch.im/repliqate-scripts/src/branch/main/libcwtch.v1.10.2-android.script) script that reproduces the official build environment, which we will be using to complete Android reproducible builds as detailed in the last section.\\n\\nYou can (and I want to highly encourage you to) perform all these steps yourself (either via Repliqate, or a setup with the same specifications) and report back. We want to know if there are any other barriers to reproducing Cwtch bindings, and anything that we can do to make the process easier.\\n\\n## Next Steps\\n\\nReproducible bindings are a big achievement, but there is obviously much more to do. In the coming weeks we are committed to undertaking the same process with our Cwtch UI builds to determine what needs to be done to make this as reproducible as bindings.\\n\\nAs we go through this process we also expect to add additional functionality to Repliqate. If you have any feedback or would like to contribute to Repliqate development then please get in touch!\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"},{"id":"cwtch-stable-api-design","metadata":{"permalink":"/blog/cwtch-stable-api-design","source":"@site/blog/2023-01-13-cwtch-stable-api-design.md","title":"Cwtch Stable API Design","description":"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ","date":"2023-01-13T00:00:00.000Z","formattedDate":"January 13, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"},{"label":"api","permalink":"/blog/tags/api"}],"readingTime":17.28,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Cwtch Stable API Design","description":"The post outlines the technical changes we are planning on making to the core Cwtch API in preparation for Cwtch Stable ","slug":"cwtch-stable-api-design","tags":["cwtch","cwtch-stable","planning","api"],"image":"/img/devlog2_small.png","hide_table_of_contents":false,"toc_max_heading_level":4,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Making Cwtch Bindings Reproducible","permalink":"/blog/cwtch-bindings-reproducible"},"nextItem":{"title":"Path to Cwtch Stable","permalink":"/blog/path-to-cwtch-stable"}},"content":"Cwtch grew out of a prototype and has been allowed to evolve over time as we discovered better ways of implementing safe and secure metadata resistant communications. \\n\\nAs we grew, we inserted experimental functionality where it was most accessible to place - not, necessarily, where it was ultimately best to place it - this has led to some degree of overlapping, and inconsistent, responsibilities across Cwtch software packages.\\n\\nAs we move out of Beta and [towards Cwtch Stable](https://docs.cwtch.im/blog/path-to-cwtch-stable) it is time to revisit these previous decisions with both the benefit of hindsight, and years of real-world testing.\\n\\nIn this post we will outline our plans for the Cwtch API that realign responsibilities, and explicitly enable new functionality to be built in a modular, controlled, and secure way. In preparation for Cwtch Stable, and beyond.\\n\\n![](/img/devlog2.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### Clarifying Terminology\\n\\nOver the years we have evolved how we talk about the various parts of the Cwtch ecosystem. To make this document clear we have revised and clarified some terms:\\n\\n- **Cwtch** refers to the overall ecosystem including all the component libraries, bindings, and the flagship Cwtch application. \\n- **Cwtchlib** refers to the [reference implementation of the Cwtch Protocol](https://git.openprivacy.ca/cwtch.im/cwtch) / Application framework, currently written in Go.\\n- **Bindings** refers to C/Java/Kotlin/Rust bindings (primarily [libcwtch-go](https://git.openprivacy.ca/cwtch.im/libcwtch-go)) that act as an interface between Cwtchlib and downstream applications.\\n- `CwtchPeer` is where the reference Cwtch API is defined. It is responsible for managing the state of a single Cwtch Profile, persistence (e.g. storing messages), and automatically reacting to certain messages like message acknowledgements and providing public profile attributes (e.g. profile display name).\\n- `ProtocolEngine` is responsible for maintaining networking resources like listening threads, peer connections, ephemeral server connections. At present, `ProtocolEngine` is also responsible for automatically responding to certain kinds of messages like providing file chunks for shared files.\\n\\n\\n### Tenets of the Cwtch API Design\\n\\nBased on the tenets we have laid out for the Path to Cwtch Stable, we have adopted the following guiding principles for a new API design:\\n\\n- **Robustness** - new features and functionality can be implemented in Cwtch without adding new functions or dependencies to existing Cwtch interfaces.\\n- **Completeness** - all behaviour is either defined in the official library, or explicitly deferred to applications, no special behaviour is implemented by intermediate wrappers.\\n- **Security** \u2013 experiments should not compromise existing Cwtch functionality - and should be able to be turned on/off at any time without issue.\\n\\n### The Cwtch Experiment Landscape\\n\\nA summary of the experiments that are currently implements or in design, and the changes to the code that were required to support them.\\n\\n- **Groups** \u2013 the very first prototypes of Cwtch were designed around group messaging and, as such, multi-party chats are the most integrated experiment within Cwtch sharing interfaces with P2P chat and requiring specialized `ProtocolEngine` functionality to manage ephemeral connections and antispam tokens, including the introduction of new peer events like NewMessageFromGroup. \\n - **Hybrid Groups** - we have plans to upgrade the Groups experience to a more flexible \u201chybrid-groups\u201d protocol which requires additional custom hook-response that needs to be tightly controlled and isolated from other parts of the system.\\n- **Filesharing** \u2013 like Groups, Filesharing is a cross-cutting feature that required new APIs, new Hooks into Peer Events, and additional capability in `ProtocolEngine`.\\n- **Profile Images** \u2013 based on Filesharing and the core get/val functionality, there are only a few small parts of the codebase that are explicitly dedicated to profile images, and these are all event-based reactions that currently reside in the event-decoration module of licwtch-go, but could easily be moved to a standalone module if a hook-based API was available.\\n- **Server Hosting** \u2013 the only example of an Application-level experiment in Cwch at present. This functionality requires no changes to the cwtchlib module, but is mainly implemented in the libcwtch-go bindings themselves. Ideally this functionality would be moved into a standalone package.\\n- **Message Formatting** \u2013 notable as the the main example of a former experimental-functionality that was promoted to an optional feature, but because it is entirely UI based in implementation there are few insights that can be gained from its history\\n- **Search / Microblogging** \u2013 proposed features that would require database access/changes in order to implement fully and efficiently, any proposed changes to the Cwtch API should allow for the possibility of new functionality at all layers of the Cwtch stack, including storage.\\n- **Status / Profile Metadata** \u2013 proposed features that only require specific APIs / hooks for saving requested information for the purposes of caching.\\n\\n### The Problem with Experiments\\n\\nWe have done some work in past to limit the impact an experimental feature can have on the rest of Cwtch, mainly through providing restricted sets of public Cwtch APIs e.g. the `SendMessages` interface that only allows callers to send messages.\\n\\nWe have also worked to package experimental functionality into so-called **Gated Functionalities** that are only available if a given experiment is turned on.\\n\\nTogether, these form the current basis for implementing to Cwtch features in the official libraries, but they are not without problems:\\n\\n- The scope of a functionality is rather broad, and can only be passed a complete Cwtch profile or a denoted subset of functionality e.g. `SendMessages` \u2013 there is no current way to scope a function to a specific conversation, or to a given zone (e.g. filesharing code is technically able to update attributes unrelated to filesharing).\\n- The implementation of experiments has mostly been delegated to bindings and, as such, the gating inside CwtchLib is limited, often relying on state to be passed into it by the bindings, or relying on the bindings explicitly disable the functionality.\\n- This lack of ownership over experiments by the official CwtchLib means that libraries based on CwtchLib instead of bindings do not have access to the safeguards provided by the bindings.\\n\\n### Restricting Powerful Cwtch APIs\\n\\nTo carefully expand Cwtch out using additional experimental APIs we must work to limit the impact further e.g. restricting actions to a given type of conversation, or only executing actions at registered times. To do this we require three separate but related strands of work:\\n\\n- Assume responsibility for experiments and features in Cwtch itself so that Cwtchlib has direct access to which experiments are enabled at any given time. Doing this allows changes to settings to always flow through `Application` and, (as currently happens with Anonymous Communication Network (ACN) state), provides a natural point at which to interface those changes into a Cwtch Profile.\\n- Finer-grained Interfaces that allow restricting actions to preregistered conversation types e.g. a `RestrictedCwtchConversationInterface` which decorates a Cwtch Profile interface such that it can only interact with a single conversation \u2013 these can then be passed into hooks and interface functions to limit their impact.\\n- Registered Hooks at pre-specified points with restricted capabilities \u2013 to allow experimental functionality to register interest in certain events, and act on them at the correct time, and to allow `CwtchPeer` to control which experiments get access to which events at a given time.\\n\\n#### Pre-Registered Hooks\\n\\nIn order to implement certain functionality actions need to take place in-between events handled by `CwtchPeer`. As a motivating example consider a new group membership protocol overlayed above the existing messages. Such a protocol may require checking against group permission settings after receiving a new message, but before inserting it into into the database (e.g. the message author needs to be confirmed against the list of current members authorized to post to the group).\\n\\nThis is currently only possible with invasive changes to the `CwtchPeer` interface, explicitly inserting a hook point and acting on it. In an ideal design we would be able to register such hooks for most likely events without additional development effort.\\n\\nWe are introducing a new set of Cwtch APIs designed for this purpose:\\n\\n- `OnNewPeerMessage` - hooked prior to inserting the message into the database.\\n- `OnPeerMessageConfirmed` \u2013 hooked after a peer message has been inserted into the database.\\n- `OnEncryptedGroupMessage` \u2013 hooked after receiving an encrypted message from a group server.\\n- `OnGroupMessageReceived` \u2013 hooked after a successful decryption of a group message, but before inserting it into the database.\\n- `OnContactRequestValue` \u2013 hooked on request of a scoped (the permission level of the attribute e.g. `public` or `conversation` level attributes), zoned ( relating to a specific feature e.g. `filesharing` or `chat`), and keyed (the name of the attribute e.g. `name` or `manifest`) value from a contact.\\n- `OnContactReceiveValue` \u2013 hooked on receipt of a requested scoped,zoned, and keyed value from a contact.\\n\\nIncluding the following APIs for managing hooked functionality:\\n\\n- `RegisterEvents` - returns a set of events that the extension is interested processing.\\n- `RegisterExperiments` - returns a set of experiments that the extension is interested in being notified about\\n- `OnEvent` - to be called by `CwtchPeer` whenever an event registered with `RegisterEvents` is called (assuming all experiments registered through `RegisterExperiments` is active)\\n\\n#### `ProtocolEngine` Subsystems\\n\\nAs mentioned in our experiment summary, some functionality needs to be implemented directly in the `ProtocolEngine`. The `ProtocolEngine` is responsible for managing networking clients, and sending/receiving packets from those clients to/from a CwtchPeer (via the event bus).\\n\\nSome types of data are too costly to send over the event bus e.g. requested chunks from shared files, and as such we need to delegate the handling of such data to a `ProtocolEngine`.\\n\\nAt the moment is this done through the concept of informal \u201csubsystems\u201d, modular add-ons to `ProtocolEngine` that process certain events. The current informal nature of this design means that there are not hard-and-fast rules regarding what functionality lives in a subsystem, and how subsystems interact with the wider `ProtocolEngine` ecosystem. \\n\\nWe are formalizing this subsystem into an interface, similar to the hooked functionality in `CwtchPeer`:\\n\\n- `RegisterEvents` - returns a set of events that the subsystem needs to consume to operate.\\n- `OnEvent` \u2013 to be called by `ProtocolEngine` whenever an event registered with `RegisterEvents` is called (when all the experiments registered through `RegisterExperiments` are active)\\n- `RegisterContexts` - returns the set of contexts that the subsystem implements e.g. `im.cwtch.filesharing`\\n\\nThis also requires a formalization of two *engine specific* events (for use on the event bus):\\n\\n- `SendCwtchMessage` \u2013 encapsulating the existing `CwtchPeerMessage` that is used internally in `ProtocolEngine` for messages between subsystems.\\n- `CwtchMessageReceived` \u2013 encapsulating the existing `handlePeerMessage` function which effectively already serves this purpose, but instead of using an Observer pattern, is implemented as an increasingly unwieldy set of if/else blocks.\\n\\nAnd the introduction of three **additional** `ProtocolEnine` specific events:\\n\\n- `StartEngineSubsystem` \u2013 replaces subsystem specific start event, can be driven by functionalities to (re)start protocol specific handling.\\n- `StopEngineSubsystem` \u2013 replaces subsystem specific stop event mechanisms, can be driven by functionalities to stop all protocol specific handling.\\n- `SubsystemStatus` \u2013 a generic event that can be published by subsystems with a collection of fields useful for debugging\\n\\nThis will allow us to move the following functionality, currently part of `ProtocolEngine` itself, into generic subsystems:\\n\\n- **Attribute Lookup Handling** - this functionality is currently part of the overloaded `handlePeerMessage` function, filtered using the `Context` parameter of the `CwtchPeerMessage`. As such it can be entirely delegated to a subsystem. \\n- **Filesharing Chunk Request Handling** \u2013 this is also part of handlePeerMessage, also filtered using the `Context` parameter, and is already almost entirely implementing in a standalone subsystem (only routing is handled by `handlePeerMessage`)\\n- **Filesharing Start File Share/Stop File Share** \u2013 this is currently part of the `handleEvent` behaviour of `ProtocolEngine` and can be moved into an `OnEvent` handler of the file sharing subsystem (where such events are already processed).\\n\\nThe introduction of pre-registered hooks in combination with the formalizations of `ProtocolEngine` subsystems will allow the follow functionality, currently implemented in `CwtchPeer` or libcwtch-go to be moved to standalone packages:\\n\\n- **Filesharing** makes heavy use of the getval/retval functionality, we can move all of this into a hooked-based functionality extension. \\n - Filesharing also depends on the file sharing subsystem to be enabled in a `ProtocolEngine`. This subsystem is responsible for processing chunk requests.\\n- **Profile Images** \u2013 we treat profile images as a specialization of the file sharing function, as such the experiment can operate entirely over apis provided by the filesharing experiment. (Right now this specialization lives in libcwtch-go as hooks into the relevant functions)\\n- **Legacy Groups** \u2013 while groups themselves are a first-class consideration for Cwtch, the actual process of constructing and receiving group messages relies heavily on processing of events, or interpreting generic conversation attributes, and as such this functionality can be moved entirely to hooked-based functionality. By doing this we also open the path towards introducing new group protocols based on the same interface.\\n- **Status/Profile Metadata** \u2013 status depends entirely on OnPeerRequestValue / OnPeerReceiveValue and requires little Cwtch Peer interaction other than saving the result.\\n \\n#### Impact on Enabling (Powerful) New Functionality\\n\\nNone of the above restricts our ability to introduce new functionality in to Cwtch that is dependent on more invasive changes (e.g. direct database access / updates), but they do allow us to structure such changes into discrete modules:\\n\\n- **Search** \u2013 a fulltext search feature requires new indexes to be created in Cwtch Storage (likely using the sqlite FT5 module). As an experiment SearchFunctionality would need access to a hook after database setup in order to create and populate those indexes. This is a far more powerful feature than most as it requires direct database access.\\n- **Non Chat Conversation Contexts** - the storage backend work we implemented last year had a long-term goal of enabling non-chat contexts like microblogging. Like search, these kinds of experiments will require deeply integrated access to the Cwtch database.\\n\\n## Application Experiments\\n\\nOne kind of experiment we haven\u2019t touched on yet is additional application functionality, at present we have one main example: Embedded Server Hosting \u2013 this allows a Cwtch desktop client to setup and manage Cwtch Servers.\\n\\nThis kind of functionality doesn\u2019t belong in Cwtchlib \u2013 as it would necessarily introduce unrelated dependencies into the core library.\\n\\nThis functionality also doesn\u2019t belong in the bindings either. They should be as minimal as possible. To that end, we will be moving this functionality out of the bindings and into dedicated repositories which can be managed via an Application Experiment interface.\\n\\n## Bindings\\n\\nThe last problem to be solved is how to interface experiments with the bindings (libcwtch-go) and ultimately downstream applications.\\n\\nWe can split the bindings into four core areas:\\n\\n- **Application Management** - functionality necessary to manage the core Cwtch application e.g. StartCwtch, ReconnectCwtchForeground, Shutdown, CreateProfile etc. This category also include FreePointer which is necessary for safe memory management.\\n- **Application Experiments** - auxiliary functionality that augments the Cwtch application with new features e.g. Server Hosting etc.\\n- **Core Profile Management** - core non-experimental functionality that requires a profile e.g. ImportBundle, SendMessage etc. These apis take a handle in addition to the parameters needed to call the underlying function.\\n- **Experimental Profile Features** \u2013 auxiliary functionality that augments profiles with additional features e.g. ShareFile, SetProfileImage etc. These apis also take a handle.\\n\\nThe flip side of the bindings is the event bus handing which is responsible for maintaining a queue for the downstream application. This queue provides some filtering and enhancement of events to improve performance. This queue can be moved entirely into Application with only GetAppBusEvent defined and exposed in the bindings.\\n\\nIn an ideal future, all of these bindings could be **generated automatically** from the Cwtchlib interface definitions i.e. there should be no special functionality in the bindings themselves. The generation would need to include C bindings (untyped with automatic checks) and the Dart library calling convention (type safe)\\n\\nWe can define three types of C/Java/Kotlin interface function templates:\\n\\n- `ProfileMethodName(profilehandle String, args...)` \u2013 which directly resolves the Cwtch Profile and calls the function.\\n- `ProfileExperimentalMethodName(profilehandle String, args...)` \u2013 which checks the current application settings to see if the experiment is enabled, and then resolves the CwtchProfile and calls the function - else errors.\\n- `ApplicationExperimentalMethodName(args...)` \u2013 which checks the current application settings to see if the experiment is enabled, and if so, calls the experimental application functionality.\\n\\nAll we need to know from CwtchLib is what methods to export to C bindings, and what template they should use. This can be automatically derived from the context `ProfileInterface` for the first, exported methods of the various `Functionalities` for the second, and `ApplicationExperiment` definitions for the third.\\n\\n## Timelines and Next Actions\\n\\n- **Freeze any changes to the bindings interface** - we have made minimal changes to the bindings in the Cwtch 1.9 and 1.10 \u2013 until we have implemented the proposed changes into cwtchlib.\\n- As part of Cwtch 1.11 and 1.12 Release Cycles\\n - Implement the `ProtocolEngine` Subsystem Design as outlined above.\\n - Implement the Hooks API.\\n - Move all special behaviour / extra functionalities in the libcwtch-go bindings into cwtchlib \u2013 with the exception of behaviour related to Application Experiments (i.e. Server Hosting).\\n - Move event handling from the bindings into Application.\\n - Move Application Experiments defined in bindings into their own libraries (or integrate them into existing libraries like cwtch-server) \u2013 keeping the existing interface definitions.\\n- Once Automated UI Tests have been integrated into the Cwtch UI Repository:\\n - Write a generate-cwtch-bindings tool that auto generates the libcwtch-go C/Android bindings **and** a dart calling convention library from cwtchlib and any configured application experiments libraries\\n - Port the existing UI app to use the newly generated dart Cwtch library (this must wait until we have automated UI testing as part of the build process to ensure that there are no regressions during this process).\\n - At this point the bindings are based off of the generated library and libcwtch-go is deprecated / replaced with automatically generated and versioned bindings.\\n\\nAs these changes are made, and these goals met we will be posting about them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, all Cwtch development.\\n\\n## Help us go further!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position to, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)\\n\\n## Appendix A: Special Behaviour Defined by libcwtch-go\\n\\nThe following is an exhaustive list of functionality currently provided by libcwtch-go bindings instead of the cwtchlib:\\n\\n- Application Settings\\n - Including Enabling / Disabling Experiment\\n- ACN Process Management - starting/stopping/restarting/configuring Tor.\\n- Notification Handling - augmenting/suppressing/augmenting interesting event notifications (primarily for Android)\\n- Logging Levels - configuring appropriate logging levels (e.g. `INFO` or `DEBUG`)\\n- Profile Images Helper Functions - handling default profile images for contacts and groups, in addition to looking up custom profile images if the experiment is enabled.\\n- UI Contact Structures - aggregating contact information for the main Cwtch UI.\\n- Group Experiment Functionality\\n - Experiment Gating\\n - GetServerInfoList\\n - GetServerInfo\\n - UI Server Struct Definition\\n- Server Hosting Experiment Functionality - creating/deleting/managing the server hosting experiment for desktop Cwtch clients.\\n- \\"Unencrypted\\" Profile Handling - replacing a blank password with a default password where the underlying API expects a password but the profile has been designated \\"unencrypted\\".\\n- Image Previews Experiment Handling - automatically starting the downloading of certain file types (when the experiment is enabled).\\n- Cwtch UI Reconnection Handling (for Android) - restarting various Cwtch subsystems when the UI attempts to reconnect in circumstances where the Android kernel has killed the underlying process.\\n- Cwtch Profile Engine Activation - starting/stopping a `ProtocolEngine` when requested by the UI, or in response to changes in ACN state.\\n- UI Profile Aggregation - aggregating information related to Profiles for the UI (e.g. network connection status / unread messages) into a single event.\\n- File sharing restarts \\n- UI Event Augmentation - augmenting various internal Cwtch events with information that the UI needs but that isn\'t directly embedded within the event (e.g. converting `handle` to a `conversation id`). Much of this augmentation is legacy, implemented before recent changes to internal Cwtch structs, and likely can either be removed entirely, or delegated into Cwtch itself.\\n- Debug Information - special information available to Cwtch debug builds (memory use / active goroutines etc.)"},{"id":"path-to-cwtch-stable","metadata":{"permalink":"/blog/path-to-cwtch-stable","source":"@site/blog/2023-01-06-path-to-cwtch-stable.md","title":"Path to Cwtch Stable","description":"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.","date":"2023-01-06T00:00:00.000Z","formattedDate":"January 6, 2023","tags":[{"label":"cwtch","permalink":"/blog/tags/cwtch"},{"label":"cwtch-stable","permalink":"/blog/tags/cwtch-stable"},{"label":"planning","permalink":"/blog/tags/planning"}],"readingTime":9.995,"hasTruncateMarker":true,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}],"frontMatter":{"title":"Path to Cwtch Stable","description":"The post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview the next steps and a timeline to tackle them.","slug":"path-to-cwtch-stable","tags":["cwtch","cwtch-stable","planning"],"image":"/img/devlog1_small.jpg","hide_table_of_contents":false,"authors":[{"name":"Sarah Jamie Lewis","title":"Executive Director, Open Privacy Research Society","image_url":"/img/sarah.jpg","imageURL":"/img/sarah.jpg"}]},"prevItem":{"title":"Cwtch Stable API Design","permalink":"/blog/cwtch-stable-api-design"}},"content":"As of December 2022 we have released 10 versions of Cwtch Beta since the [initial launch, 18 months ago, in June 2021](https://openprivacy.ca/discreet-log/10-cwtch-beta-and-beyond/).\\n\\nThere is a consensus among the team that the next large step for the Cwtch project to take is a move from public **Beta** to **Stable** \u2013 marking a point at which we consider Cwtch to be secure and usable.\\n\\nThis post outlines the general principles that are guiding the development of Cwtch Stable, the obstacles that prevent a stable Cwtch release, and closes with an overview of the next steps and our timeline for tackling them.\\n\\n![](/img/devlog1.png)\\n\\n\x3c!--truncate--\x3e\\n\\n### Tenets of Cwtch Stable\\n\\nIt is important to state that Cwtch Stable **does not mean an end to Cwtch development**. Rather, it establishes a baseline at which point Cwtch is considered to be a fully supported project. The Cwtch Team have set the following tenets that guide our decision-making and priorities:\\n\\n1. **Consistent Interface** \u2013 each new Cwtch release should be accompanied by consistent releases to all support libraries. This requires a stable and documented API so that we can be clear when upgrading a library will result in breaking change for downstream projects. We should not, as a general rule, have to make breaking changes to this API interface in order to support new experimental features.\\n2. **Universal Availability and Cohesive Support** \u2013 people who use Cwtch understand that if Cwtch is available for a platform then that means all features will work as expected, that there are no surprise limitations, and any differences are well documented. People should not have to go out of their way to install Cwtch.\\n3. **Reproducible Builds** \u2013 Cwtch builds should be trivially reproducible, including the ability to reproduce all bundled assets. Reproducibility should not rely on containerization, but all containers used in our build process should be reproducible.\\n4. **Proven Security** \u2013 we can demonstrate that Cwtch provides first class security through well documented design, testing, and audit procedures. We should be able to do this for Cwtch in addition to all functional dependencies.\\n\\n### Known Problems\\n\\nTo begin, let\'s outline the current state of Cwtch and lay out the issues that stand in the way of Cwtch Stable.\\n\\n1. **Lack of a Stable API for future feature development** \u2013 while the core Cwtch API has remained fairly unchanged in recent releases we understand that the addition of new features e.g. cohesive group support likely requires new API hooks that allow safe manipulation of Cwtch Profile (transactional semantics and post-event hooks). Before we can even consider a stable release we need to define what this API should look like, and implement it. (Tenet 1)\\n2. **Special functionality in libCwtch-go** \u2013 our C-API bridge (libCwtch-go) currently implements a lot of special functionality in support for both experimental features (e.g. profile images) and UI settings. This special behaviour makes it difficult to track feature responsibility. This behaviour must either be pushed back into the main Cwtch library, or defined to be the responsibility of a downstream application e.g. Cwtch UI. (Tenet 1)\\n3. **libCwtch-rs partial support** - we currently do not officially consider [libCwtch-rs](https://lib.rs/crates/libcwtch) when updating libCwtch-go as part of our release schedule. Before we can consider a Cwtch Stable release we should have multiple beta releases where libCwtch-rs has full support for any and all new Cwtch features. (Tenet 1, Tenet 2)\\n4. **Lack of Reproducible Pipelines** - while the vast majority of our build pipeline is automated, containerized, and reproducible, there remain bundled assets that cannot be trivially constructed, and assets that have non-reproducible elements (e.g. build-time injected via git tags, and go binaries including build user information). (Tenet 3)\\n5. **Lack of up to date, and translated, Security Documentation** \u2013 the [Cwtch security handbook](https://docs.openprivacy.ca/cwtch-security-handbook/) is currently isolated from the rest of our documentation and doesn\u2019t benefit from cross-linking, or translations. (Tenet 4)\\n6. **No Automated UI Tests** \u2013 we put a lot of work into [building out a testing framework for the UI](https://openprivacy.ca/discreet-log/23-cucumber-testing/), but it currently sits mostly unused, and unexercised in our build pipelines. We should revisit that work. (Tenet 4)\\n7. **Code Signing Provider** \u2013 our previous code signing certificate provider had support issues, and we have not yet decided on a replacement. ( Tenet 4)\\n8. **Second-class Android Support** - while we have put [a lot of effort behind Android support](https://openprivacy.ca/discreet-log/27-android-improvements/) across the Beta timeline, it still clearly suffers from additional issues that desktop editions do not. In order to consider Cwtch stable we must resolve all major bugs impacting Android usability. (Tenet 2)\\n9. **Lack of Fuzzing** \u2013 while [Fuzzbot](https://openprivacy.ca/discreet-log/07-fuzzbot/) sets a standard high above most other secure communication applications, we can and should do better. Fuzzbot currently only targets user-endpoint messages, which are the most likely to result in real-world risk, but we should strive to have the same coverage for internal events at both the network level, the internal Cwtch App level, and the event bus level. (Tenet 4)\\n10. **Lack of Formal Release Acceptance Process** \u2013 currently the features and experiments that get included in each release are determined in an ad-hoc consensus. This occasionally means that some features are left unsupported on certain platforms, and bugs occasionally arise in platforms (Android in particular) due to \u201cunrelated\u201d changes. In order for Cwtch to be declared stable, a formal acceptance process must ensure that new changes do not break existing features, and that they work across all platforms. (Tenet2, Tenet 4)\\n11. **Inconsistent Cwtch Information Discovery** \u2013 our current documentation is split between docs.cwtch.im, cwtch.im and docs.openprivacy.ca, in additional to blogs on Discreet Log. This makes it difficult for people to learn about Cwtch, and also means that our own explanations often must link across multiple different sites. (Tenet 2)\\n12. **Incomplete Documentation** \u2013 docs.cwtch.im was very well received. However, it still suffers from incomplete sections, missing links, and an overall lack of screenshots. What screenshots there are lack consistency in sizing, style, and feel. (Tenet 2)\\n\\n### Plan of Action\\n\\nOutside of the problems that have standalone solutions (e.g. find a new code signing provider, or fix all Android issues), there are a number of higher level activities that need to be completed before we can be confident in a Cwtch Stable release:\\n\\n1. **Define, Publish, and Implement a Cwtch Interface Specification Documentation** \u2013 this should include examples of how new (experimental) behaviour might be implemented from finer-grained composition. Must include moving all special functionality out of libCwtch-go. Should be followed up by implementing the proposed design. (Tenet 1, Tenet 4)\\n2. **Define, Publish, and Implement a Cwtch Release Process** \u2013 this document should outline the criteria for publishing a new release, the difference between major and minor versions, how features are tested, how regressions are caught before release, and who is responsible for different parts of the process. (Tenet 2)\\n3. **Define, Publish, and Implement a Cwtch Support Document** - including answers to the questions: what systems do we support, how do we decide what systems are supported, how do we handle new OS versions, and how does application support differ from library support. This should also include a list of blockers for systems we wish to support, but currently cannot e.g ios. (Tenet 2)\\n4. **Define, Publish, and Implement a Cwtch Packaging Document** - as a supplement to the Support document we need to define what packaging we support, in addition to what app stores and managers for which we provide official releases. ( Tenet 2)\\n5. **Define, Publish, and Implement a Reproducible Builds Document** \u2013 this should cover not only Cwtch binaries, but also Docker containers, and included assets (e.g. Tor binaries). Followed up by implementing the plan into our build pipeline. ( Tenet 3)\\n6. **Expand the Cwtch Documentation Site** \u2013 to include the Security Handbook, development blogs, design documentation, and support plans. This should be our only publishing platform, outside of a landing page, and downloads on cwtch.im. This expansion should include a style guide for documentation and screenshots to ensure that we maintain consistent language and visuals when talking about a feature (e.g. we should use the same profile image style, theme, profile names, message style etc.) (Tenet 1, Tenet 2, Tenet 3, Tenet 4)\\n7. **Expand our Automated Testing to include UI and Fuzzing** - integrate UI automated tests into our build pipeline. Expand our fuzzing to include the event bus, and PeerApp packets. Finally, integrate automated fuzzing into the build pipeline, so that all new features are fuzzed to the same level. (Tenet 4)\\n8. **Re-evaluate all Issues across all Cwtch related repositories** \u2013 issues are either bugs that need to be fixed before stable (i.e. they are in service of one of the Tenets), new feature ideas that should be scheduled around stable work (i.e. they don\u2019t align with a specific Tenet), or support requests for systems that need input from the Support and Packaging Plans.\\n9. **Define a Stable Feature Set** \u2013 there are still a few features which do not exist in Cwtch Beta which would be required for a stable release, such as chat search. Following on from the Cwtch Interface Specification Document, the team should decide what features Cwtch Stable will target, and these features should be prioritized for inclusion in Cwtch 1.11, Cwtch 1.12 and any future Beta releases. (Tenet 1)\\n\\n### Goals and Timelines\\n\\nWith all of that laid out, we are now ready to introduce a timeline for resolving some of these problems, and moving us towards a state where we can launch Cwtch Stable:\\n\\n1. By **1st February 2023**, the Cwtch team will have reviewed all existing Cwtch issues in line with this document, and established a timeline for including them in upcoming releases (or specifically commit to not including them in upcoming releases).\\n2. By **1st February 2023**, the Cwtch team will have finalized a feature set that defines Cwtch Stable and established a timeline for including these features in upcoming Cwtch Beta releases.\\n3. By **1st February 2023**, the Cwtch team will have expanded the Cwtch Documentation website to include a section for Security, Design Documents, Infrastructure and Support, in addition to a new development blog.\\n4. By **31st March 2023**, the Cwtch team will have created a style guide for documentation and have used it to ensure that all Cwtch features have consistent documentation available, with at least one screenshot (where applicable).\\n5. By **31st March 2023** the Cwtch team will have published a Cwtch Interface Specification Document, a Cwtch Release Process Document, a Cwtch Support Plan document, a Cwtch Packaging Document, and a document describing the Reproducible Builds Process. These documents will be available on the newly expanded Cwtch Documentation website.\\n6. By **31st March 2023** the Cwtch team will have integrated automated UI tests into the build pipeline for the cwtch-ui repository.\\n7. By **31st March 2023** the Cwtch team will have integrated automated fuzzing into the build pipeline for all Cwtch dependencies maintained by the Cwtch team.\\n8. By **31st March 2023** the Cwtch team will have committed to a date, timeline, and roadmap for launching Cwtch Stable.\\n\\nAs these documents are written, and these goals met we will be posting them here! Subscribe to our [RSS feed](/blog/rss.xml), [Atom feed](/blog/atom.xml), or [JSON feed](/blog/feed.json) to stay up to date, and get the latest on, Cwtch development.\\n\\n### Help us get there!\\n\\nWe couldn\'t do what we do without all the wonderful community support we get, from [one-off donations](https://openprivacy.ca/donate) to [recurring support via Patreon](https://www.patreon.com/openprivacy).\\n\\nIf you want to see us move faster on some of these goals and are in a position, please [donate](https://openprivacy.ca/donate). If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer.\\n\\nDonations of **$5 or more** can opt to receive stickers as a thank-you gift!\\n\\nFor more information about donating to Open Privacy and claiming a thank you gift [please visit the Open Privacy Donate page](https://openprivacy.ca/donate/).\\n\\n![A Photo of Cwtch Stickers](/img/stickers-new.jpg)"}]}')}}]); \ No newline at end of file diff --git a/build-staging/assets/js/d0554977.42033312.js b/build-staging/assets/js/d0554977.2cdbecbc.js similarity index 78% rename from build-staging/assets/js/d0554977.42033312.js rename to build-staging/assets/js/d0554977.2cdbecbc.js index 19342aaf..36c3672b 100644 --- a/build-staging/assets/js/d0554977.42033312.js +++ b/build-staging/assets/js/d0554977.2cdbecbc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1565],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},h=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),c=l(a),g=n,m=c["".concat(p,".").concat(g)]||c[g]||u[g]||o;return a?r.createElement(m,i(i({ref:t},h),{},{components:a})):r.createElement(m,i({ref:t},h))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=g;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:n,i[1]=s;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var r=a(7462),n=(a(7294),a(3905));const o={title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",slug:"path-to-hybrid-groups",tags:["cwtch","hybrid-groups"],image:"/img/hybridgroups.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},i=void 0,s={permalink:"/blog/path-to-hybrid-groups",source:"@site/blog/2024-01-05-path-to-hybrid-groups.md",title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",date:"2024-01-05T00:00:00.000Z",formattedDate:"January 5, 2024",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"hybrid-groups",permalink:"/blog/tags/hybrid-groups"}],readingTime:5.14,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",slug:"path-to-hybrid-groups",tags:["cwtch","hybrid-groups"],image:"/img/hybridgroups.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},nextItem:{title:"Cwtch 1.13 Stable Release Candidate",permalink:"/blog/cwtch-1-13"}},p={authorsImageUrls:[void 0]},l=[{value:"The Problem with Cwtch Groups",id:"the-problem-with-cwtch-groups",level:2},{value:"What Are Hybrid Groups?",id:"what-are-hybrid-groups",level:2},{value:"Levels of Hybrid Groups",id:"levels-of-hybrid-groups",level:3},{value:"Group Messaging Metadata",id:"group-messaging-metadata",level:2},{value:"A Rough Timeline (Q1: Week 0 - Week 10 2024)",id:"a-rough-timeline-q1-week-0---week-10-2024",level:2},{value:"Stay up to date!",id:"stay-up-to-date",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],h={toc:l},c="wrapper";function u(e){let{components:t,...o}=e;return(0,n.kt)(c,(0,r.Z)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Back in ",(0,n.kt)("a",{parentName:"p",href:"/blog/cwtch-1-13"},"September 2023 we released Cwtch 1.13"),", the first version of Cwtch to be labelled as ",(0,n.kt)("strong",{parentName:"p"},"stable"),",\nand a major milestone in Cwtch development. "),(0,n.kt)("p",null,"With the Cwtch interface now stable, we are in a position to begin a new phase in Cwtch development: a Path towards\n",(0,n.kt)("strong",{parentName:"p"},"Hybrid Groups"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{src:a(871).Z,width:"1005",height:"481"})),(0,n.kt)("h2",{id:"the-problem-with-cwtch-groups"},"The Problem with Cwtch Groups"),(0,n.kt)("p",null,"One of the unique features of Cwtch is that ",(0,n.kt)("a",{parentName:"p",href:"/docs/groups/introduction"},"groups")," are dependent on ",(0,n.kt)("a",{parentName:"p",href:"/security/components/cwtch/server"},"untrusted infrastructure"),"."),(0,n.kt)("p",null,"Because of this, at their most basic, a Cwtch group is simply an agreement between a set of peers on a common\ncryptographic key, and a common (set of) untrusted server(s)."),(0,n.kt)("p",null,"This provides Cwtch Groups with very nice properties such as anonymity to anyone not in the group, but it does mean\nthat certain other nice properties like member flexibility, and credential rotation are difficult to achieve."),(0,n.kt)("p",null,"We want to allow people to make the right trade-off when it comes to their own risk models, i.e. to be able to trade\nefficiency for trust when that decision makes sense."),(0,n.kt)("p",null,"To do that we need to introduce a new class of group into Cwtch, something we are calling ",(0,n.kt)("strong",{parentName:"p"},"Hybrid Groups"),"."),(0,n.kt)("h2",{id:"what-are-hybrid-groups"},"What Are Hybrid Groups?"),(0,n.kt)("p",null,"The goal of hybrid groups is to balance the security properties of Cwtch peer-to-peer communication with the\nproperties of untrusted infrastructure. "),(0,n.kt)("p",null,"This is done by augmenting existing Cwtch Groups with an additional layer of peer-to-peer communication in order to provide\nefficient participant management, key rotation, and other useful features."),(0,n.kt)("h3",{id:"levels-of-hybrid-groups"},"Levels of Hybrid Groups"),(0,n.kt)("p",null,"In practice, we imagine there will be a few different levels of Hybrid Group, reflecting different trade-offs between inter-peer trust,\ncommunication efficiency, and group security."),(0,n.kt)("p",null,"There are ",(0,n.kt)("strong",{parentName:"p"},"Traditional Groups"),", these have similar properties to the existing Cwtch Groups. Highly inefficient, but essentially\nrequire zero-trust on behalf of participants other than an expectation that the key is kept secret."),(0,n.kt)("p",null,"We plan to introduce ",(0,n.kt)("strong",{parentName:"p"},"Managed Groups"),": A new kind of group where all participants explicitly trust a given always-online peer (e.g. a bot) with group operations. These\nwill be highly efficient, at the cost of that explicit trust (if that peer behaves maliciously then certain properties are broken). Managed groups will\nbe the first Cwtch groups to allow ",(0,n.kt)("strong",{parentName:"p"},"Contractable")," and ",(0,n.kt)("strong",{parentName:"p"},"Expandable")," groups, and more efficient ",(0,n.kt)("strong",{parentName:"p"},"Key Rotation"),"."),(0,n.kt)("p",null,"And finally a category of ",(0,n.kt)("strong",{parentName:"p"},"Augmented Groups"),": An extension of Managed Groups that places configurable restrictions of the trust given to\nthe peer e.g. by requiring participants to take part in a meta-protocol that confirms certain actions before they are carried out (preventing\nthe trusted-peer from harming properties like ",(0,n.kt)("strong",{parentName:"p"},"Participant Consistency"),"."),(0,n.kt)("h2",{id:"group-messaging-metadata"},"Group Messaging Metadata"),(0,n.kt)("p",null,"As with the rest of Cwtch, our ultimate goal is that no metadata (and specifically as part of this work, no group metadata e.g. membership, message timing) be\navailable to a party outside of the group."),(0,n.kt)("p",null,"Traditional Cwtch Groups take this to the extreme, and the expense of long syncing times, and a high possibility of disruption. Managed Groups\nand Augmented groups will allow communities to make the right trade-offs allowing for greater resilience and faster syncing."),(0,n.kt)("h2",{id:"a-rough-timeline-q1-week-0---week-10-2024"},"A Rough Timeline (Q1: Week 0 - Week 10 2024)"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 0")," - Planning Q1 Cwtch Timeline (this devlog), minor bug fixes and other small UI-focused work originating from reports and feedback\nfrom ",(0,n.kt)("a",{parentName:"li",href:"/docs/contribute/testing"},"Cwtch testers"),"."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 1")," - Work begins on exposing ",(0,n.kt)("strong",{parentName:"li"},"Enhanced Permissions")," in the Cwtch library. These are essential to implementing many of the aspects\nof the new group design, as well as improving other parts of contact management. (Expect more about this in a future devlog). Also, a formal model for Managed Groups will be created and documented.\nThis will form the basis of the implementation."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 2")," - At this point we should be able to begin designing the Managed Group Extension to Cwtch. This will use the Cwtch Event Hooks API\nto respond to Peer events to manage groups. During this work, we also expect to migrate the legacy group code into it's own similar extension to make\nbest use of the APIs. "),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 3")," - Towards the end of January we expect to have a complete formal model of Managed Groups and to be able to start integrating the new extensions into the\nCwtch-UI. We also expect to be in the process of releasing a new 1.14 version of Cwtch that supports Enhanced Permissions."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Weeks 4 - Week 6")," - February marks the 6th anniversary of the founding of Open Privacy Research Society, and our organizational year end. During this\ntime core members of the Cwtch team are often involved in administrative tasks that need to be done during this time, as such we are not planning to make too much progress on Cwtch during this time."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Weeks 7 - Week 10")," - As we approach March, we will be formally integrating Managed Groups in Cwtch, and planning a Cwtch 1.15 release which will feature the new group type. During this time we will also be updating\nCwtch ",(0,n.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/docs/category/groups"},"Group Documentation")," .")),(0,n.kt)("p",null,"Once Managed Groups have been rolled out, we will assess what we have learned and proceed with similar steps for\nAugmented Groups in Q2 (more on that in a later devlog!)."),(0,n.kt)("h2",{id:"stay-up-to-date"},"Stay up to date!"),(0,n.kt)("p",null,"As always, we will be regularly updating this devlog ",(0,n.kt)("a",{parentName:"p",href:"https://fosstodon.org/@cwtch"},"and other channels")," as we continue to make progress towards\nsurveillance resistant infrastructure!"),(0,n.kt)("p",null,"Subscribe to our ",(0,n.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,n.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,n.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all aspects of Cwtch development."),(0,n.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,n.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,n.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,n.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,n.kt)("p",null,"Donations of ",(0,n.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,n.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}u.isMDXComponent=!0},871:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/hybridgroups-11c21d2516ceadabac8af92290b53a08.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[1565],{3905:(e,t,a)=>{a.d(t,{Zo:()=>h,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},h=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),c=l(a),g=n,m=c["".concat(p,".").concat(g)]||c[g]||u[g]||o;return a?r.createElement(m,i(i({ref:t},h),{},{components:a})):r.createElement(m,i({ref:t},h))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=g;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:n,i[1]=s;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var r=a(7462),n=(a(7294),a(3905));const o={title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",slug:"path-to-hybrid-groups",tags:["cwtch","hybrid-groups"],image:"/img/hybridgroups.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg"}]},i=void 0,s={permalink:"/blog/path-to-hybrid-groups",source:"@site/blog/2024-01-05-path-to-hybrid-groups.md",title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",date:"2024-01-05T00:00:00.000Z",formattedDate:"January 5, 2024",tags:[{label:"cwtch",permalink:"/blog/tags/cwtch"},{label:"hybrid-groups",permalink:"/blog/tags/hybrid-groups"}],readingTime:5.14,hasTruncateMarker:!0,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}],frontMatter:{title:"Path to Hybrid Groups",description:"A look at how we plan on implementing the next generation of Cwtch multi-party messaging",slug:"path-to-hybrid-groups",tags:["cwtch","hybrid-groups"],image:"/img/hybridgroups.png",hide_table_of_contents:!1,toc_max_heading_level:4,authors:[{name:"Sarah Jamie Lewis",title:"Executive Director, Open Privacy Research Society",image_url:"/img/sarah.jpg",imageURL:"/img/sarah.jpg"}]},nextItem:{title:"Cwtch 1.13 Stable Release Candidate",permalink:"/blog/cwtch-1-13"}},p={authorsImageUrls:[void 0]},l=[{value:"The Problem with Cwtch Groups",id:"the-problem-with-cwtch-groups",level:2},{value:"What Are Hybrid Groups?",id:"what-are-hybrid-groups",level:2},{value:"Levels of Hybrid Groups",id:"levels-of-hybrid-groups",level:3},{value:"Group Messaging Metadata",id:"group-messaging-metadata",level:2},{value:"A Rough Timeline (Q1: Week 0 - Week 10 2024)",id:"a-rough-timeline-q1-week-0---week-10-2024",level:2},{value:"Stay up to date!",id:"stay-up-to-date",level:2},{value:"Help us go further!",id:"help-us-go-further",level:2}],h={toc:l},c="wrapper";function u(e){let{components:t,...o}=e;return(0,n.kt)(c,(0,r.Z)({},h,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Back in ",(0,n.kt)("a",{parentName:"p",href:"/blog/cwtch-1-13"},"September 2023 we released Cwtch 1.13"),", the first version of Cwtch to be labelled as ",(0,n.kt)("strong",{parentName:"p"},"stable"),",\nand a major milestone in Cwtch development. "),(0,n.kt)("p",null,"With the Cwtch interface now stable, we are in a position to begin a new phase in Cwtch development: a Path towards\n",(0,n.kt)("strong",{parentName:"p"},"Hybrid Groups"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{src:a(871).Z,width:"1005",height:"481"})),(0,n.kt)("h2",{id:"the-problem-with-cwtch-groups"},"The Problem with Cwtch Groups"),(0,n.kt)("p",null,"One of the unique features of Cwtch is that ",(0,n.kt)("a",{parentName:"p",href:"/docs/groups/introduction"},"groups")," are dependent on ",(0,n.kt)("a",{parentName:"p",href:"/security/components/cwtch/server"},"untrusted infrastructure"),"."),(0,n.kt)("p",null,"Because of this, at their most basic, a Cwtch group is simply an agreement between a set of peers on a common\ncryptographic key, and a common (set of) untrusted server(s)."),(0,n.kt)("p",null,"This provides Cwtch Groups with very nice properties such as anonymity to anyone not in the group, but it does mean\nthat certain other nice properties like member flexibility, and credential rotation are difficult to achieve."),(0,n.kt)("p",null,"We want to allow people to make the right trade-off when it comes to their own risk models, i.e. to be able to trade\nefficiency for trust when that decision makes sense."),(0,n.kt)("p",null,"To do that we need to introduce a new class of group into Cwtch, something we are calling ",(0,n.kt)("strong",{parentName:"p"},"Hybrid Groups"),"."),(0,n.kt)("h2",{id:"what-are-hybrid-groups"},"What Are Hybrid Groups?"),(0,n.kt)("p",null,"The goal of hybrid groups is to balance the security properties of Cwtch peer-to-peer communication with the\nproperties of untrusted infrastructure. "),(0,n.kt)("p",null,"This is done by augmenting existing Cwtch Groups with an additional layer of peer-to-peer communication in order to provide\nefficient participant management, key rotation, and other useful features."),(0,n.kt)("h3",{id:"levels-of-hybrid-groups"},"Levels of Hybrid Groups"),(0,n.kt)("p",null,"In practice, we imagine there will be a few different levels of Hybrid Group, reflecting different trade-offs between inter-peer trust,\ncommunication efficiency, and group security."),(0,n.kt)("p",null,"There are ",(0,n.kt)("strong",{parentName:"p"},"Traditional Groups"),", these have similar properties to the existing Cwtch Groups. Highly inefficient, but essentially\nrequire zero-trust on behalf of participants other than an expectation that the key is kept secret."),(0,n.kt)("p",null,"We plan to introduce ",(0,n.kt)("strong",{parentName:"p"},"Managed Groups"),": A new kind of group where all participants explicitly trust a given always-online peer (e.g. a bot) with group operations. These\nwill be highly efficient, at the cost of that explicit trust (if that peer behaves maliciously then certain properties are broken). Managed groups will\nbe the first Cwtch groups to allow ",(0,n.kt)("strong",{parentName:"p"},"Contractable")," and ",(0,n.kt)("strong",{parentName:"p"},"Expandable")," groups, and more efficient ",(0,n.kt)("strong",{parentName:"p"},"Key Rotation"),"."),(0,n.kt)("p",null,"And finally a category of ",(0,n.kt)("strong",{parentName:"p"},"Augmented Groups"),": An extension of Managed Groups that places configurable restrictions of the trust given to\nthe peer e.g. by requiring participants to take part in a meta-protocol that confirms certain actions before they are carried out (preventing\nthe trusted-peer from harming properties like ",(0,n.kt)("strong",{parentName:"p"},"Participant Consistency"),"."),(0,n.kt)("h2",{id:"group-messaging-metadata"},"Group Messaging Metadata"),(0,n.kt)("p",null,"As with the rest of Cwtch, our ultimate goal is that no metadata (and specifically as part of this work, no group metadata e.g. membership, message timing) be\navailable to a party outside of the group."),(0,n.kt)("p",null,"Traditional Cwtch Groups take this to the extreme, and the expense of long syncing times, and a high possibility of disruption. Managed Groups\nand Augmented groups will allow communities to make the right trade-offs allowing for greater resilience and faster syncing."),(0,n.kt)("h2",{id:"a-rough-timeline-q1-week-0---week-10-2024"},"A Rough Timeline (Q1: Week 0 - Week 10 2024)"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 0")," - Planning Q1 Cwtch Timeline (this devlog), minor bug fixes and other small UI-focused work originating from reports and feedback\nfrom ",(0,n.kt)("a",{parentName:"li",href:"/docs/contribute/testing"},"Cwtch testers"),"."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 1")," - Work begins on exposing ",(0,n.kt)("strong",{parentName:"li"},"Enhanced Permissions")," in the Cwtch library. These are essential to implementing many of the aspects\nof the new group design, as well as improving other parts of contact management. (Expect more about this in a future devlog). Also, a formal model for Managed Groups will be created and documented.\nThis will form the basis of the implementation."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 2")," - At this point we should be able to begin designing the Managed Group Extension to Cwtch. This will use the Cwtch Event Hooks API\nto respond to Peer events to manage groups. During this work, we also expect to migrate the legacy group code into it's own similar extension to make\nbest use of the APIs. "),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Week 3")," - Towards the end of January we expect to have a complete formal model of Managed Groups and to be able to start integrating the new extensions into the\nCwtch-UI. We also expect to be in the process of releasing a new 1.14 version of Cwtch that supports Enhanced Permissions."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Weeks 4 - Week 6")," - February marks the 6th anniversary of the founding of ",(0,n.kt)("a",{parentName:"li",href:"https://openprivacy.ca"},"Open Privacy Research Society"),", and our organizational year end. During this\ntime core members of the Cwtch team are often involved in administrative tasks that need to be done during this time, as such we are not planning to make too much progress on Cwtch during this time."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Weeks 7 - Week 10")," - As we approach March, we will be formally integrating Managed Groups in Cwtch, and planning a Cwtch 1.15 release which will feature the new group type. During this time we will also be updating\nCwtch ",(0,n.kt)("a",{parentName:"li",href:"https://docs.cwtch.im/docs/category/groups"},"Group Documentation")," .")),(0,n.kt)("p",null,"Once Managed Groups have been rolled out, we will assess what we have learned and proceed with similar steps for\nAugmented Groups in Q2 (more on that in a later devlog!)."),(0,n.kt)("h2",{id:"stay-up-to-date"},"Stay up to date!"),(0,n.kt)("p",null,"As always, we will be regularly updating this devlog ",(0,n.kt)("a",{parentName:"p",href:"https://fosstodon.org/@cwtch"},"and other channels")," as we continue to make progress towards\nsurveillance resistant infrastructure!"),(0,n.kt)("p",null,"Subscribe to our ",(0,n.kt)("a",{parentName:"p",href:"/blog/rss.xml"},"RSS feed"),", ",(0,n.kt)("a",{parentName:"p",href:"/blog/atom.xml"},"Atom feed"),", or ",(0,n.kt)("a",{parentName:"p",href:"/blog/feed.json"},"JSON feed")," to stay up to date, and get the latest on, all aspects of Cwtch development."),(0,n.kt)("h2",{id:"help-us-go-further"},"Help us go further!"),(0,n.kt)("p",null,"We couldn't do what we do without all the wonderful community support we get, from ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"one-off donations")," to ",(0,n.kt)("a",{parentName:"p",href:"https://www.patreon.com/openprivacy"},"recurring support via Patreon"),"."),(0,n.kt)("p",null,"If you want to see us move faster on some of these goals and are in a position to, please ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate"},"donate"),". If you happen to be at a company that wants to do more for the community and this aligns, please consider donating or sponsoring a developer."),(0,n.kt)("p",null,"Donations of ",(0,n.kt)("strong",{parentName:"p"},"$5 or more")," can opt to receive stickers as a thank-you gift!"),(0,n.kt)("p",null,"For more information about donating to Open Privacy and claiming a thank you gift ",(0,n.kt)("a",{parentName:"p",href:"https://openprivacy.ca/donate/"},"please visit the Open Privacy Donate page"),"."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"A Photo of Cwtch Stickers",src:a(4515).Z,width:"1024",height:"768"})))}u.isMDXComponent=!0},871:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/hybridgroups-11c21d2516ceadabac8af92290b53a08.png"},4515:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/stickers-new-1e9b14bdd638b4907cce833e813a09ad.jpg"}}]); \ No newline at end of file diff --git a/build-staging/assets/js/main.c59698c8.js b/build-staging/assets/js/main.10f93ed4.js similarity index 99% rename from build-staging/assets/js/main.c59698c8.js rename to build-staging/assets/js/main.10f93ed4.js index 4756ecfc..7a51dc2f 100644 --- a/build-staging/assets/js/main.c59698c8.js +++ b/build-staging/assets/js/main.10f93ed4.js @@ -1,2 +1,2 @@ -/*! For license information please see main.c59698c8.js.LICENSE.txt */ -(self.webpackChunkuser_handbook=self.webpackChunkuser_handbook||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(7462),o=n(8356),i=n.n(o),l=n(6887);const s={"003ad223":[()=>n.e(8073).then(n.t.bind(n,6533,19)),"~docs/default/category-docs-tutorialsidebar-category-appearance-f0b.json",6533],"017f0ba6":[()=>n.e(9398).then(n.bind(n,9707)),"@site/security/components/ui/image_previews.md",9707],"01a85c17":[()=>Promise.all([n.e(532),n.e(4013)]).then(n.bind(n,1223)),"@theme/BlogTagsListPage",1223],"0250df79":[()=>n.e(4627).then(n.bind(n,5704)),"@site/blog/2024-01-05-path-to-hybrid-groups.md?truncated=true",5704],"06604d79":[()=>n.e(2216).then(n.bind(n,8245)),"@site/blog/2023-09-06-cwtch-stable-roadmap-update.md",8245],"06a743f0":[()=>n.e(3080).then(n.t.bind(n,6502,19)),"~blog/default/blog-tags-bindings-021.json",6502],"081d7fe1":[()=>n.e(5696).then(n.bind(n,3518)),"@site/docs/groups/introduction.md",3518],"09058439":[()=>n.e(4186).then(n.bind(n,3818)),"@site/security/components/ui/overlays.md",3818],"0991cafe":[()=>n.e(5876).then(n.bind(n,8946)),"@site/blog/2023-07-05-cwtch-stable-roadmap-update.md",8946],"0a9e402c":[()=>n.e(6562).then(n.bind(n,2617)),"@site/docs/chat/share-file.md",2617],"0be9de06":[()=>n.e(7222).then(n.t.bind(n,390,19)),"~blog/default/blog-tags-api-ce2-list.json",390],"0d64c1d9":[()=>n.e(8710).then(n.bind(n,9133)),"@site/blog/2023-01-20-reproducible-builds-bindings.md",9133],"0e384e19":[()=>n.e(9671).then(n.bind(n,9881)),"@site/docs/intro.md",9881],"0e3e2a9e":[()=>n.e(9038).then(n.bind(n,4247)),"@site/docs/chat/delete-contact.md",4247],"1075f7cd":[()=>n.e(9899).then(n.bind(n,5478)),"@site/security/components/tapir/authentication_protocol.md",5478],"1252ef76":[()=>n.e(815).then(n.t.bind(n,5566,19)),"~blog/default/blog-tags-developer-documentation-72f.json",5566],"13bbad87":[()=>n.e(7531).then(n.bind(n,1075)),"@site/security/components/cwtch/key_bundles.md",1075],"141cdfa9":[()=>n.e(7293).then(n.bind(n,677)),"@site/blog/2023-04-06-availability-and-profile-attributes.md?truncated=true",677],"142f86d0":[()=>n.e(7538).then(n.t.bind(n,959,19)),"~blog/default/blog-tags-autobindings-56d.json",959],"14e91d7d":[()=>n.e(606).then(n.t.bind(n,2592,19)),"~blog/default/blog-tags-cwtch-stable-page-3-24f-list.json",2592],"14eb3368":[()=>Promise.all([n.e(532),n.e(9817)]).then(n.bind(n,4228)),"@theme/DocCategoryGeneratedIndexPage",4228],"15b89b76":[()=>n.e(8392).then(n.t.bind(n,9610,19)),"~blog/default/blog-tags-testing-92e.json",9610],"15d993af":[()=>n.e(1174).then(n.t.bind(n,3170,19)),"~blog/default/blog-tags-cwtch-30e-list.json",3170],"16838ca5":[()=>n.e(4704).then(n.t.bind(n,4674,19)),"~blog/default/blog-tags-cwtch-30e.json",4674],17896441:[()=>Promise.all([n.e(532),n.e(9785),n.e(7918)]).then(n.bind(n,5154)),"@theme/DocItem",5154],"1944a0c9":[()=>n.e(9140).then(n.t.bind(n,2796,19)),"~blog/default/blog-tags-security-handbook-f46.json",2796],"1a25c548":[()=>n.e(5732).then(n.bind(n,1202)),"@site/blog/2023-01-06-path-to-cwtch-stable.md?truncated=true",1202],"1af46bd3":[()=>n.e(962).then(n.bind(n,374)),"@site/docs/settings/appearance/ui-columns.md",374],"1b4ba274":[()=>n.e(4052).then(n.bind(n,4061)),"@site/docs/settings/behaviour/notification-policy.md",4061],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1ebd8798":[()=>n.e(4788).then(n.bind(n,5558)),"@site/blog/2023-02-24-autogenerating-cwtch-bindings.md?truncated=true",5558],"22069e6c":[()=>n.e(2852).then(n.bind(n,6951)),"@site/docs/servers/unlock-server.md",6951],"238b6b00":[()=>n.e(129).then(n.bind(n,3874)),"@site/docs/settings/experiments/clickable-links.md",3874],"2853a99a":[()=>n.e(6297).then(n.bind(n,8915)),"@site/docs/groups/leave-group.md",8915],"2a2f80d5":[()=>n.e(291).then(n.bind(n,7331)),"@site/blog/2023-08-03-nightly-preview-conversation-search.md",7331],"2c8522e6":[()=>n.e(7499).then(n.t.bind(n,712,19)),"~docs/default/category-docs-tutorialsidebar-category-experiments-7d0.json",712],"2e7a3344":[()=>n.e(9142).then(n.t.bind(n,7718,19)),"~blog/default/blog-tags-search-304-list.json",7718],"2ffd7dc7":[()=>n.e(2073).then(n.bind(n,5360)),"@site/docs/settings/behaviour/notification-content.md",5360],"3152febb":[()=>n.e(225).then(n.t.bind(n,3492,19)),"~docs/default/category-docs-tutorialsidebar-category-getting-started-3f9.json",3492],"34cd4dc6":[()=>n.e(3429).then(n.bind(n,1172)),"@site/docs/chat/save-conversation-history.md",1172],"38f00f86":[()=>n.e(9667).then(n.t.bind(n,2686,19)),"~blog/default/blog-tags-documentation-944.json",2686],"396ff4f7":[()=>n.e(5987).then(n.bind(n,5205)),"@site/blog/2023-09-27-cwtch-1.13-nightly.md?truncated=true",5205],"39c54b43":[()=>n.e(8793).then(n.t.bind(n,4990,19)),"~blog/default/blog-tags-cwtch-page-2-dca-list.json",4990],"3a109bd3":[()=>n.e(7782).then(n.bind(n,877)),"@site/blog/2023-03-10-cwtch-documentation.md?truncated=true",877],"3b599162":[()=>n.e(7294).then(n.t.bind(n,2159,19)),"~blog/default/blog-tags-libcwtch-b3a-list.json",2159],"3ce57273":[()=>n.e(6972).then(n.bind(n,7548)),"@site/docs/settings/experiments/file-sharing.md",7548],"3db42865":[()=>n.e(7139).then(n.t.bind(n,3769,19)),"/home/sarah/PARA/projects/docs.cwtch.im/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",3769],"3e7ae638":[()=>n.e(9595).then(n.bind(n,8255)),"@site/security/components/tapir/packet_format.md",8255],"414c86b4":[()=>n.e(730).then(n.bind(n,3798)),"@site/docs/groups/accept-group-invite.md",3798],"41c638ee":[()=>n.e(8266).then(n.t.bind(n,8129,19)),"~blog/default/blog-tags-nightly-7a1-list.json",8129],43521719:[()=>n.e(9376).then(n.bind(n,4134)),"@site/docs/chat/message-formatting.md",4134],"437de1b1":[()=>n.e(2562).then(n.t.bind(n,4785,19)),"~docs/docs-security/category-security-tutorialsidebar-category-cwtch-aa0.json",4785],"43b107c1":[()=>n.e(9200).then(n.bind(n,1168)),"@site/blog/2023-02-03-cwtch-testing-i.md",1168],"442b4cb8":[()=>n.e(6971).then(n.t.bind(n,3157,19)),"~blog/default/blog-tags-bindings-021-list.json",3157],"44fbbcc6":[()=>n.e(1088).then(n.bind(n,7079)),"@site/docs/profiles/exporting-profile.md",7079],"48119dbc":[()=>n.e(4998).then(n.bind(n,5847)),"@site/docs/servers/create-server.md",5847],"4912a2e0":[()=>n.e(1598).then(n.t.bind(n,5814,19)),"~blog/default/blog-tags-cwtch-stable-07c.json",5814],"49ced744":[()=>n.e(5006).then(n.t.bind(n,592,19)),"~docs/docs-security/category-security-tutorialsidebar-category-cwtch-components-abf.json",592],"4aa555c3":[()=>n.e(7797).then(n.bind(n,3449)),"@site/blog/2023-06-16-cwtch-1.12.md?truncated=true",3449],"4bb443f0":[()=>n.e(4078).then(n.t.bind(n,9731,19)),"~blog/default/blog-tags-testing-92e-list.json",9731],"4d27f429":[()=>n.e(788).then(n.bind(n,7362)),"@site/blog/2023-01-20-reproducible-builds-bindings.md?truncated=true",7362],"4e8da046":[()=>n.e(6368).then(n.bind(n,9497)),"@site/docs/profiles/introduction.md",9497],"4e96e24f":[()=>n.e(9726).then(n.bind(n,8732)),"@site/docs/chat/block-contact.md",8732],"4f68bcc6":[()=>n.e(3516).then(n.t.bind(n,4289,19)),"/home/sarah/PARA/projects/docs.cwtch.im/.docusaurus/docusaurus-plugin-content-docs/docs-security/plugin-route-context-module-100.json",4289],"52f07771":[()=>n.e(7958).then(n.t.bind(n,6818,19)),"~blog/default/blog-tags-cwtch-page-3-3b7.json",6818],"53cc4802":[()=>n.e(7594).then(n.bind(n,3109)),"@site/blog/2023-02-03-cwtch-testing-i.md?truncated=true",3109],"5420a7ba":[()=>n.e(6515).then(n.bind(n,3962)),"@site/docs/settings/experiments/message-formatting.md",3962],"553b7761":[()=>n.e(732).then(n.bind(n,4465)),"@site/docs/getting-started/supported_platforms.md",4465],"55d4c988":[()=>n.e(6946).then(n.t.bind(n,9048,19)),"~blog/default/blog-tags-cwtch-page-2-dca.json",9048],"58b316cf":[()=>n.e(7015).then(n.t.bind(n,2990,19)),"~blog/default/blog-tags-cwtch-stable-page-3-24f.json",2990],"5a3f34f2":[()=>n.e(7143).then(n.bind(n,1739)),"@site/docs/settings/behaviour/block-unknown-connections.md",1739],"5a5e3510":[()=>n.e(1315).then(n.bind(n,6185)),"@site/docs/profiles/change-password.md",6185],"5b041459":[()=>n.e(7710).then(n.bind(n,2650)),"@site/security/risk.md",2650],"5b4e4bee":[()=>n.e(3171).then(n.t.bind(n,8340,19)),"~docs/docs-security/category-security-tutorialsidebar-category-connectivity-tor-2eb.json",8340],"5beee875":[()=>n.e(9444).then(n.bind(n,2724)),"@site/blog/2023-06-07-new-nightly.md",2724],"5cb298ca":[()=>n.e(2909).then(n.bind(n,4673)),"@site/blog/2023-04-28-developer-docs.md?truncated=true",4673],"5dc151e9":[()=>n.e(923).then(n.bind(n,2320)),"@site/developing/release.md",2320],"5e5faacc":[()=>n.e(8192).then(n.bind(n,9655)),"@site/blog/2023-01-27-platform-support.md",9655],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"5f154b3e":[()=>n.e(6840).then(n.t.bind(n,3896,19)),"~blog/default/blog-tags-search-304.json",3896],"5f6192c8":[()=>n.e(7479).then(n.t.bind(n,8271,19)),"~docs/docs-security/category-security-tutorialsidebar-category-tapir-5d2.json",8271],"6015355d":[()=>n.e(198).then(n.t.bind(n,4978,19)),"~blog/default/blog-tags-cwtch-stable-page-2-9bf-list.json",4978],"6275ceb4":[()=>n.e(6555).then(n.bind(n,248)),"@site/blog/2023-03-10-cwtch-documentation.md",248],"628b3074":[()=>n.e(3478).then(n.t.bind(n,827,19)),"~docs/default/category-docs-tutorialsidebar-category-contribute-357.json",827],"6575cef9":[()=>n.e(8588).then(n.bind(n,2723)),"@site/docs/contribute/stickers.md",2723],"65db1367":[()=>n.e(4370).then(n.t.bind(n,1468,19)),"~blog/default/blog-tags-whonix-75e.json",1468],"663d5f0b":[()=>n.e(7992).then(n.bind(n,3361)),"@site/docs/groups/manage-known-servers.md",3361],"67152af3":[()=>n.e(2322).then(n.bind(n,1887)),"@site/docs/groups/edit-group-name.md",1887],"6875c492":[()=>Promise.all([n.e(532),n.e(9785),n.e(6048),n.e(8610)]).then(n.bind(n,1714)),"@theme/BlogTagsPostsPage",1714],"691d9b08":[()=>n.e(6202).then(n.bind(n,2089)),"@site/blog/2023-08-18-whonix-nightly-preview.md?truncated=true",2089],"693f9c9e":[()=>n.e(6927).then(n.t.bind(n,7822,19)),"~docs/default/category-docs-tutorialsidebar-category-servers-afb.json",7822],"697a71fd":[()=>n.e(712).then(n.bind(n,432)),"@site/docs/profiles/change-profile-image.md",432],"69b09ea9":[()=>n.e(498).then(n.t.bind(n,2332,19)),"~blog/default/blog-tags-community-d90.json",2332],"6a78f460":[()=>n.e(439).then(n.bind(n,2982)),"@site/blog/2023-04-06-availability-and-profile-attributes.md",2982],"6b72ab5e":[()=>n.e(8017).then(n.t.bind(n,2306,19)),"~blog/default/blog-tags-reproducible-builds-973-list.json",2306],"6d453d64":[()=>n.e(9287).then(n.t.bind(n,794,19)),"~blog/default/blog-tags-api-ce2.json",794],"709d36d8":[()=>n.e(176).then(n.bind(n,5722)),"@site/security/components/ui/android.md",5722],"7285d864":[()=>n.e(3965).then(n.bind(n,3166)),"@site/docs/chat/add-contact.md",3166],"76493ef6":[()=>n.e(6033).then(n.t.bind(n,4438,19)),"~docs/default/category-docs-tutorialsidebar-category-platforms-081.json",4438],"7650afbf":[()=>n.e(1586).then(n.bind(n,3233)),"@site/docs/chat/share-address-with-friends.md",3233],"76913e45":[()=>n.e(9072).then(n.t.bind(n,6271,19)),"~blog/default/blog-tags-repliqate-4c9-list.json",6271],"7cfd769c":[()=>n.e(5591).then(n.bind(n,3063)),"@site/blog/2023-07-26-cwtch-stable-call-for-credits.md",3063],"7daa3c80":[()=>n.e(1970).then(n.bind(n,4229)),"@site/docs/servers/edit-server.md",4229],"7df3f7bb":[()=>n.e(5586).then(n.bind(n,7092)),"@site/docs/contribute/developing.md",7092],"7dfbf03e":[()=>n.e(1234).then(n.t.bind(n,6784,19)),"~docs/docs-developer/category-developing-tutorialsidebar-category-building-a-cwtch-app-355.json",6784],"814f3328":[()=>n.e(2535).then(n.t.bind(n,5641,19)),"~blog/default/blog-post-list-prop-default.json",5641],"824a28c6":[()=>n.e(5905).then(n.bind(n,9347)),"@site/developing/building-a-cwtch-app/intro.md",9347],"83128a56":[()=>n.e(545).then(n.bind(n,5377)),"@site/docs/platforms/whonix.md",5377],"83d480e9":[()=>n.e(205).then(n.t.bind(n,3672,19)),"~blog/default/blog-tags-release-b5c.json",3672],"840bb092":[()=>n.e(8351).then(n.bind(n,576)),"@site/docs/profiles/change-name.md",576],"8986836c":[()=>n.e(7).then(n.t.bind(n,8348,19)),"~blog/default/blog-tags-contributors-aaf.json",8348],"89c52e74":[()=>n.e(8655).then(n.bind(n,8052)),"@site/docs/profiles/availability-status.md",8052],"89f86a37":[()=>n.e(9759).then(n.bind(n,9366)),"@site/blog/2023-03-29-cwtch-1.11.md?truncated=true",9366],"8eb4e46b":[()=>n.e(1).then(n.t.bind(n,2638,19)),"~blog/default/blog-page-2-677.json",2638],"8ec965fd":[()=>n.e(6471).then(n.bind(n,4645)),"@site/docs/tor.md",4645],"8fe7a387":[()=>n.e(5233).then(n.bind(n,9667)),"@site/blog/2023-03-03-autobindings-optional-experiments.md",9667],"917e8196":[()=>n.e(5497).then(n.bind(n,6933)),"@site/docs/settings/experiments/qrcodes.md",6933],"92999a1c":[()=>n.e(8442).then(n.t.bind(n,5310,19)),"~blog/default/blog-page-3-fd4.json",5310],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"947e3a34":[()=>n.e(7875).then(n.bind(n,1823)),"@site/security/components/connectivity/intro.md",1823],"975564ee":[()=>n.e(8389).then(n.bind(n,4777)),"@site/docs/chat/introduction.md",4777],"97a045eb":[()=>n.e(3838).then(n.t.bind(n,4869,19)),"~blog/default/blog-tags-nightly-7a1.json",4869],"986bf1b5":[()=>n.e(3625).then(n.t.bind(n,8327,19)),"~docs/default/category-docs-tutorialsidebar-category-profiles-9d3.json",8327],"98da7451":[()=>n.e(8141).then(n.t.bind(n,8777,19)),"~docs/default/category-docs-tutorialsidebar-category-settings-aa6.json",8777],"992a3bb7":[()=>n.e(1415).then(n.t.bind(n,8229,19)),"~blog/default/blog-tags-documentation-944-list.json",8229],"99f50016":[()=>n.e(3854).then(n.bind(n,1189)),"@site/blog/2023-09-06-cwtch-stable-roadmap-update.md?truncated=true",1189],"9b12a270":[()=>n.e(9249).then(n.bind(n,9816)),"@site/blog/2023-02-10-android-reproducibility.md",9816],"9ba2c259":[()=>n.e(1825).then(n.t.bind(n,8123,19)),"~blog/default/blog-tags-preview-ae1-list.json",8123],"9bb37799":[()=>n.e(9767).then(n.bind(n,2957)),"@site/security/components/intro.md",2957],"9c021584":[()=>n.e(7438).then(n.t.bind(n,8055,19)),"~blog/default/blog-tags-release-b5c-list.json",8055],"9d21518d":[()=>n.e(3628).then(n.bind(n,1335)),"@site/docs/settings/experiments/image-previews-and-profile-pictures.md",1335],"9dd8190d":[()=>n.e(2688).then(n.bind(n,7561)),"@site/blog/2023-02-24-autogenerating-cwtch-bindings.md",7561],"9e2a7473":[()=>n.e(1258).then(n.bind(n,8725)),"@site/blog/2023-01-13-cwtch-stable-api-design.md",8725],"9e4087bc":[()=>n.e(3608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],"9eb25904":[()=>n.e(5252).then(n.t.bind(n,6460,19)),"~blog/default/blog-tags-whonix-75e-list.json",6460],"9f1c7621":[()=>n.e(1312).then(n.bind(n,4387)),"@site/blog/2023-02-17-cwtch-testing-ii.md",4387],a02b4022:[()=>n.e(3492).then(n.bind(n,4889)),"@site/blog/2023-06-16-cwtch-1.12.md",4889],a08943ae:[()=>n.e(1800).then(n.bind(n,2661)),"@site/docs/settings/appearance/change-language.md",2661],a11b2692:[()=>n.e(8688).then(n.t.bind(n,4904,19)),"~blog/default/blog-tags-hybrid-groups-61f.json",4904],a19b8c23:[()=>n.e(6435).then(n.bind(n,5487)),"@site/docs/servers/introduction.md",5487],a34f2ac7:[()=>n.e(6291).then(n.t.bind(n,1683,19)),"~blog/default/blog-tags-support-474-list.json",1683],a430b379:[()=>n.e(1367).then(n.t.bind(n,8595,19)),"~blog/default/blog-tags-repliqate-4c9.json",8595],a48a2641:[()=>n.e(6945).then(n.bind(n,209)),"@site/blog/2023-07-26-cwtch-stable-call-for-credits.md?truncated=true",209],a65a3c47:[()=>n.e(7591).then(n.bind(n,5432)),"@site/blog/2023-04-28-developer-docs.md",5432],a6882456:[()=>n.e(4415).then(n.bind(n,5937)),"@site/docs/chat/unblock-contact.md",5937],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(9785),n.e(6048),n.e(3089)]).then(n.bind(n,46)),"@theme/BlogListPage",46],a6f005ae:[()=>n.e(3412).then(n.bind(n,2725)),"@site/blog/2023-07-05-cwtch-stable-roadmap-update.md?truncated=true",2725],a6fe627e:[()=>n.e(9239).then(n.bind(n,2577)),"@site/docs/settings/experiments/group-experiment.md",2577],a7023ddc:[()=>n.e(1713).then(n.t.bind(n,3457,19)),"~blog/default/blog-tags-tags-4c2.json",3457],a79c88c2:[()=>n.e(9976).then(n.bind(n,8553)),"@site/blog/2023-01-13-cwtch-stable-api-design.md?truncated=true",8553],a827eaec:[()=>n.e(7548).then(n.t.bind(n,9163,19)),"~blog/default/blog-tags-hybrid-groups-61f-list.json",9163],a84d2af0:[()=>n.e(890).then(n.bind(n,7177)),"@site/blog/2023-07-14-cwtch-ui-reproducible-builds.md",7177],a8c7fdc6:[()=>n.e(1602).then(n.t.bind(n,6454,19)),"~docs/docs-security/version-current-metadata-prop-751.json",6454],a9159543:[()=>n.e(5941).then(n.bind(n,8986)),"@site/docs/settings/experiments/server-hosting.md",8986],a9d2d00e:[()=>n.e(6126).then(n.bind(n,1528)),"@site/security/components/cwtch/groups.md",1528],ac6c2a1e:[()=>n.e(8639).then(n.t.bind(n,6086,19)),"~blog/default/blog-tags-support-474.json",6086],acb99df2:[()=>n.e(10).then(n.t.bind(n,1892,19)),"~blog/default/blog-tags-cwtch-stable-07c-list.json",1892],af23c5f9:[()=>n.e(3218).then(n.bind(n,4958)),"@site/blog/2023-03-31-cwtch-stable-roadmap-update.md",4958],afaff11a:[()=>n.e(2878).then(n.t.bind(n,318,19)),"~blog/default/blog-tags-community-d90-list.json",318],b0404c31:[()=>n.e(7860).then(n.bind(n,3478)),"@site/blog/2023-01-06-path-to-cwtch-stable.md",3478],b1e57def:[()=>n.e(266).then(n.bind(n,8142)),"@site/security/references.md",8142],b273a073:[()=>n.e(5940).then(n.bind(n,4069)),"@site/docs/servers/delete-server.md",4069],b2b675dd:[()=>n.e(533).then(n.t.bind(n,8017,19)),"~blog/default/blog-c06.json",8017],b2f554cd:[()=>n.e(1477).then(n.t.bind(n,10,19)),"~blog/default/blog-archive-80c.json",10],b59bb8da:[()=>n.e(4729).then(n.t.bind(n,6693,19)),"~docs/default/category-docs-tutorialsidebar-category-conversations-a1f.json",6693],b5c61d38:[()=>n.e(8849).then(n.bind(n,3159)),"@site/security/components/cwtch/server.md",3159],bb772baa:[()=>n.e(6341).then(n.bind(n,1020)),"@site/docs/profiles/delete-profile.md",1020],bf059cf9:[()=>n.e(5273).then(n.bind(n,2626)),"@site/blog/2023-02-10-android-reproducibility.md?truncated=true",2626],bfc2e843:[()=>n.e(610).then(n.bind(n,296)),"@site/docs/settings/appearance/streamer-mode.md",296],c063e42f:[()=>n.e(8589).then(n.bind(n,4463)),"@site/security/components/ui/input.md",4463],c11bf3c5:[()=>n.e(7322).then(n.bind(n,8085)),"@site/docs/settings/introduction.md",8085],c14f15fd:[()=>n.e(7649).then(n.bind(n,3071)),"@site/developing/building-a-cwtch-app/core-concepts.md",3071],c2081115:[()=>n.e(8194).then(n.bind(n,7047)),"@site/security/components/ecosystem-overview.md",7047],c33e2c0d:[()=>n.e(9936).then(n.t.bind(n,6629,19)),"~docs/docs-security/category-security-tutorialsidebar-category-cwtch-ui-ecd.json",6629],c42e2be1:[()=>n.e(4842).then(n.bind(n,7771)),"@site/docs/profiles/create-a-profile.md",7771],c4773fe1:[()=>n.e(2612).then(n.bind(n,4457)),"@site/docs/contribute/translate.md",4457],c4f5d8e4:[()=>Promise.all([n.e(532),n.e(4195)]).then(n.bind(n,3261)),"@site/src/pages/index.js",3261],c747432f:[()=>n.e(8835).then(n.bind(n,2090)),"@site/blog/2023-03-03-autobindings-optional-experiments.md?truncated=true",2090],c94c4dfb:[()=>n.e(9146).then(n.t.bind(n,4469,19)),"/home/sarah/PARA/projects/docs.cwtch.im/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",4469],c96c5262:[()=>n.e(3761).then(n.bind(n,5426)),"@site/blog/2023-03-29-cwtch-1.11.md",5426],c9a691cf:[()=>n.e(2221).then(n.t.bind(n,2426,19)),"~docs/default/category-docs-tutorialsidebar-category-behaviour-e0d.json",2426],cc8d20ec:[()=>n.e(5035).then(n.bind(n,7672)),"@site/docs/profiles/profile-info.md",7672],ccc49370:[()=>Promise.all([n.e(532),n.e(9785),n.e(6048),n.e(6103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],cda43b61:[()=>n.e(6539).then(n.bind(n,7206)),"@site/docs/chat/accept-deny-new-conversation.md",7206],ce314f92:[()=>n.e(6965).then(n.bind(n,6672)),"@site/docs/platforms/tails.md",6672],ce4b3243:[()=>n.e(1179).then(n.t.bind(n,1250,19)),"~blog/default/blog-tags-autobindings-56d-list.json",1250],ced167e6:[()=>n.e(9951).then(n.t.bind(n,5022,19)),"~blog/default/blog-tags-contributors-aaf-list.json",5022],d0554977:[()=>n.e(1565).then(n.bind(n,5461)),"@site/blog/2024-01-05-path-to-hybrid-groups.md",5461],d2206db2:[()=>n.e(7585).then(n.bind(n,4218)),"@site/blog/2023-09-27-cwtch-1.13-nightly.md",4218],d39fd6c2:[()=>n.e(5230).then(n.bind(n,1007)),"@site/security/intro.md",1007],d548bd8c:[()=>n.e(2006).then(n.bind(n,5311)),"@site/blog/2023-07-14-cwtch-ui-reproducible-builds.md?truncated=true",5311],d5f314f9:[()=>n.e(5869).then(n.t.bind(n,9317,19)),"/home/sarah/PARA/projects/docs.cwtch.im/.docusaurus/docusaurus-plugin-content-docs/docs-developer/plugin-route-context-module-100.json",9317],d66d73fd:[()=>n.e(8858).then(n.bind(n,6089)),"@site/security/development.md",6089],d6a44406:[()=>n.e(3213).then(n.t.bind(n,3260,19)),"~blog/default/blog-tags-cwtch-stable-page-2-9bf.json",3260],dc098020:[()=>n.e(6682).then(n.bind(n,258)),"@site/security/deployment.md",258],dc3c323e:[()=>n.e(564).then(n.bind(n,2909)),"@site/docs/groups/create-group.md",2909],df814c0d:[()=>n.e(6494).then(n.t.bind(n,2637,19)),"~blog/default/blog-tags-developer-documentation-72f-list.json",2637],e269d28d:[()=>n.e(9306).then(n.bind(n,448)),"@site/blog/2023-08-18-whonix-nightly-preview.md",448],e4fed92d:[()=>n.e(4995).then(n.bind(n,6142)),"@site/docs/chat/reply-to-message.md",6142],e62fac9c:[()=>n.e(8292).then(n.t.bind(n,4572,19)),"~blog/default/blog-tags-reproducible-builds-973.json",4572],e838c292:[()=>n.e(4943).then(n.bind(n,8074)),"@site/blog/2023-08-03-nightly-preview-conversation-search.md?truncated=true",8074],e88d32a9:[()=>n.e(6585).then(n.t.bind(n,5745,19)),"/home/sarah/PARA/projects/docs.cwtch.im/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],e92b958d:[()=>n.e(7011).then(n.t.bind(n,1954,19)),"~blog/default/blog-tags-planning-ec4.json",1954],eb09219a:[()=>n.e(5327).then(n.t.bind(n,2242,19)),"~blog/default/blog-tags-security-handbook-f46-list.json",2242],eb183be6:[()=>n.e(1596).then(n.bind(n,5940)),"@site/docs/profiles/importing-a-profile.md",5940],eb701f89:[()=>n.e(9999).then(n.t.bind(n,8416,19)),"~blog/default/blog-tags-preview-ae1.json",8416],ebdffa2e:[()=>n.e(4710).then(n.t.bind(n,5797,19)),"~blog/default/blog-tags-libcwtch-b3a.json",5797],ed85aa58:[()=>n.e(1987).then(n.bind(n,274)),"@site/docs/servers/share-key.md",274],ed9713f0:[()=>n.e(7820).then(n.bind(n,7887)),"@site/docs/settings/appearance/light-dark-mode.md",7887],ef243df7:[()=>n.e(7667).then(n.t.bind(n,4354,19)),"~blog/default/blog-tags-planning-ec4-list.json",4354],ef78badf:[()=>n.e(5532).then(n.bind(n,5481)),"@site/blog/2023-01-27-platform-support.md?truncated=true",5481],efb69e30:[()=>n.e(4003).then(n.bind(n,2676)),"@site/docs/chat/conversation-settings.md",2676],f041e880:[()=>n.e(5226).then(n.bind(n,3291)),"@site/blog/2023-03-31-cwtch-stable-roadmap-update.md?truncated=true",3291],f146017a:[()=>n.e(6241).then(n.bind(n,1354)),"@site/docs/contribute/documentation.md",1354],f47fcb38:[()=>n.e(4325).then(n.t.bind(n,1837,19)),"~docs/default/category-docs-tutorialsidebar-category-groups-c04.json",1837],f4bfc819:[()=>n.e(8430).then(n.bind(n,5096)),"@site/docs/groups/send-invite.md",5096],f76a3b8e:[()=>n.e(2184).then(n.bind(n,3103)),"@site/blog/2023-02-17-cwtch-testing-ii.md?truncated=true",3103],f928e8d9:[()=>n.e(8786).then(n.t.bind(n,7160,19)),"~docs/docs-developer/version-current-metadata-prop-751.json",7160],f92b996b:[()=>n.e(4059).then(n.bind(n,1763)),"@site/security/components/cwtch/message_formats.md",1763],f96ae61b:[()=>n.e(2700).then(n.bind(n,4802)),"@site/docs/profiles/unlock-profile.md",4802],fb3c1916:[()=>n.e(276).then(n.bind(n,8886)),"@site/developing/intro.md",8886],fc0ce2b3:[()=>n.e(6363).then(n.bind(n,7266)),"@site/docs/contribute/testing.md",7266],fd27e325:[()=>n.e(1199).then(n.bind(n,9327)),"@site/developing/building-a-cwtch-app/building-an-echobot.md",9327],fdfbe12f:[()=>n.e(6522).then(n.t.bind(n,1484,19)),"~blog/default/blog-tags-cwtch-page-3-3b7-list.json",1484],fe1dd7ae:[()=>n.e(1979).then(n.bind(n,1501)),"@site/blog/2023-06-07-new-nightly.md?truncated=true",1501]};function c(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(9670),d=n(226);function p(e,t){if("*"===e)return i()({loading:c,loader:()=>n.e(4972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const o=l[`${e}-${t}`],p={},f=[],m=[],g=(0,u.Z)(o);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=s[n];r&&(p[t]=r[0],f.push(r[1]),m.push(r[2]))})),i().Map({loading:c,loader:p,modules:f,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let o=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{o=o[e]})),o[l[l.length-1]]=a}));const l=i.__comp;delete i.__comp;const s=i.__context;return delete i.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,a.Z)({},i,n)))}})}const f=[{path:"/blog",component:p("/blog","ca9"),exact:!0},{path:"/blog/archive",component:p("/blog/archive","2da"),exact:!0},{path:"/blog/autobindings",component:p("/blog/autobindings","1f5"),exact:!0},{path:"/blog/autobindings-ii",component:p("/blog/autobindings-ii","231"),exact:!0},{path:"/blog/availability-status-profile-attributes",component:p("/blog/availability-status-profile-attributes","a8c"),exact:!0},{path:"/blog/cwtch-1-13",component:p("/blog/cwtch-1-13","081"),exact:!0},{path:"/blog/cwtch-android-reproducibility",component:p("/blog/cwtch-android-reproducibility","677"),exact:!0},{path:"/blog/cwtch-bindings-reproducible",component:p("/blog/cwtch-bindings-reproducible","279"),exact:!0},{path:"/blog/cwtch-developer-documentation",component:p("/blog/cwtch-developer-documentation","44c"),exact:!0},{path:"/blog/cwtch-documentation",component:p("/blog/cwtch-documentation","968"),exact:!0},{path:"/blog/cwtch-nightly-1-11",component:p("/blog/cwtch-nightly-1-11","a07"),exact:!0},{path:"/blog/cwtch-nightly-1-12",component:p("/blog/cwtch-nightly-1-12","312"),exact:!0},{path:"/blog/cwtch-nightly-preview-conversation-search",component:p("/blog/cwtch-nightly-preview-conversation-search","4df"),exact:!0},{path:"/blog/cwtch-nightly-preview-whonix-save-history",component:p("/blog/cwtch-nightly-preview-whonix-save-history","98f"),exact:!0},{path:"/blog/cwtch-nightly-v.11-74",component:p("/blog/cwtch-nightly-v.11-74","497"),exact:!0},{path:"/blog/cwtch-platform-support",component:p("/blog/cwtch-platform-support","6f7"),exact:!0},{path:"/blog/cwtch-stable-api-design",component:p("/blog/cwtch-stable-api-design","88b"),exact:!0},{path:"/blog/cwtch-stable-call-for-credits",component:p("/blog/cwtch-stable-call-for-credits","c3e"),exact:!0},{path:"/blog/cwtch-stable-roadmap-update",component:p("/blog/cwtch-stable-roadmap-update","d8b"),exact:!0},{path:"/blog/cwtch-stable-roadmap-update-june",component:p("/blog/cwtch-stable-roadmap-update-june","b0c"),exact:!0},{path:"/blog/cwtch-stable-roadmap-update-sept",component:p("/blog/cwtch-stable-roadmap-update-sept","cd0"),exact:!0},{path:"/blog/cwtch-testing-i",component:p("/blog/cwtch-testing-i","346"),exact:!0},{path:"/blog/cwtch-testing-ii",component:p("/blog/cwtch-testing-ii","281"),exact:!0},{path:"/blog/cwtch-ui-reproducible-builds-linux",component:p("/blog/cwtch-ui-reproducible-builds-linux","3b4"),exact:!0},{path:"/blog/page/2",component:p("/blog/page/2","d83"),exact:!0},{path:"/blog/page/3",component:p("/blog/page/3","c15"),exact:!0},{path:"/blog/path-to-cwtch-stable",component:p("/blog/path-to-cwtch-stable","451"),exact:!0},{path:"/blog/path-to-hybrid-groups",component:p("/blog/path-to-hybrid-groups","fdb"),exact:!0},{path:"/blog/tags",component:p("/blog/tags","0a7"),exact:!0},{path:"/blog/tags/api",component:p("/blog/tags/api","ab1"),exact:!0},{path:"/blog/tags/autobindings",component:p("/blog/tags/autobindings","625"),exact:!0},{path:"/blog/tags/bindings",component:p("/blog/tags/bindings","060"),exact:!0},{path:"/blog/tags/community",component:p("/blog/tags/community","711"),exact:!0},{path:"/blog/tags/contributors",component:p("/blog/tags/contributors","6cd"),exact:!0},{path:"/blog/tags/cwtch",component:p("/blog/tags/cwtch","c40"),exact:!0},{path:"/blog/tags/cwtch-stable",component:p("/blog/tags/cwtch-stable","90a"),exact:!0},{path:"/blog/tags/cwtch-stable/page/2",component:p("/blog/tags/cwtch-stable/page/2","577"),exact:!0},{path:"/blog/tags/cwtch-stable/page/3",component:p("/blog/tags/cwtch-stable/page/3","fe5"),exact:!0},{path:"/blog/tags/cwtch/page/2",component:p("/blog/tags/cwtch/page/2","9e9"),exact:!0},{path:"/blog/tags/cwtch/page/3",component:p("/blog/tags/cwtch/page/3","0ab"),exact:!0},{path:"/blog/tags/developer-documentation",component:p("/blog/tags/developer-documentation","d56"),exact:!0},{path:"/blog/tags/documentation",component:p("/blog/tags/documentation","0da"),exact:!0},{path:"/blog/tags/hybrid-groups",component:p("/blog/tags/hybrid-groups","14c"),exact:!0},{path:"/blog/tags/libcwtch",component:p("/blog/tags/libcwtch","b5e"),exact:!0},{path:"/blog/tags/nightly",component:p("/blog/tags/nightly","07f"),exact:!0},{path:"/blog/tags/planning",component:p("/blog/tags/planning","375"),exact:!0},{path:"/blog/tags/preview",component:p("/blog/tags/preview","949"),exact:!0},{path:"/blog/tags/release",component:p("/blog/tags/release","a29"),exact:!0},{path:"/blog/tags/repliqate",component:p("/blog/tags/repliqate","b4a"),exact:!0},{path:"/blog/tags/reproducible-builds",component:p("/blog/tags/reproducible-builds","be2"),exact:!0},{path:"/blog/tags/search",component:p("/blog/tags/search","9a2"),exact:!0},{path:"/blog/tags/security-handbook",component:p("/blog/tags/security-handbook","606"),exact:!0},{path:"/blog/tags/support",component:p("/blog/tags/support","132"),exact:!0},{path:"/blog/tags/testing",component:p("/blog/tags/testing","bc9"),exact:!0},{path:"/blog/tags/whonix",component:p("/blog/tags/whonix","42f"),exact:!0},{path:"/developing",component:p("/developing","f07"),routes:[{path:"/developing/building-a-cwtch-app/building-an-echobot",component:p("/developing/building-a-cwtch-app/building-an-echobot","416"),exact:!0,sidebar:"tutorialSidebar"},{path:"/developing/building-a-cwtch-app/core-concepts",component:p("/developing/building-a-cwtch-app/core-concepts","804"),exact:!0,sidebar:"tutorialSidebar"},{path:"/developing/building-a-cwtch-app/intro",component:p("/developing/building-a-cwtch-app/intro","2e9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/developing/category/building-a-cwtch-app",component:p("/developing/category/building-a-cwtch-app","46a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/developing/intro",component:p("/developing/intro","967"),exact:!0,sidebar:"tutorialSidebar"},{path:"/developing/release",component:p("/developing/release","b76"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/docs",component:p("/docs","732"),routes:[{path:"/docs/category/appearance",component:p("/docs/category/appearance","7b4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/behaviour",component:p("/docs/category/behaviour","e4f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/contribute",component:p("/docs/category/contribute","702"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/conversations",component:p("/docs/category/conversations","d82"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/experiments",component:p("/docs/category/experiments","151"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/getting-started",component:p("/docs/category/getting-started","01f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/groups",component:p("/docs/category/groups","5c5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/platforms",component:p("/docs/category/platforms","3c7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/profiles",component:p("/docs/category/profiles","387"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/servers",component:p("/docs/category/servers","7e8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/category/settings",component:p("/docs/category/settings","a03"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/accept-deny-new-conversation",component:p("/docs/chat/accept-deny-new-conversation","530"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/add-contact",component:p("/docs/chat/add-contact","ff4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/block-contact",component:p("/docs/chat/block-contact","f86"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/conversation-settings",component:p("/docs/chat/conversation-settings","8fa"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/delete-contact",component:p("/docs/chat/delete-contact","377"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/introduction",component:p("/docs/chat/introduction","413"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/message-formatting",component:p("/docs/chat/message-formatting","af9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/reply-to-message",component:p("/docs/chat/reply-to-message","cd5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/save-conversation-history",component:p("/docs/chat/save-conversation-history","496"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/share-address-with-friends",component:p("/docs/chat/share-address-with-friends","280"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/share-file",component:p("/docs/chat/share-file","d13"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/chat/unblock-contact",component:p("/docs/chat/unblock-contact","0c8"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/contribute/developing",component:p("/docs/contribute/developing","9ea"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/contribute/documentation",component:p("/docs/contribute/documentation","102"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/contribute/stickers",component:p("/docs/contribute/stickers","113"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/contribute/testing",component:p("/docs/contribute/testing","1b4"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/contribute/translate",component:p("/docs/contribute/translate","4c7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/getting-started/supported_platforms",component:p("/docs/getting-started/supported_platforms","744"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/accept-group-invite",component:p("/docs/groups/accept-group-invite","8be"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/create-group",component:p("/docs/groups/create-group","f6d"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/edit-group-name",component:p("/docs/groups/edit-group-name","4f1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/introduction",component:p("/docs/groups/introduction","869"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/leave-group",component:p("/docs/groups/leave-group","d38"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/manage-known-servers",component:p("/docs/groups/manage-known-servers","3b7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/groups/send-invite",component:p("/docs/groups/send-invite","aa7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/intro",component:p("/docs/intro","aed"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/platforms/tails",component:p("/docs/platforms/tails","db5"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/platforms/whonix",component:p("/docs/platforms/whonix","fcb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/availability-status",component:p("/docs/profiles/availability-status","23c"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/change-name",component:p("/docs/profiles/change-name","4b7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/change-password",component:p("/docs/profiles/change-password","f4a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/change-profile-image",component:p("/docs/profiles/change-profile-image","d00"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/create-a-profile",component:p("/docs/profiles/create-a-profile","0dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/delete-profile",component:p("/docs/profiles/delete-profile","f16"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/exporting-profile",component:p("/docs/profiles/exporting-profile","290"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/importing-a-profile",component:p("/docs/profiles/importing-a-profile","bca"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/introduction",component:p("/docs/profiles/introduction","740"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/profile-info",component:p("/docs/profiles/profile-info","87a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/profiles/unlock-profile",component:p("/docs/profiles/unlock-profile","867"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/create-server",component:p("/docs/servers/create-server","ebf"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/delete-server",component:p("/docs/servers/delete-server","6dd"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/edit-server",component:p("/docs/servers/edit-server","e03"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/introduction",component:p("/docs/servers/introduction","073"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/share-key",component:p("/docs/servers/share-key","6c7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/servers/unlock-server",component:p("/docs/servers/unlock-server","425"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/appearance/change-language",component:p("/docs/settings/appearance/change-language","fc7"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/appearance/light-dark-mode",component:p("/docs/settings/appearance/light-dark-mode","790"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/appearance/streamer-mode",component:p("/docs/settings/appearance/streamer-mode","d70"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/appearance/ui-columns",component:p("/docs/settings/appearance/ui-columns","99f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/behaviour/block-unknown-connections",component:p("/docs/settings/behaviour/block-unknown-connections","436"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/behaviour/notification-content",component:p("/docs/settings/behaviour/notification-content","ce9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/behaviour/notification-policy",component:p("/docs/settings/behaviour/notification-policy","34e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/clickable-links",component:p("/docs/settings/experiments/clickable-links","e62"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/file-sharing",component:p("/docs/settings/experiments/file-sharing","763"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/group-experiment",component:p("/docs/settings/experiments/group-experiment","223"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/image-previews-and-profile-pictures",component:p("/docs/settings/experiments/image-previews-and-profile-pictures","bd9"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/message-formatting",component:p("/docs/settings/experiments/message-formatting","314"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/qrcodes",component:p("/docs/settings/experiments/qrcodes","095"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/experiments/server-hosting",component:p("/docs/settings/experiments/server-hosting","8a2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/settings/introduction",component:p("/docs/settings/introduction","e3a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/docs/tor",component:p("/docs/tor","94b"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/security",component:p("/security","12c"),routes:[{path:"/security/category/connectivity--tor",component:p("/security/category/connectivity--tor","c9a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/category/cwtch",component:p("/security/category/cwtch","db2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/category/cwtch-components",component:p("/security/category/cwtch-components","b00"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/category/cwtch-ui",component:p("/security/category/cwtch-ui","53f"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/category/tapir",component:p("/security/category/tapir","f6e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/connectivity/intro",component:p("/security/components/connectivity/intro","818"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/cwtch/groups",component:p("/security/components/cwtch/groups","843"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/cwtch/key_bundles",component:p("/security/components/cwtch/key_bundles","cbb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/cwtch/message_formats",component:p("/security/components/cwtch/message_formats","609"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/cwtch/server",component:p("/security/components/cwtch/server","92a"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/ecosystem-overview",component:p("/security/components/ecosystem-overview","b67"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/intro",component:p("/security/components/intro","74e"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/tapir/authentication_protocol",component:p("/security/components/tapir/authentication_protocol","ab3"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/tapir/packet_format",component:p("/security/components/tapir/packet_format","4cb"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/ui/android",component:p("/security/components/ui/android","f66"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/ui/image_previews",component:p("/security/components/ui/image_previews","976"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/ui/input",component:p("/security/components/ui/input","30b"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/components/ui/overlays",component:p("/security/components/ui/overlays","676"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/deployment",component:p("/security/deployment","ef2"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/development",component:p("/security/development","5ad"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/intro",component:p("/security/intro","be1"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/references",component:p("/security/references","b21"),exact:!0,sidebar:"tutorialSidebar"},{path:"/security/risk",component:p("/security/risk","dc7"),exact:!0,sidebar:"tutorialSidebar"}]},{path:"/",component:p("/","057"),exact:!0},{path:"*",component:p("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>o});var r=n(7294);const a=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),o=n(3727),i=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(2295)];var c=n(723),u=n(6550),d=n(8790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(7462),m=n(5742),g=n(2263),h=n(4996),b=n(6668),v=n(1944),y=n(4711),w=n(9727),k=n(3320),S=n(197);function E(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,g.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.Z)(),a=function(){const{siteConfig:{url:e}}=(0,g.Z)(),{pathname:t}=(0,u.TH)();return e+(0,h.Z)(t)}(),o=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:o}),r.createElement("link",{rel:"canonical",href:o}))}function x(){const{i18n:{currentLocale:e}}=(0,g.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(_,null),r.createElement(E,null),r.createElement(S.Z,{tag:k.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,f.Z)({key:t},e))))))}const C=new Map;function T(e){if(C.has(e.pathname))return{...e,pathname:C.get(e.pathname)};if((0,d.f)(c.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return C.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return C.set(e.pathname,t),{...e,pathname:t}}var L=n(8934),A=n(8940);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const R=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),P("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function N(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(c.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class O extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?P("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=P("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),N(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(R,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const I=O,D="__docusaurus-base-url-issue-banner-container",M="__docusaurus-base-url-issue-banner",j="__docusaurus-base-url-issue-banner-suggestion-container",F="__DOCUSAURUS_INSERT_BASEURL_BANNER";function B(e){return`\nwindow['${F}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${F}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${D}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{window[F]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,B(e))),r.createElement("div",{id:D}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement(z,null):null}function $(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,g.Z)(),i=(0,h.Z)(e),{htmlLang:l,direction:s}=o[a];return r.createElement(m.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var G=n(4763);function q(){const e=(0,d.H)(c.Z),t=(0,u.TH)();return r.createElement(G.Z,null,r.createElement(A.M,null,r.createElement(L.t,null,r.createElement(p,null,r.createElement($,null),r.createElement(x,null),r.createElement(U,null),r.createElement(I,{location:T(t)},e)))))}var H=n(6887);const Z=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var V=n(9670);const W=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,Q={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!W.has(e))(e))return!1;W.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(H).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,V.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Z(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),N(e))},X=Object.freeze(Q);if(l.Z.canUseDOM){window.docusaurus=X;const e=a.hydrate;N(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(o.VK,null,r.createElement(q,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"docs-developer":{"path":"/developing","versions":[{"name":"current","label":"Next","isLast":true,"path":"/developing","mainDocId":"intro","docs":[{"id":"building-a-cwtch-app/building-an-echobot","path":"/developing/building-a-cwtch-app/building-an-echobot","sidebar":"tutorialSidebar"},{"id":"building-a-cwtch-app/core-concepts","path":"/developing/building-a-cwtch-app/core-concepts","sidebar":"tutorialSidebar"},{"id":"building-a-cwtch-app/intro","path":"/developing/building-a-cwtch-app/intro","sidebar":"tutorialSidebar"},{"id":"intro","path":"/developing/intro","sidebar":"tutorialSidebar"},{"id":"release","path":"/developing/release","sidebar":"tutorialSidebar"},{"id":"/category/building-a-cwtch-app","path":"/developing/category/building-a-cwtch-app","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/developing/intro","label":"intro"}}}}],"breadcrumbs":true},"docs-security":{"path":"/security","versions":[{"name":"current","label":"Next","isLast":true,"path":"/security","mainDocId":"intro","docs":[{"id":"components/connectivity/intro","path":"/security/components/connectivity/intro","sidebar":"tutorialSidebar"},{"id":"components/cwtch/groups","path":"/security/components/cwtch/groups","sidebar":"tutorialSidebar"},{"id":"components/cwtch/key_bundles","path":"/security/components/cwtch/key_bundles","sidebar":"tutorialSidebar"},{"id":"components/cwtch/message_formats","path":"/security/components/cwtch/message_formats","sidebar":"tutorialSidebar"},{"id":"components/cwtch/server","path":"/security/components/cwtch/server","sidebar":"tutorialSidebar"},{"id":"components/ecosystem-overview","path":"/security/components/ecosystem-overview","sidebar":"tutorialSidebar"},{"id":"components/intro","path":"/security/components/intro","sidebar":"tutorialSidebar"},{"id":"components/tapir/authentication_protocol","path":"/security/components/tapir/authentication_protocol","sidebar":"tutorialSidebar"},{"id":"components/tapir/packet_format","path":"/security/components/tapir/packet_format","sidebar":"tutorialSidebar"},{"id":"components/ui/android","path":"/security/components/ui/android","sidebar":"tutorialSidebar"},{"id":"components/ui/image_previews","path":"/security/components/ui/image_previews","sidebar":"tutorialSidebar"},{"id":"components/ui/input","path":"/security/components/ui/input","sidebar":"tutorialSidebar"},{"id":"components/ui/overlays","path":"/security/components/ui/overlays","sidebar":"tutorialSidebar"},{"id":"deployment","path":"/security/deployment","sidebar":"tutorialSidebar"},{"id":"development","path":"/security/development","sidebar":"tutorialSidebar"},{"id":"intro","path":"/security/intro","sidebar":"tutorialSidebar"},{"id":"references","path":"/security/references","sidebar":"tutorialSidebar"},{"id":"risk","path":"/security/risk","sidebar":"tutorialSidebar"},{"id":"/category/cwtch-components","path":"/security/category/cwtch-components","sidebar":"tutorialSidebar"},{"id":"/category/connectivity--tor","path":"/security/category/connectivity--tor","sidebar":"tutorialSidebar"},{"id":"/category/tapir","path":"/security/category/tapir","sidebar":"tutorialSidebar"},{"id":"/category/cwtch","path":"/security/category/cwtch","sidebar":"tutorialSidebar"},{"id":"/category/cwtch-ui","path":"/security/category/cwtch-ui","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/security/intro","label":"intro"}}}}],"breadcrumbs":true},"default":{"path":"/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/docs","mainDocId":"intro","docs":[{"id":"chat/accept-deny-new-conversation","path":"/docs/chat/accept-deny-new-conversation","sidebar":"tutorialSidebar"},{"id":"chat/add-contact","path":"/docs/chat/add-contact","sidebar":"tutorialSidebar"},{"id":"chat/block-contact","path":"/docs/chat/block-contact","sidebar":"tutorialSidebar"},{"id":"chat/conversation-settings","path":"/docs/chat/conversation-settings","sidebar":"tutorialSidebar"},{"id":"chat/delete-contact","path":"/docs/chat/delete-contact","sidebar":"tutorialSidebar"},{"id":"chat/introduction","path":"/docs/chat/introduction","sidebar":"tutorialSidebar"},{"id":"chat/message-formatting","path":"/docs/chat/message-formatting","sidebar":"tutorialSidebar"},{"id":"chat/reply-to-message","path":"/docs/chat/reply-to-message","sidebar":"tutorialSidebar"},{"id":"chat/save-conversation-history","path":"/docs/chat/save-conversation-history","sidebar":"tutorialSidebar"},{"id":"chat/share-address-with-friends","path":"/docs/chat/share-address-with-friends","sidebar":"tutorialSidebar"},{"id":"chat/share-file","path":"/docs/chat/share-file","sidebar":"tutorialSidebar"},{"id":"chat/unblock-contact","path":"/docs/chat/unblock-contact","sidebar":"tutorialSidebar"},{"id":"contribute/developing","path":"/docs/contribute/developing","sidebar":"tutorialSidebar"},{"id":"contribute/documentation","path":"/docs/contribute/documentation","sidebar":"tutorialSidebar"},{"id":"contribute/stickers","path":"/docs/contribute/stickers","sidebar":"tutorialSidebar"},{"id":"contribute/testing","path":"/docs/contribute/testing","sidebar":"tutorialSidebar"},{"id":"contribute/translate","path":"/docs/contribute/translate","sidebar":"tutorialSidebar"},{"id":"getting-started/supported_platforms","path":"/docs/getting-started/supported_platforms","sidebar":"tutorialSidebar"},{"id":"groups/accept-group-invite","path":"/docs/groups/accept-group-invite","sidebar":"tutorialSidebar"},{"id":"groups/create-group","path":"/docs/groups/create-group","sidebar":"tutorialSidebar"},{"id":"groups/edit-group-name","path":"/docs/groups/edit-group-name","sidebar":"tutorialSidebar"},{"id":"groups/introduction","path":"/docs/groups/introduction","sidebar":"tutorialSidebar"},{"id":"groups/leave-group","path":"/docs/groups/leave-group","sidebar":"tutorialSidebar"},{"id":"groups/manage-known-servers","path":"/docs/groups/manage-known-servers","sidebar":"tutorialSidebar"},{"id":"groups/send-invite","path":"/docs/groups/send-invite","sidebar":"tutorialSidebar"},{"id":"intro","path":"/docs/intro","sidebar":"tutorialSidebar"},{"id":"platforms/tails","path":"/docs/platforms/tails","sidebar":"tutorialSidebar"},{"id":"platforms/whonix","path":"/docs/platforms/whonix","sidebar":"tutorialSidebar"},{"id":"profiles/availability-status","path":"/docs/profiles/availability-status","sidebar":"tutorialSidebar"},{"id":"profiles/change-name","path":"/docs/profiles/change-name","sidebar":"tutorialSidebar"},{"id":"profiles/change-password","path":"/docs/profiles/change-password","sidebar":"tutorialSidebar"},{"id":"profiles/change-profile-image","path":"/docs/profiles/change-profile-image","sidebar":"tutorialSidebar"},{"id":"profiles/create-a-profile","path":"/docs/profiles/create-a-profile","sidebar":"tutorialSidebar"},{"id":"profiles/delete-profile","path":"/docs/profiles/delete-profile","sidebar":"tutorialSidebar"},{"id":"profiles/exporting-profile","path":"/docs/profiles/exporting-profile","sidebar":"tutorialSidebar"},{"id":"profiles/importing-a-profile","path":"/docs/profiles/importing-a-profile","sidebar":"tutorialSidebar"},{"id":"profiles/introduction","path":"/docs/profiles/introduction","sidebar":"tutorialSidebar"},{"id":"profiles/profile-info","path":"/docs/profiles/profile-info","sidebar":"tutorialSidebar"},{"id":"profiles/unlock-profile","path":"/docs/profiles/unlock-profile","sidebar":"tutorialSidebar"},{"id":"servers/create-server","path":"/docs/servers/create-server","sidebar":"tutorialSidebar"},{"id":"servers/delete-server","path":"/docs/servers/delete-server","sidebar":"tutorialSidebar"},{"id":"servers/edit-server","path":"/docs/servers/edit-server","sidebar":"tutorialSidebar"},{"id":"servers/introduction","path":"/docs/servers/introduction","sidebar":"tutorialSidebar"},{"id":"servers/share-key","path":"/docs/servers/share-key","sidebar":"tutorialSidebar"},{"id":"servers/unlock-server","path":"/docs/servers/unlock-server","sidebar":"tutorialSidebar"},{"id":"settings/appearance/change-language","path":"/docs/settings/appearance/change-language","sidebar":"tutorialSidebar"},{"id":"settings/appearance/light-dark-mode","path":"/docs/settings/appearance/light-dark-mode","sidebar":"tutorialSidebar"},{"id":"settings/appearance/streamer-mode","path":"/docs/settings/appearance/streamer-mode","sidebar":"tutorialSidebar"},{"id":"settings/appearance/ui-columns","path":"/docs/settings/appearance/ui-columns","sidebar":"tutorialSidebar"},{"id":"settings/behaviour/block-unknown-connections","path":"/docs/settings/behaviour/block-unknown-connections","sidebar":"tutorialSidebar"},{"id":"settings/behaviour/notification-content","path":"/docs/settings/behaviour/notification-content","sidebar":"tutorialSidebar"},{"id":"settings/behaviour/notification-policy","path":"/docs/settings/behaviour/notification-policy","sidebar":"tutorialSidebar"},{"id":"settings/experiments/clickable-links","path":"/docs/settings/experiments/clickable-links","sidebar":"tutorialSidebar"},{"id":"settings/experiments/file-sharing","path":"/docs/settings/experiments/file-sharing","sidebar":"tutorialSidebar"},{"id":"settings/experiments/group-experiment","path":"/docs/settings/experiments/group-experiment","sidebar":"tutorialSidebar"},{"id":"settings/experiments/image-previews-and-profile-pictures","path":"/docs/settings/experiments/image-previews-and-profile-pictures","sidebar":"tutorialSidebar"},{"id":"settings/experiments/message-formatting","path":"/docs/settings/experiments/message-formatting","sidebar":"tutorialSidebar"},{"id":"settings/experiments/qrcodes","path":"/docs/settings/experiments/qrcodes","sidebar":"tutorialSidebar"},{"id":"settings/experiments/server-hosting","path":"/docs/settings/experiments/server-hosting","sidebar":"tutorialSidebar"},{"id":"settings/introduction","path":"/docs/settings/introduction","sidebar":"tutorialSidebar"},{"id":"tor","path":"/docs/tor","sidebar":"tutorialSidebar"},{"id":"/category/getting-started","path":"/docs/category/getting-started","sidebar":"tutorialSidebar"},{"id":"/category/profiles","path":"/docs/category/profiles","sidebar":"tutorialSidebar"},{"id":"/category/conversations","path":"/docs/category/conversations","sidebar":"tutorialSidebar"},{"id":"/category/groups","path":"/docs/category/groups","sidebar":"tutorialSidebar"},{"id":"/category/servers","path":"/docs/category/servers","sidebar":"tutorialSidebar"},{"id":"/category/settings","path":"/docs/category/settings","sidebar":"tutorialSidebar"},{"id":"/category/appearance","path":"/docs/category/appearance","sidebar":"tutorialSidebar"},{"id":"/category/behaviour","path":"/docs/category/behaviour","sidebar":"tutorialSidebar"},{"id":"/category/experiments","path":"/docs/category/experiments","sidebar":"tutorialSidebar"},{"id":"/category/contribute","path":"/docs/category/contribute","sidebar":"tutorialSidebar"},{"id":"/category/platforms","path":"/docs/category/platforms","sidebar":"tutorialSidebar"}],"draftIds":[],"sidebars":{"tutorialSidebar":{"link":{"path":"/docs/intro","label":"intro"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en","es","de","it"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"},"es":{"label":"Espa\xf1ol","direction":"ltr","htmlLang":"es","calendar":"gregory","path":"es"},"de":{"label":"Deutsch","direction":"ltr","htmlLang":"de","calendar":"gregory","path":"de"},"it":{"label":"Italiano","direction":"ltr","htmlLang":"it","calendar":"gregory","path":"it"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.4.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.1"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(7961);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(c,{error:t}))}function c(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return r.createElement(p,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(l.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const d=e=>r.createElement(u,e);class p extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??d)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(405);function o(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7462),a=n(7294),o=n(3727),i=n(8780),l=n(2263),s=n(3919),c=n(412);const u=a.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:k}=(0,d.C)(),S=(0,a.useContext)(u),E=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>E.current));const _=p||f;const x=(0,s.Z)(_),C=_?.replace("pathname://","");let T=void 0!==C?(L=C,b&&(e=>e.startsWith("/"))(L)?k(L):L):void 0;var L;T&&x&&(T=(0,i.applyTrailingSlash)(T,{trailingSlash:y,baseUrl:w}));const A=(0,a.useRef)(!1),P=n?o.OL:o.rU,R=c.Z.canUseIntersectionObserver,N=(0,a.useRef)(),O=()=>{A.current||null==T||(window.docusaurus.preload(T),A.current=!0)};(0,a.useEffect)((()=>(!R&&x&&null!=T&&window.docusaurus.prefetch(T),()=>{R&&N.current&&N.current.disconnect()})),[N,T,R,x]);const I=T?.startsWith("#")??!1,D=!T||!x||I;return D||h||S.collectLink(T),D?a.createElement("a",(0,r.Z)({ref:E,href:T},_&&!x&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(P,(0,r.Z)({},v,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{E.current=e,R&&e&&x&&(N.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(N.current.unobserve(e),N.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))}))})),N.current.observe(e))},to:T},n&&{isActive:g,activeClassName:m}))}const f=a.forwardRef(p)},1875:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});const r=()=>null},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const l=i({message:t,id:n});return r.createElement(r.Fragment,null,a(l,o))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>o});var r=n(7294);const a=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(a),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return r.createElement(a.Provider,{value:i},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>g,gA:()=>p,_r:()=>u,Jo:()=>h,zh:()=>d,yW:()=>m,gB:()=>f});var r=n(6550),a=n(2263),o=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=function(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},u=()=>i("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=o.m),void 0===n&&(n={});const r=i(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function f(e){return d(e).versions}function m(e){const t=d(e);return l(t)}function g(e){const t=d(e),{pathname:n}=(0,r.TH)();return s(t,n)}function h(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(6726)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function o(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},7961:(e,t,n)=>{"use strict";n.d(t,{Z:()=>dt});var r=n(7294),a=n(6010),o=n(4763),i=n(1944),l=n(7462),s=n(6550),c=n(5999),u=n(5936);const d="__docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:a}=f();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var h=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(g,{className:v.skipToContent})}var w=n(6668),k=n(9689);function S(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:o=1.2,className:i,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:o},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const E={closeButton:"closeButton_CVFx"};function _(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,c.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",E.closeButton,e.className)}),r.createElement(S,{width:14,height:14,strokeWidth:3.1}))}const x={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(x.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const T={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function L(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,k.nT)();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return r.createElement("div",{className:T.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:T.announcementBarPlaceholder}),r.createElement(C,{className:T.announcementBarContent}),i&&r.createElement(_,{onClick:n,className:T.announcementBarClose}))}var A=n(2961),P=n(2466);var R=n(902),N=n(3102);const O=r.createContext(null);function I(e){let{children:t}=e;const n=function(){const e=(0,A.e)(),t=(0,N.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,R.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(O.Provider,{value:n},t)}function D(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(O);if(!e)throw new R.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,N.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:D(o)})),[a,o,t])}function j(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var F=n(2949),B=n(2389);function z(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function U(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function G(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const l=(0,B.Z)(),s=(0,c.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===o?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)($.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",$.toggleButton,!l&&$.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!l,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(z,{className:(0,a.Z)($.toggleIcon,$.lightToggleIcon)}),r.createElement(U,{className:(0,a.Z)($.toggleIcon,$.darkToggleIcon)})))}const q=r.memo(G),H={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function Z(e){let{className:t}=e;const n=(0,w.L)().navbar.style,a=(0,w.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:i}=(0,F.I)();return a?null:r.createElement(q,{className:t,buttonClassName:"dark"===n?H.darkNavbarColorModeToggle:void 0,value:o,onChange:i})}var V=n(1327);function W(){return r.createElement(V.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Y(){const e=(0,A.e)();return r.createElement("button",{type:"button","aria-label":(0,c.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(S,{color:"var(--ifm-color-emphasis-600)"}))}function K(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(W,null),r.createElement(Z,{className:"margin-right--md"}),r.createElement(Y,null))}var Q=n(9960),X=n(4996),J=n(3919);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const p=(0,X.Z)(a),f=(0,X.Z)(t),m=(0,X.Z)(o,{forcePrependBaseUrl:!0}),g=i&&o&&!(0,J.Z)(o),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,g&&r.createElement(te.Z,c&&{width:12,height:12}))};return o?r.createElement(Q.Z,(0,l.Z)({href:u?m:o},d,h)):r.createElement(Q.Z,(0,l.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(f)},d,h))}function re(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(ne,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?r.createElement("li",null,i):i}function ae(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...a}=e;const o=t?ae:re;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),le=n(8596),se=n(2263);function ce(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(ne,(0,l.Z)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",o)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(_e,(0,l.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:i,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,se.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(ne,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),f()}}),c.children??c.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(_e,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function pe(e){let{mobile:t=!1,...n}=e;const a=t?de:ue;return r.createElement(a,n)}var fe=n(4711);function me(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const ge="iconLanguage_nlXk";var he=n(1875);const be={searchBox:"searchBox_ZlJk"};function ve(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,be.searchBox)},t)}var ye=n(143),we=n(2802);var ke=n(373);const Se=e=>e.docs.find((t=>t.id===e.mainDocId));const Ee={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,se.Z)(),p=(0,fe.l)(),{search:f,hash:m}=(0,s.TH)(),g=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...a],h=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(pe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:ge}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(ve,{className:n},r.createElement(he.Z,null))},dropdown:pe,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,ye.Iw)(a),s=(0,we.vY)(t,a);return null===s?null:r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.path===s.path||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,ye.Iw)(a),s=(0,we.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...o}=e;const i=(0,we.lO)(a)[0],s=t??i.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(oe,(0,l.Z)({},o,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...u}=e;const{search:d,hash:p}=(0,s.TH)(),f=(0,ye.Iw)(n),m=(0,ye.gB)(n),{savePreferredVersionName:g}=(0,ke.J)(n),h=[...o,...m.map((e=>{const t=f.alternateDocVersions[e.name]??Se(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>g(e.name)}})),...i],b=(0,we.lO)(n)[0],v=t&&h.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&h.length>1?void 0:Se(b).path;return h.length<=1?r.createElement(oe,(0,l.Z)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(pe,(0,l.Z)({},u,{mobile:t,label:v,to:y,items:h,isActive:a?()=>!1:void 0}))}};function _e(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=Ee[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function xe(){const e=(0,A.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(_e,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ce(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Te(){const e=0===(0,w.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Ce,{onClick:()=>t.hide()}),t.content)}function Le(){const e=(0,A.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(j,{header:r.createElement(K,null),primaryMenu:r.createElement(xe,null),secondaryMenu:r.createElement(Te,null)}):null}const Ae={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Pe(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Re(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,w.L)(),i=(0,A.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,P.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+c{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,"aria-label":(0,c.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Ae.navbarHideable,!s&&Ae.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Pe,{onClick:i.toggle}),r.createElement(Le,null))}var Ne=n(8780);const Oe={errorBoundaryError:"errorBoundaryError_a6uf"};function Ie(e){return r.createElement("button",(0,l.Z)({type:"button"},e),r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function De(e){let{error:t}=e;const n=(0,Ne.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Oe.errorBoundaryError},n)}class Me extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const je="right";function Fe(e){let{width:t=30,height:n=30,className:a,...o}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Be(){const{toggle:e,shown:t}=(0,A.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(Fe,null))}const ze={colorModeToggle:"colorModeToggle_DEke"};function Ue(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(Me,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(_e,e)))))}function $e(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Ge(){const e=(0,A.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??je)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement($e,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Be,null),r.createElement(W,null),r.createElement(Ue,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(Ue,{items:a}),r.createElement(Z,{className:ze.colorModeToggle}),!o&&r.createElement(ve,null,r.createElement(he.Z,null)))})}function qe(){return r.createElement(Re,null,r.createElement(Ge,null))}function He(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,c=(0,X.Z)(n),u=(0,X.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(Q.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?u:a}:{to:c},s),o,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function Ze(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(He,{item:t}))}function Ve(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(Ze,{key:t,item:e})))))}function We(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Ve,{key:t,column:e}))))}function Ye(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function Ke(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(He,{item:t})}function Qe(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(Ke,{item:e}),t.length!==n+1&&r.createElement(Ye,null))))))}function Xe(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(We,{columns:t}):r.createElement(Qe,{links:t})}var Je=n(941);const et={footerLogoLink:"footerLogoLink_BH7S"};function tt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(Je.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function nt(e){let{logo:t}=e;return t.href?r.createElement(Q.Z,{href:t.href,className:et.footerLogoLink,target:t.target},r.createElement(tt,{logo:t})):r.createElement(tt,{logo:t})}function rt(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function at(e){let{style:t,links:n,logo:o,copyright:i}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(o||i)&&r.createElement("div",{className:"footer__bottom text--center"},o&&r.createElement("div",{className:"margin-bottom--sm"},o),i)))}function ot(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(at,{style:o,links:n&&n.length>0&&r.createElement(Xe,{links:n}),logo:a&&r.createElement(nt,{logo:a}),copyright:t&&r.createElement(rt,{copyright:t})})}const it=r.memo(ot),lt=(0,R.Qc)([F.S,k.pl,P.OC,ke.L5,i.VC,function(e){let{children:t}=e;return r.createElement(N.n2,null,r.createElement(A.M,null,r.createElement(I,null,t)))}]);function st(e){let{children:t}=e;return r.createElement(lt,null,t)}function ct(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Ie,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(De,{error:t})))))}const ut={mainWrapper:"mainWrapper_z2l0"};function dt(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.t)(),r.createElement(st,null,r.createElement(i.d,{title:s,description:c}),r.createElement(y,null),r.createElement(L,null),r.createElement(qe,null),r.createElement("div",{id:d,className:(0,a.Z)(h.k.wrapper.main,ut.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(ct,e)},t)),!n&&r.createElement(it,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),o=n(9960),i=n(4996),l=n(2263),s=n(6668),c=n(941);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=a.createElement(c.Z,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:c}}=(0,s.L)(),{imageClassName:d,titleClassName:p,...f}=e,m=(0,i.Z)(c?.href||"/"),g=n?"":t,h=c?.alt??g;return a.createElement(o.Z,(0,r.Z)({to:m},f,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:h,imageClassName:d}),null!=n&&a.createElement("b",{className:p},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(5742);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var r=n(7462),a=n(7294),o=n(6010),i=n(2389),l=n(2949);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function c(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:c,className:u,alt:d,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,f.map((e=>a.createElement("img",(0,r.Z)({key:e,src:c[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],u)},p)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>s,z:()=>h});var r=n(7462),a=n(7294),o=n(412),i=n(1442);const l="ease-in-out";function s(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),o=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:o}}const c={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?c:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const o=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){if((0,i.n)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??l}`,height:`${t}px`}}function s(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return d(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(s(),requestAnimationFrame((()=>{e.style.height=c.height,e.style.overflow=c.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{s()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function f(e){if(!o.Z.canUseDOM)return e?c:u}function m(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return p({collapsibleRef:c,collapsed:n,animation:o}),a.createElement(t,{ref:c,style:s?void 0:f(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(c.current,n),i?.(n))},className:l},r)}function g(e){let{collapsed:t,...n}=e;const[o,i]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,a.useLayoutEffect)((()=>{o&&s(t)}),[o,t]),o?a.createElement(m,(0,r.Z)({},n,{collapsed:l})):null}function h(e){let{lazy:t,...n}=e;const r=t?g:m;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>f});var r=n(7294),a=n(2389),o=n(12),i=n(902),l=n(6668);const s=(0,o.WA)("docusaurus.announcement.dismiss"),c=(0,o.WA)("docusaurus.announcement.id"),u=()=>"true"===s.get(),d=e=>s.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,o]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{o(u())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(p.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(p);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>h,S:()=>g});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),c="theme",u=(0,i.WA)(c),d={light:"light",dark:"dark"},p=e=>e===d.dark?d.dark:d.light,f=e=>a.Z.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),m=e=>{u.set(p(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(f(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=u.get();null!==t&&i(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[a,i])}();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>h});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(2802),s=n(902),c=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.WA)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.WA)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.WA)(u(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const f=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(f.Provider,{value:n},t)}function h(e){let{children:t}=e;return l.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(f);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.m);const t=(0,a.zh)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(i.Provider,{value:o},t)}function s(){const e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>l,q:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t,version:n}=e;return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(null===e)throw new a.i6("DocsVersionProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(7294),a=n(3102),o=n(7524),i=n(6550),l=(n(1688),n(902));function s(e){!function(e){const t=(0,i.k6)(),n=(0,l.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6668);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,c.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[i,l]=(0,r.useState)(!1);s((()=>{if(i)return l(!1),!1}));const u=(0,r.useCallback)((()=>{l((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&l(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:i})),[e,n,u,i])}function p(e){let{children:t}=e;const n=d();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new l.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>c});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){return a.Z.canUseDOM?window.innerWidth>i?o.desktop:o.mobile:o.ssr}const s=!1;function c(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1442:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{n:()=>r})},2802:(e,t,n)=>{"use strict";n.d(t,{MN:()=>x,Wl:()=>m,_F:()=>v,cE:()=>p,jA:()=>g,xz:()=>f,hI:()=>_,lO:()=>k,vY:()=>E,oz:()=>S,s1:()=>w});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(4477),c=n(1116);function u(e){return Array.from(new Set(e))}var d=n(8596);const p=!!i._r;function f(e){const t=(0,s.E)();if(!e)return;const n=t.docs[e];if(!n)throw new Error(`no version doc found by id=${e}`);return n}function m(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=m(t);if(e)return e}}}function g(){const{pathname:e}=(0,a.TH)(),t=(0,c.V)();if(!t)throw new Error("Unexpected: cant find current sidebar in context");const n=y({sidebarItems:t.items,pathname:e,onlyCategories:!0}).slice(-1)[0];if(!n)throw new Error(`${e} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`);return n}const h=(e,t)=>void 0!==e&&(0,d.Mg)(e,t),b=(e,t)=>e.some((e=>v(e,t)));function v(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||b(e.items,t))}function y(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function w(){const e=(0,c.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>u([t,n,a].filter(Boolean))),[t,n,a])}function S(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function E(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${u(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function _(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),i=t.routes,l=i.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:c}}function x(e){return e.filter((e=>"category"!==e.type||!!m(e)))}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,VC:()=>f});var r=n(7294),a=n(6010),o=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),c=n(2263);function u(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const u=function(e){const{siteConfig:t}=(0,c.Z)(),{title:n,titleDelimiter:r}=t;return e?.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,s.C)(),p=i?d(i,{absolute:!0}):void 0;return r.createElement(o.Z,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),l)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function f(e){let{children:t}=e;const n=l(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,a.Z)(o,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>c,Ql:()=>s,i6:()=>l,zX:()=>o});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function o(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>l});var r=n(7294),a=n(723),o=n(2263);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>s,RF:()=>d});var r=n(7294),a=n(412),o=n(2389),i=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function c(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,o.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&at&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>a});n(2263);const r="default";function a(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>s});n(7294),n(1688);const r="localStorage";function a(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function s(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=o(t?.persistence);return null===n?l:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),a({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),a({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>o});var r=n(2263),a=n(6550);function o(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:o}}=(0,r.Z)(),{pathname:i}=(0,a.TH)(),l=o===n?e:e.replace(`/${o}/`,"/"),s=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),a=n(6550),o=n(902);function i(e){const t=(0,a.TH)(),n=(0,o.D9)(t),i=(0,o.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(a,o)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;ta});const a=function(){for(var e,t,n=0,a="";n{"use strict";n.d(t,{lX:()=>w,q_:()=>C,ob:()=>f,PP:()=>L,Ep:()=>p});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r=0;p--){var f=i[p];"."===f?o(i,p):".."===f?(o(i,p),d++):d&&(o(i,p),d--)}if(!c)for(;d--;d)i.unshift("..");!c||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(2177);function s(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function f(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=f(n);a&&a!==m&&e(t,a,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,a,o,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),c=o.querySelector(r.barSelector),u=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,i(e,u,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),c=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&f(a),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var o,i,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s{var r=n(5826);e.exports=f,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=p;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",u=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],p=n[1],f=n.index;if(l+=e.slice(i,f),i=f+d.length,p)l+=p[1];else{var m=e[i],g=n[2],h=n[3],b=n[4],v=n[5],y=n[6],w=n[7];l&&(r.push(l),l="");var k=null!=g&&null!=m&&m!==g,S="+"===y||"*"===y,E="?"===y||"*"===y,_=n[2]||u,x=b||v;r.push({name:h||o++,prefix:g||"",delimiter:_,optional:E,repeat:S,partial:k,asterisk:!!w,pattern:x?c(x):w?".*":"[^"+s(_)+"]+?"})}}return i{"use strict";n.d(t,{Z:()=>o});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);E+=S.value.length,S=S.next){var _=S.value;if(t.length>e.length)return;if(!(_ instanceof a)){var x,C=1;if(v){if(!(x=o(k,E,e,b))||x.index>=e.length)break;var T=x.index,L=x.index+x[0].length,A=E;for(A+=S.value.length;T>=A;)A+=(S=S.next).value.length;if(E=A-=S.value.length,S.value instanceof a)continue;for(var P=S;P!==t.tail&&(Ad.reach&&(d.reach=I);var D=S.prev;if(N&&(D=s(t,D,N),E+=N.length),c(t,D,C),S=s(t,D,new a(p,h?r.tokenize(R,h):R,y,R)),O&&s(t,S,O),C>1){var M={cause:p+","+m,reach:I};i(e,t,n,S.prev,E,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function c(e,t,n){for(var r=t.next,a=0;a"+o.content+""},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n0)){var l=p(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s=0&&f(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function c(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,s(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,u={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return u[n]=a,n})).join(""),n,r),p=Object.keys(u);return i=0,function e(t){for(var n=0;n=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=p[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var s=o.substring(0,l),d=c(u[a]),f=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),f){var g=[f];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(//g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r*\.{3}(?:[^{}]|)*\})/.source;function o(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(a);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=i(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=o.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=o[a],d=n.tokenStack[u],p="string"==typeof c?c:c.content,f=t(r,u),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(m+f.length),v=[];g&&v.push.apply(v,i([g])),v.push(h),b&&v.push.apply(v,i([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&i(c.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const o=a},9901:e=>{e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041a\u0443\u041c\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:(e,t,n)=>{const r=n(9901),a=n(9642),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(6500).resolve(t)],delete Prism.languages[e],n(6500)(t),o.add(e)}))}i.silent=!1,e.exports=i},6726:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6726},6500:(e,t,n)=>{var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6500},9642:e=>{"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,r=e.length;n "));var l={},s=e[r];if(s){function c(t){if(!(t in e))throw new Error(r+" depends on an unknown component "+t);if(!(t in l))for(var i in a(t,o),l[t]=!0,n[t])l[i]=!0}t(s.require,c),t(s.optional,c),t(s.modify,c)}n[r]=l,o.pop()}}return function(e){var t=n[e];return t||(a(e,r),t=n[e]),t}}function a(e){for(var t in e)return!0;return!1}return function(o,i,l){var s=function(e){var t={};for(var n in e){var r=e[n];for(var a in r)if("meta"!=a){var o=r[a];t[a]="string"==typeof o?{title:o}:o}}return t}(o),c=function(e){var n;return function(r){if(r in e)return r;if(!n)for(var a in n={},e){var o=e[a];t(o&&o.alias,(function(t){if(t in n)throw new Error(t+" cannot be alias for both "+a+" and "+n[t]);if(t in e)throw new Error(t+" cannot be alias of "+a+" because it is a component.");n[t]=a}))}return n[r]||r}}(s);i=i.map(c),l=(l||[]).map(c);var u=n(i),d=n(l);i.forEach((function e(n){var r=s[n];t(r&&r.require,(function(t){t in d||(u[t]=!0,e(t))}))}));for(var p,f=r(s),m=u;a(m);){for(var g in p={},m){var h=s[g];t(h&&h.modify,(function(e){e in d&&(p[e]=!0)}))}for(var b in d)if(!(b in u))for(var v in f(b))if(v in u){p[b]=!0;break}for(var y in m=p)u[y]=!0}var w={getIds:function(){var e=[];return w.load((function(t){e.push(t)})),e},load:function(t,n){return function(t,n,r,a){var o=a?a.series:void 0,i=a?a.parallel:e,l={},s={};function c(e){if(e in l)return l[e];s[e]=!0;var a,u=[];for(var d in t(e))d in n&&u.push(d);if(0===u.length)a=r(e);else{var p=i(u.map((function(e){var t=c(e);return delete s[e],t})));o?a=o(p,(function(){return r(e)})):r(e)}return l[e]=a}for(var u in n)c(u);var d=[];for(var p in s)d.push(l[p]);return i(d)}(f,u,t,n)}};return w}}();e.exports=t},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),o=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n