pzp-wiki/guide/intro/index.html

16 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-intro">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v2.4.1">
<title data-rh="true">PZP Docs | PZP</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://pzp.wiki/img/pzp-butts.jpeg"><meta data-rh="true" name="twitter:image" content="https://pzp.wiki/img/pzp-butts.jpeg"><meta data-rh="true" property="og:url" content="https://pzp.wiki/guide/intro"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="PZP Docs | PZP"><meta data-rh="true" name="description" content="What is &quot;PZP&quot;:"><meta data-rh="true" property="og:description" content="What is &quot;PZP&quot;:"><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://pzp.wiki/guide/intro"><link data-rh="true" rel="alternate" href="https://pzp.wiki/guide/intro" hreflang="en"><link data-rh="true" rel="alternate" href="https://pzp.wiki/guide/intro" hreflang="x-default"><link rel="stylesheet" href="/assets/css/styles.8cac783c.css">
<link rel="preload" href="/assets/js/runtime~main.bd244c3a.js" as="script">
<link rel="preload" href="/assets/js/main.cdb9f0b2.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div role="region" aria-label="Skip to main content"><a class="skipToContent_I4kl" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/img/pzp-butts.jpeg" alt="PZP logo" class="themedImage_DSLm themedImage--light_GmUB"><img src="/img/pzp-butts.jpeg" alt="PZP logo" class="themedImage_DSLm themedImage--dark_FA9L"></div><b class="navbar__title text--truncate">PZP</b></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/guide/intro">Guide</a></div><div class="navbar__items navbar__items--right"><a href="https://codeberg.org/pzp" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Code<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_Bfrr"><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"></path></svg></a><div class="toggle__aBh colorModeToggle_Vabb"><button class="clean-btn toggleButton_NAbc toggleButtonDisabled_CyXE" type="button" disabled="" title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live="polite"><svg viewBox="0 0 24 24" width="24" height="24" class="lightToggleIcon_tSon"><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"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" class="darkToggleIcon_V8Do"><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"></path></svg></button></div><div class="searchBox_le0k"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_mdP2 docsWrapper_fFqs"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_ZIlh" type="button"></button><div class="docPage_DJij"><aside class="theme-doc-sidebar-container docSidebarContainer_BPRz"><div class="sidebarViewport_ysM_"><div class="sidebar_lfv_"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_dqkg"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" href="/guide/intro">PZP Docs</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist" aria-expanded="false" href="/guide/category/philosophy">Philosophy</a><button aria-label="Toggle the collapsible sidebar category &#x27;Philosophy&#x27;" type="button" class="clean-btn menu__caret"></button></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist" aria-expanded="false" href="/guide/category/concepts">Concepts</a><button aria-label="Toggle the collapsible sidebar category &#x27;Concepts&#x27;" type="button" class="clean-btn menu__caret"></button></div></li></ul></nav></div></div></aside><main class="docMainContainer_mXIk"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_rOHj"><div class="docItemContainer_2fo2"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_hJFX" aria-label="Breadcrumbs"><ul class="breadcrumbs" itemscope="" itemtype="https://schema.org/BreadcrumbList"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_c9DA"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link" itemprop="name">PZP Docs</span><meta itemprop="position" content="1"></li></ul></nav><div class="tocCollapsible_DJZ1 theme-doc-toc-mobile tocMobile_VZyR"><button type="button" class="clean-btn tocCollapsibleButton_l0Ri">On this page</button></div><div class="theme-doc-markdown markdown"><h1>PZP Docs</h1><p>What is &quot;PZP&quot;:</p><ul><li>A <a href="https://www.inkandswitch.com/local-first/" target="_blank" rel="noopener noreferrer">local-first</a> P2P protocol with 10 years of learnings baked in</li><li>Message formats + Message validation + RPC methods</li><li>If scuttlebutt is 🙂 then pzp is 😎 </li><li>No apps so far except for a <a href="https://codeberg.org/pzp/zooboard" target="_blank" rel="noopener noreferrer">demo app</a>, but it&#x27;s ready for developers to have fun with and hack on.</li></ul><h2 class="anchor anchorWithStickyNavbar_xehe" id="features">Features<a href="#features" class="hash-link" aria-label="Direct link to Features" title="Direct link to Features"></a></h2><ul><li>Peer to peer. PZP is designed in a way to avoid centralization of power.</li><li>Low storage expectations. Expecting users to store large amounts of data makes adoption on phones and old devices hard, and eventually risks centralization and corporate takeover when only resource rich users or even companies have enough resources needed to keep the network running.</li><li>Content/public-key adressed data. We try to avoid relying on DNS since that would put too much trust/pressure on single nodes.</li><li>Easy to use CRDT data structures like sets and dicts.</li><li><a href="https://www.inkandswitch.com/local-first/" target="_blank" rel="noopener noreferrer">Local-first</a></li><li>No DHTs or other <a href="https://handbook.scuttlebutt.nz/stories/design-challenge-avoid-centralization-and-singletons" target="_blank" rel="noopener noreferrer">singletons</a>.</li><li>First class multi-device and multi-app support. A user&#x27;s account ID is independent of what keypair(s) they choose to use, so keypairs can be added and rotated.</li><li>Partial replication using tangles (merkle-trees) and <a href="https://github.com/AljoschaMeyer/bamboo#links-and-entry-verification" target="_blank" rel="noopener noreferrer">lipmaa links</a>.</li><li>Message deletion (can leave nothing, or only metadata).</li><li>Trust based (friend to friend) with a simple invite system.</li></ul><h3 class="anchor anchorWithStickyNavbar_xehe" id="how-pzp-is-different-from-ssb-secure-scuttlebutt">How PZP is different from <a href="https://scuttlebutt.nz/" target="_blank" rel="noopener noreferrer">SSB (Secure Scuttlebutt)</a><a href="#how-pzp-is-different-from-ssb-secure-scuttlebutt" class="hash-link" aria-label="Direct link to how-pzp-is-different-from-ssb-secure-scuttlebutt" title="Direct link to how-pzp-is-different-from-ssb-secure-scuttlebutt"></a></h3><ul><li>Storage is designed to not grow indefinitely. By default (of course overridable) an app&#x27;s storage shouldn&#x27;t go above 100MB.</li><li>Multi device/app support from the start. Every device/app has its own keypair. They&#x27;re connected together into one identity using an Account tangle. The Account tangle&#x27;s root message ID is the account&#x27;s identifier.</li><li>One account or even keypair can post messages concurrently (forking) without problem. Because there aren&#x27;t linear feeds, everything is in tangles, including state updates like e.g. username changes.</li><li>Deletion is possible. The data contents of a message is separate from the message metadata, and only the metadata + hash of the data is signed.</li><li>When messages are getting signed they get serialized according to <a href="https://tools.ietf.org/html/rfc8785" target="_blank" rel="noopener noreferrer">RFC 8785</a>.</li><li>Easy to use invites</li></ul><h3 class="anchor anchorWithStickyNavbar_xehe" id="how-pzp-is-different-from-nostr">How PZP is different from Nostr<a href="#how-pzp-is-different-from-nostr" class="hash-link" aria-label="Direct link to How PZP is different from Nostr" title="Direct link to How PZP is different from Nostr"></a></h3><ul><li>keys are not shared across devices</li><li>sig-chains - you know if you&#x27;re missing content in PZP</li><li>trust based - invite only</li></ul><h2 class="anchor anchorWithStickyNavbar_xehe" id="tangles">Tangles<a href="#tangles" class="hash-link" aria-label="Direct link to Tangles" title="Direct link to Tangles"></a></h2><p>Tangles control how messages are organised. They provide a way to group, and causally sort (partially), which is important for replication.</p><p>Basics of tangles in PZP: it&#x27;s a directed acyclic graph (DAG) which aims to be as linear as possible</p><p>There are 3 sorts of tangles:</p><ul><li>Account - a tangle which weaves (device) keys and defines capabilities / permissions of these</li><li>Feed - a tangle where all messages are from valid devices (as defined by an Account), and scoped to a particular domain<ul><li>e.g. all post messages from &quot;mix&quot;</li><li>e.g. all chess messages from &quot;happy0&quot;</li></ul></li><li>Thread - a tangle where multiple Accounts are collaborating on some state<ul><li>e.g. all the messages making up a &quot;10th birthday gathering&quot;</li><li>e.g. all the messages in a discussion</li><li>e.g. all the messages in a shared shopping list</li></ul></li></ul><p>All tangles have</p><ul><li>a root / root message</li><li>an ID (the id of the root message of the tangle)</li><li>have tangle-data for causal ordering</li></ul><p>How the tangles differ</p><ul><li>the Account tangle has strict validation of messages (it is only valid to write to it if you&#x27;ve been given permission to)</li><li>a Feed root is deterministic! (only inputs are accountId + domain)</li></ul><h3 class="anchor anchorWithStickyNavbar_xehe" id="account-tangle">Account Tangle<a href="#account-tangle" class="hash-link" aria-label="Direct link to Account Tangle" title="Direct link to Account Tangle"></a></h3><p>The account tangle starts with a message which says &quot;This key is allowed to author messages on behalf of this account, and add further keys&quot;.</p><p>Subsequent messages in this tangle may add / remove capabilities for existing / new keys.</p><p>Messages in this tangle are verified by checking state they&#x27;re extending on</p><h3 class="anchor anchorWithStickyNavbar_xehe" id="feed-tangle">Feed Tangle<a href="#feed-tangle" class="hash-link" aria-label="Direct link to Feed Tangle" title="Direct link to Feed Tangle"></a></h3><p><em>Domain Tangle, AccountDomain Tangle</em></p><h3 class="anchor anchorWithStickyNavbar_xehe" id="thread-tangle">Thread Tangle<a href="#thread-tangle" class="hash-link" aria-label="Direct link to Thread Tangle" title="Direct link to Thread Tangle"></a></h3><p>TODO</p><h2 class="anchor anchorWithStickyNavbar_xehe" id="specifications">Specifications<a href="#specifications" class="hash-link" aria-label="Direct link to Specifications" title="Direct link to Specifications"></a></h2><h3 class="anchor anchorWithStickyNavbar_xehe" id="messages"><a href="https://codeberg.org/pzp/pzp-db/src/branch/master/protospec.md" target="_blank" rel="noopener noreferrer">Messages</a><a href="#messages" class="hash-link" aria-label="Direct link to messages" title="Direct link to messages"></a></h3><h3 class="anchor anchorWithStickyNavbar_xehe" id="replication"><a href="https://codeberg.org/pzp/pzp-sync/src/branch/master/protospec.md" target="_blank" rel="noopener noreferrer">Replication</a><a href="#replication" class="hash-link" aria-label="Direct link to replication" title="Direct link to replication"></a></h3><h3 class="anchor anchorWithStickyNavbar_xehe" id="invites"><a href="https://codeberg.org/pzp/pzp-invite/src/branch/master/protospec.md" target="_blank" rel="noopener noreferrer">Invites</a><a href="#invites" class="hash-link" aria-label="Direct link to invites" title="Direct link to invites"></a></h3><h3 class="anchor anchorWithStickyNavbar_xehe" id="sets"><a href="https://codeberg.org/pzp/pzp-set/src/branch/master/protospec.md" target="_blank" rel="noopener noreferrer">Sets</a><a href="#sets" class="hash-link" aria-label="Direct link to sets" title="Direct link to sets"></a></h3><h3 class="anchor anchorWithStickyNavbar_xehe" id="dicts"><a href="https://codeberg.org/pzp/pzp-dict/src/branch/master/protospec.md" target="_blank" rel="noopener noreferrer">Dicts</a><a href="#dicts" class="hash-link" aria-label="Direct link to dicts" title="Direct link to dicts"></a></h3><h2 class="anchor anchorWithStickyNavbar_xehe" id="further-exploration">Further exploration<a href="#further-exploration" class="hash-link" aria-label="Direct link to Further exploration" title="Direct link to Further exploration"></a></h2><h3 class="anchor anchorWithStickyNavbar_xehe" id="code">Code<a href="#code" class="hash-link" aria-label="Direct link to Code" title="Direct link to Code"></a></h3><p>PZP is not ready for end users yet but it&#x27;s stable enough for developers to have a fun time hacking with/on it. All the code is available <a href="https://codeberg.org/pzp" target="_blank" rel="noopener noreferrer">on codeberg</a></p><h3 class="anchor anchorWithStickyNavbar_xehe" id="sdk">SDK<a href="#sdk" class="hash-link" aria-label="Direct link to SDK" title="Direct link to SDK"></a></h3><p>We have <a href="https://codeberg.org/pzp/pzp-sdk" target="_blank" rel="noopener noreferrer">a simple SDK</a> that helps you get started making PZP apps.</p><h3 class="anchor anchorWithStickyNavbar_xehe" id="demo-app">Demo app<a href="#demo-app" class="hash-link" aria-label="Direct link to Demo app" title="Direct link to Demo app"></a></h3><p><a href="https://codeberg.org/pzp/zooboard" target="_blank" rel="noopener noreferrer">A demo app</a> demonstrating some PZP features. Take a look at the code for inspiration. Note that you probably have to be a developer to build and use it.</p></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://codeberg.org/pzp/pzp-wiki/src/branch/master/guide/guide/intro.md" target="_blank" rel="noreferrer noopener" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_8p0m" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_a6LJ"></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--next" href="/guide/category/philosophy"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Philosophy</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_CMAt thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#features" class="table-of-contents__link toc-highlight">Features</a><ul><li><a href="#how-pzp-is-different-from-ssb-secure-scuttlebutt" class="table-of-contents__link toc-highlight">How PZP is different from SSB (Secure Scuttlebutt)</a></li><li><a href="#how-pzp-is-different-from-nostr" class="table-of-contents__link toc-highlight">How PZP is different from Nostr</a></li></ul></li><li><a href="#tangles" class="table-of-contents__link toc-highlight">Tangles</a><ul><li><a href="#account-tangle" class="table-of-contents__link toc-highlight">Account Tangle</a></li><li><a href="#feed-tangle" class="table-of-contents__link toc-highlight">Feed Tangle</a></li><li><a href="#thread-tangle" class="table-of-contents__link toc-highlight">Thread Tangle</a></li></ul></li><li><a href="#specifications" class="table-of-contents__link toc-highlight">Specifications</a><ul><li><a href="#messages" class="table-of-contents__link toc-highlight">Messages</a></li><li><a href="#replication" class="table-of-contents__link toc-highlight">Replication</a></li><li><a href="#invites" class="table-of-contents__link toc-highlight">Invites</a></li><li><a href="#sets" class="table-of-contents__link toc-highlight">Sets</a></li><li><a href="#dicts" class="table-of-contents__link toc-highlight">Dicts</a></li></ul></li><li><a href="#further-exploration" class="table-of-contents__link toc-highlight">Further exploration</a><ul><li><a href="#code" class="table-of-contents__link toc-highlight">Code</a></li><li><a href="#sdk" class="table-of-contents__link toc-highlight">SDK</a></li><li><a href="#demo-app" class="table-of-contents__link toc-highlight">Demo app</a></li></ul></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Guide</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/guide/intro">Guide</a></li></ul></div><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://autonomous.zone/@pzp" target="_blank" rel="noopener noreferrer" class="footer__link-item">Mastodon<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_Bfrr"><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"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">More</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://codeberg.org/pzp" target="_blank" rel="noopener noreferrer" class="footer__link-item">Code<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_Bfrr"><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"></path></svg></a></li><li class="footer__item"><a href="https://codeberg.org/pzp/pzp-sdk" target="_blank" rel="noopener noreferrer" class="footer__link-item">SDK<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_Bfrr"><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"></path></svg></a></li><li class="footer__item"><a href="https://codeberg.org/pzp/zooboard" target="_blank" rel="noopener noreferrer" class="footer__link-item">Demo app<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_Bfrr"><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"></path></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2024 PZP contributors, licensed CC-BY-SA-4.0. Built with Docusaurus.</div></div></div></footer></div>
<script src="/assets/js/runtime~main.bd244c3a.js"></script>
<script src="/assets/js/main.cdb9f0b2.js"></script>
</body>
</html>