create-noy-db

Wizard + CLI tool for noy-db: scaffold a fresh Nuxt 4 + Pinia encrypted store, or add collections to an existing project. Invoke via `npm create noy-db`.
18,223
Install
npm install create-noy-db
Latest Version:0.9.0
License:Apache-2.0
Last Updated:Oct 14, 2026
Links: GitHub  ·  npm
Maintainer: vlanna
noy-db logo

noy-db

None Of Your DataBase

(formerly shortened as: "None Of Your Damn Business")

Your data. Your device. Your keys. Nobody else's server.

An encrypted, offline-first, serverless document store. The library lives inside your app, stores in whatever backend you choose, and nobody in the middle ever sees plaintext — not the cloud provider, not the sysadmin, not the database vendor. Not noy-db either.

npm License: Apache-2.0 Node.js TypeScript Runtime Deps Crypto


Start

npm create noy-db@latest      # one question, one file, an encrypted vault in the browser

Then noy-db doctor tells you what is configured and what is not yet, and noy-db add --list shows every store, framework, unlock method and export you can add. Docs, tutorials and the playground: noy-db.lanna.ai/start. Prefer no scaffold? pnpm add @noy-db/hub and the 30-second example below is the whole API you need on day one.

This repo is the core package tree. Showcases, playgrounds and recipes live in noy-db/docs and are served at noy-db.lanna.ai.


What makes noy-db different

  • 🔒 Hard privacy by construction. Stores only ever see ciphertext. AES-256-GCM with per-user keys derived from a secret via PBKDF2. Breach the cloud, subpoena the provider, lose the USB stick — every one of those surfaces already holds ciphertext. Zero crypto dependencies — only the Web Crypto API.
  • ☁️ Serverless, runs anywhere. No noy-db server. No Docker. No managed service. The library embeds in your app — 0 runtime deps; a put/get app ships ~95 kB gzip today (hub's root barrel; family#120 is the slimmer door), the Find-only query path alone is 28.8 kB. Works in Node 18+, Bun, Deno, every modern browser, Cloudflare Workers, Electron, mobile PWAs.
  • 📴 Offline-first. Every operation works without network. Sync when you want to, to whatever you want to. Single code path for online and offline — no "online mode" to toggle.
  • 👥 Multi-user, no auth server. 5 roles (owner / admin / operator / viewer / client), per-collection permissions, key rotation on revoke. The keyring travels with the data.
  • 🧩 One core, many bridges. @noy-db/hub is the encrypted document-store core. ~60 optional to-* / in-* / on-* / as-* / by-* / at-* packages let existing apps keep their preferred storage, framework, unlock method, export format, session-share transport, and server-side sealing host — without changing anything else.
  • 🔐 Advanced crypto features. Hierarchical per-record tiers, deterministic encryption for searchable indexes, WebRTC peer-to-peer sync, AES-256-GCM blob store with deduplication, HKDF-keyed ETags, hash-chained audit ledger.
  • ♻️ Hot resilience — any full replica heals the others. Lose or corrupt every store but one: when the survivor is online, lost stores re-fill from it and corrupted records re-align to it, with no backup involved. Backups (pods) are the other product — everything gone, or a state from the past. ⚠️ The guarantee holds once every writer is 0.9.0 or later (an older hub writes keyrings without the compare-and-swap guard and clobbers it), and it is witnessed against a cloud store; browser-store recovery is not yet independently witnessed.
  • 🧪 Thousand-plus tests, CI in under a minute. Every store / integration / auth / export package is mock-tested — CI runs without AWS, Google Drive, SFTP servers, or any real service.

@noy-db/hub is the trust boundary. Encryption happens in the core before data reaches any store. The to-*, in-*, on-*, as-*, and by-* bridges never see plaintext — zero-knowledge by construction.

Two trust boundaries. The at-* family is the one deliberate exception: a sealing-key host you control (Lambda, EC2, a worker) can decrypt the scoped slice it unseals — that's the point, so you can run server-side work for users who never hold a key. You trust it because it's your infrastructure and the key lives in your managed key store; least privilege via per-user sealed credentials. Offline-first by default; online when you want.

Pre-1.0 stance. The core privacy model, envelope format, keyrings, permissions, and query DSL are implemented and tested. Public APIs may still change based on adopter feedback before 1.0; data migrations and security-critical changes will be documented. No third-party cryptographic audit yet — that is a v1.0 target.


30-second vanilla example

The minimum — no framework, no cloud, nothing to install beyond @noy-db/hub:

import { createNoydb } from '@noy-db/hub'

const db = await createNoydb({       // zero-config: in-memory by default (built-in store)
  user: 'alice',
  secret: 'correct-horse-battery-staple',
})

const vault = await db.openVault('acme')
const invoices = vault.collection<{ id: string; amount: number }>('invoices')

await invoices.put('inv-001', { id: 'inv-001', amount: 1200 })
console.log(await invoices.get('inv-001'))   // { id: 'inv-001', amount: 1200 }

await db.close()                               // clears keys from memory

createNoydb() needs no store — it uses a built-in in-memory store by default (non-persistent). For tests wanting the fuller in-memory backend (adds listVaults/ping/tx), pass store: memoryStore({ full: true }) — same package, no extra install.

Swap storage with one line — keep the rest identical:

// Persist to disk
import { toFile } from '@noy-db/to-file'
store: toFile({ dir: './data' })

// Browser (IndexedDB)
import { toBrowserIdb } from '@noy-db/to-browser-idb'
store: toBrowserIdb()

Extended cloud and SQL backends (@noy-db/to-aws-dynamo, @noy-db/to-aws-s3, @noy-db/to-postgres, and 13 more) live in the noy-db-to companion repo — same npm names, separate install.

→ Full store catalog: Storage stores (to-*).


The 24-service catalog

A minimalist core (~6,500 LOC) plus 24 opt-in capabilities behind with*() strategy seams. Apps that don't import a strategy ship none of its code.

import { createNoydb } from '@noy-db/hub'
import { withHistory } from '@noy-db/hub/history'
import { withReduce } from '@noy-db/hub/reduce'
import { withBlobs } from '@noy-db/hub/blobs'

const db = await createNoydb({
  store: ...,
  user: ...,
  historyStrategy: withHistory(),     // versioning + ledger + time-machine
  reduceStrategy: withReduce(),       // sum/groupBy/avg
  blobsStrategy: withBlobs(),          // file attachments
  // ... 21 more available
})
Cluster Services
Read & Query indexing · joins · aggregate · live
Write & Mutate history · transactions · crdt
Derived data derivations · materialized-views · overlay-views
Data Shape blobs · i18n
Time & Audit periods · consent · guards
Snapshot & Portability shadow · bundle
Collaboration & Auth sync · team · session
Operations routing

→ Starter recipes: noy-db-docs/content/docs/recipes — personal-notebook · accounting-app · realtime-crdt-app · analytics-app


Try it — playground + showcases

Playground apps and the showcase suite now live in noy-db-docs:

  • playground/cli/ — guided 5-minute CLI walkthrough. Shows CRUD, multi-user, sync, backup.
  • playground/nuxt/ — runnable Nuxt 4 reference app (invoices, multi-tenant, biometric unlock, magic-link client portal).
  • showcases/ — 132 progressive end-to-end tests that double as tutorials. Numbered 00-49 across storage, multi-user, services, auth, exports, frameworks, and session-share transports — pick a feature and read the runnable code. Plus recipe tests verifying the starter applications.

The six package families

Each prefix reads as a preposition — the mental model stays the same as you scale from one-file vaults to multi-tenant cloud deployments.

Prefix Reads as What it is Catalog
to- "data goes to a backend" Storage destinations — the only piece that touches ciphertext on the wire. 2 essentials (to-file, to-browser-idb) on the core line; to-meter is a store WRAPPER and lives in noy-db/in beside its consumers, plus the built-in memoryStore() in the hub itself; extended cloud/SQL/remote-FS backends in noy-db-to. → stores.md
in- "runs in a framework" Framework integrations — thin reactive bindings. React, Next.js, Vue, Nuxt, Pinia, Svelte, Zustand, TanStack Query/Table, Yjs CRDT, LLM tool-calling. → integrations.md
on- "you get on via this method" Unlock / auth — composable primitives. Passkeys (WebAuthn), OIDC split-key, magic links, TOTP, email OTP, recovery codes, Shamir k-of-n, duress + honeypot. → auth.md
as- "export as XLSX / JSON / …" Portable artefacts — two-tier authorisation with audit ledger. CSV, Excel, XML, JSON, NDJSON, SQL dump, PDF blobs, ZIP, and the encrypted .noydb bundle. → exports.md
by- "sync by way of …" Session-share transports — live-state bridges between realms. @noy-db/by-peer (WebRTC peers, renamed from @noy-db/p2p) and @noy-db/by-tabs (BroadcastChannel multi-tab) ship today; by-server, by-room reserved. → transports.md
at- "sealed at a trusted host" Sealing-key providers — the online complement to offline-first. A host you control unseals a scoped slice for server-side work (it can decrypt what it unseals — the one non-zero-knowledge family). at-env, at-macos-keychain, at-aws-kms, at-gcp-kms, at-azure-keyvault. → at-hosts.md

Plus the hub (@noy-db/hub) and one command line, create-noy-db: npm create noy-db scaffolds a project and noy-db does everything after (add, user, backup, pod inspect/verify, describe, config, monitor, inspect). @noy-db/cli is a deprecated redirect.

Maturity at a glance. @noy-db/hub is Core — security-critical, highest test bar. to-file, to-browser-idb are Recommended essentials that ship here, and an in-memory store is built into the hub. Cloud/SQL backends (to-aws-dynamo, to-aws-s3, to-postgres, etc.) are in noy-db-to — same quality bar, separate repo. Most other satellites are Bridges — thin adapters proven in tests but less production-battled. P2P, niche stores, and unusual auth modes are Experimental — useful, validate before depending on them.


Schema-driven UI

Two sibling packages — @noy-db/ui and @noy-db/ui-nuxt — ship from a separate repo (noy-db/ui) but publish under the same @noy-db npm org. They are a domain-free, schema-driven search/list/detail layer that renders itself from collection.describe() — the field-metadata surface the hub exposes (labels, types, dictKey enums, PII masking, i18n, JSON-Schema) — so you don't hand-write forms or tables for each collection. @noy-db/ui is the framework-agnostic engine plus design tokens; @noy-db/ui-nuxt is the Nuxt module and components built on it. They stay on the right side of the trust boundary: the UI only ever touches records the hub has already decrypted in-process, never ciphertext or keys, and they peer-depend on @noy-db/hub by published-version range on their own independent release line.


Querying without SQL

The store never sees plaintext, so it never runs your query. The query DSL lives inside @noy-db/hub and runs after decryption — the storage backend stays a dumb, untrusted ciphertext store.

await invoices.query()
  .where('status', '==', 'issued')
  .where('clientId', '==', 'c-42')
  .orderBy('issuedAt', 'desc')
  .toArray()

// Intra-vault joins, live queries, aggregations, streaming
invoices.query().join<'client', Client>('clientId', { as: 'client' }).toArray()
invoices.query().where(...).live().subscribe(() => render())
invoices.query().groupBy('clientId').aggregate({ total: sum('amount') }).run()
for await (const r of invoices.scan()) { /* backpressure-friendly */ }

The DSL ships in four groups, and only the first is always loaded. @noy-db/hub — the import every example here uses — attaches all four, so nothing above changes. If you import @noy-db/hub/query directly to keep your bundle small, you get Find (where, or, and, filter, orderBy, limit, offset, page, after, first, toArray, count, exists, ids, toPlan) and add the rest a line at a time, once, anywhere in your app's entry:

import '@noy-db/hub/query/live'     // subscribe, live
import '@noy-db/hub/query/reduce'   // aggregate, groupBy, window, distinct, dateTrunc
import '@noy-db/hub/query/relate'   // joins, traverse, ancestorsOf, descendantsOf, explain

The methods and their types arrive together, so a call to a group you have not imported does not compile — and @noy-db/hub/query/all is the one-line way to take the lot. Measured on the Find-only path: 28.8 kB minified against 80.7 kB before the split.

The query terminals are synchronous. toArray(), ids(), page(), first(), count() and exists() return their value directly — T[], number, boolean — not a promise of it. Query runs over an already-decrypted in-memory cache, so by the time a plan executes there is nothing to await; the await in the example above is harmless (awaiting an array yields the array) and is what you should write, because on a collection that has not been loaded yet the terminal returns a pending result that hydrates when awaited and refuses any synchronous use — an unloaded collection is not an empty one. What does not work is .catch(): query().toArray().catch(fn) fails with "catch is not a function" on a loaded collection. Wrap the call in try / catch instead.

Two same-named methods elsewhere are async, and legitimately so, because they genuinely fetch: PartitionedQuery.toArray() (across partition legs) and the lazy-mode builder's collection.lazyQuery().toArray() (through the persisted index side-car). Both return Promise<T[]>.

Joins are intra-vault and core-side — no backend ever inspects plaintext fields. Cross-vault correlation is explicit via queryAcross. Huge relational workloads are still better served by a real database; noy-db is for sensitive, small-to-mid datasets where the trust boundary matters more than query throughput.

Private, AI-ready retrieval. On top of the query DSL, collection.retrieve(query) adds a ranked search tier that — like everything else — runs after decryption, so no plaintext, no embedding, and no query ever leaves the process. It layers from client-side lexical ranking, to an optional persisted lexical index, to encrypted-local semantic/vector search (cosine over locally-computed embeddings), to a hybrid mode that fuses lexical and semantic results with reciprocal-rank fusion. The fusion primitive (fuseRetrieval) is exported from @noy-db/hub/cargo (the klum orchestration seam), so an orchestrator can federate ranked result-sets across many vaults without any of them sharing plaintext.

const hits = await invoices.retrieve('overdue acme', { mode: 'hybrid', limit: 10 })

The 6-method store contract

get(vault, collection, id)
put(vault, collection, id, envelope, expectedVersion?)
delete(vault, collection, id)
list(vault, collection)
loadAll(vault)
saveAll(vault, data)

If your existing storage can implement these six methods, it can store noy-db ciphertext. These six are all that is REQUIRED — the kernel ships a built-in in-memory store (so store is optional for the in-memory case); the essential to-file and to-browser-idb ship here for persistence; to-memory, the fuller in-memory backend, and 18 more extended stores (SQL, cloud, remote-FS, personal drives) live in noy-db-to. A custom store is createStore(opts => ({ name, ...methods })).

⭐ Six more members are OPTIONAL, and each has a defined fallback — so a store implements only what its backend can do natively, and the hub degrades rather than refusing:

optional when absent
listPage? paged pull falls back to list + get in batches of the same size
listSince? the sync walks without a server-side cursor
getStoreTime? the hub uses local time
ping? reachability is inferred from the next real call
presencePublish? / presenceSubscribe? no presence channel; nothing else changes

Plus a capabilities? object (txAtomic, maxBlobBytes, …), where a declared capability the store does not implement is the one failure the conformance kit exists to catch. ⚠️ So "the 6-method contract" is shorthand for the required surface, not a count of the interface.


Install for common scenarios

# Development / testing — in-memory, no persistence (built-in; nothing to add)
pnpm add @noy-db/hub
# …and the optional half of the store contract (listVaults / ping / tx) is the
# same built-in store with an option — still nothing to add:
#   createNoydb({ store: memoryStore({ full: true }), ... })

# Local CLI / Node service — files on disk
pnpm add @noy-db/hub @noy-db/to-file

# Browser app with IndexedDB
pnpm add @noy-db/hub @noy-db/to-browser-idb

# Nuxt 4 + Pinia — the happy path (framework bindings: github.com/noy-db/in)
pnpm add @noy-db/in-nuxt @noy-db/in-pinia @noy-db/hub @noy-db/to-browser-idb @pinia/nuxt pinia

# React / Next.js
pnpm add @noy-db/in-nextjs @noy-db/in-react @noy-db/hub @noy-db/to-browser-idb

# Offline-first with cloud sync (cloud adapters from noy-db-to)
pnpm add @noy-db/hub @noy-db/to-file @noy-db/to-aws-dynamo

For starter applications see noy-db-docs/content/docs/recipes — four runnable recipes covering personal, accounting, real-time, and analytics shapes.

Release channels

noy-db ships through two npm dist-tags. The default install pulls the curated, themed releases; an opt-in @next channel carries in-flight features for early-adopter consumers.

# Stable — themed releases (default)
pnpm add @noy-db/hub

# Early-adopter — in-flight features, expect breakage between versions
pnpm add @noy-db/hub@next

Pre-1.0 (today): both channels can be ahead of where you'd expect a 0.x library to be — anything in @next is "actively maturing"; anything in @latest has at least passed a themed release gate. Post-1.0: @latest becomes a strict-SemVer contract, @next keeps its experimental nature.


Runs on whatever you've got

Platform Runtime Default backend
🖥️ Desktop (macOS / Linux / Windows) Node 18+, Bun, Deno to-file
📱 Mobile browser Safari 14+, Chrome 90+ to-browser-idb
🌐 Desktop browser Chrome, Firefox, Safari, Edge to-browser-idb
⚡ PWA / offline web app Service Worker + browser to-browser-idb
🖧 Server (headless) Node 18+ to-file / to-aws-dynamo / to-postgres (noy-db-to)
💾 USB stick / removable disk Any OS + any runtime to-file
🔌 Electron / Tauri Desktop shell to-file
☁️ Cloudflare Workers Edge JS to-cloudflare-d1 + to-cloudflare-r2 (noy-db-to)
🧪 Tests / CI Any JS runtime built-in memoryStore() — nothing to install

Minimum requirements: a JavaScript engine and the Web Crypto API. That's it.


Hard privacy is the point

In privacy engineering there's a distinction worth naming.

  • Soft privacy is a promise. A provider pledges to protect your data — by policy, by staff training, by a compliance certificate on the wall. You trust the policy, the people, the future owners, the jurisdiction, the subpoena response, the breach-response team on their worst day.
  • Hard privacy removes the need for that trust. Nobody else can break the promise because nobody else is in a position to. They don't have the keys. They never had the keys.

noy-db is a hard-privacy tool. The only party that can read a record is the party holding the secret. That holds whether your cloud is breached, a sysadmin inspects the table, a court compels the provider, a laptop is stolen, or a backup is left on café Wi-Fi — every one of those surfaces already holds ciphertext.

There is no "encrypted in transit, briefly decrypted at rest for processing" step. There is no support engineer at noy-db with a recovery key — we do not run a service and we do not possess any key. The KEK exists in your process memory for the length of a session and is destroyed when you call db.close().

This matters to an individual keeping private journals, medical notes, immigration paperwork, legal correspondence, or financial records. It matters a great deal more to an organisation that holds other people's sensitive data as a fiduciary — a law firm, an professional services firm, a clinic, a small newsroom, a union office, a humanitarian NGO — and cannot, in good conscience, hand that data to a third-party service whose incident response, jurisdiction, and future acquirer they don't control.

A note on the ethics of hard privacy

Strong encryption is a dual-use technology. The same guarantees that protect dissidents, journalists, abuse survivors, clinicians' patients, and every ordinary person's private life can also shield conduct that is unlawful or harmful. We do not pretend otherwise.

Our position: the capacity to keep one's own records, thoughts, and correspondence private from everyone else — including one's government, one's employer, and the company selling one the software — is foundational. It is bound up with personal autonomy itself, and it is a right, not a feature we chose to grant.

noy-db does not inspect your data. It cannot — that is the architectural point. What you choose to store in a noy-db vault, and what you do with it, is your business. If you are using noy-db in a context where you have legal or professional obligations — GDPR, PDPA, HIPAA, PCI-DSS, retention, lawful-access rules, auditability, tax record-keeping — those obligations remain yours to meet under the law of wherever you operate.


Encryption

Layer Algorithm Purpose
Key derivation PBKDF2-SHA256 (600K iterations) Secret → KEK
Key wrapping AES-KW (RFC 3394) KEK wraps/unwraps DEKs
Data encryption AES-256-GCM DEK encrypts records
IV generation CSPRNG Fresh 12-byte IV per write
Integrity HMAC-SHA256 Presence channel + blob eTags

Zero crypto dependencies. Everything uses crypto.subtle — built into Node 18+ and modern browsers.


Roles & permissions

Role Read Write Grant Revoke Export
owner all all all roles all yes
admin all all operator, viewer, client, admin admin and below yes
operator granted collections granted collections — — ACL-scoped
viewer all — — — yes
client granted collections — — — ACL-scoped

Every mutation (grant, revoke, rotate, elevate) writes a hash-chained audit ledger entry. Hierarchical per-record classification tiers (collection.elevate() / demote() / delegate() / invisibility / ghost modes) plus scoped tier-elevated handles (vault.elevate(tier, { ttlMs, reason }) for time-boxed privileged writes) are covered in the history and team services.


Not for

  • Million-row analytics workloads.
  • Server-side SQL over plaintext — the store is deliberately blind.
  • Workloads that need the storage backend itself to run joins, filters, or aggregations over plaintext.
  • Search-heavy workloads unless the searchable-index privacy tradeoff (opt-in deterministic encryption) is acceptable for your threat model.
  • Teams that need audited cryptography today — noy-db has not yet had a third-party cryptographic audit. That is a v1.0 target.

Serious use of noy-db is for sensitive, small-to-mid datasets where the privacy boundary matters more than query throughput.


Architecture

noy-db architecture overview — hub at the center, five satellite package families around it

Stores only see ciphertext. Encryption happens in core before data reaches any backend — a DynamoDB admin, an S3 bucket owner, or whoever finds the USB stick all see encrypted blobs.


International project, Global project

noy-db is an international open-source project. The first production consumer was an enterprise pilot — the library's design assumptions (offline-first, multi-user, sensitive domain data, per-tenant isolation, USB-based workflows for intermittent connectivity) come directly from that real-world deployment.

Multi-language data is a first-class concern, not an afterthought. The optional i18n service lets a single field hold values in multiple locales (i18nText({ languages: ['en', 'th', 'zh'] })), pairs enum-like fields with shared label dictionaries (dictKey('status', ['draft', 'paid']) resolving to per-locale labels), and resolves the right locale at read time without touching ciphertext on the wire. Dictionaries are themselves encrypted and versioned, so even your translation strings stay private. Records, dictionaries, and exports are Unicode-clean — Thai (ภาษาไทย), Chinese (中文), Arabic (العربية), Devanagari (हिंदी), Cyrillic, Hebrew, every script the Web Crypto API and your storage backend can carry. Locale-aware exports round-trip human-readable headers back to stable keys (the xlsx reader inverts dictionary labels on import; same for csv, json, ndjson, xml).


Dependencies

Almost every package has zero runtime dependencies, and none pulls in a heavyweight SDK. Things like @aws-sdk/client-dynamodb, ssh2, pg, mysql2, zustand, react, vue, @tanstack/query-core are peer dependencies — you already have them in your app.

The exceptions, stated rather than rounded off: as-xml and as-xlsx depend on fast-xml-parser; in-devtools-tui (noy-db/in) on ink and react; create-noy-db on its scaffolder toolchain. hub and in-nuxt depend only on a sibling @noy-db/* package on the same version line.

The hub package itself uses only crypto.subtle, which is built into every target runtime (Node ≥ 18, Bun, Deno, modern browsers, Cloudflare Workers).


Where to go next

If you want to… Read
see what's always-on (the floor) Core
browse the 24 opt-in services Services — the service index
copy a starter recipe Recipes — personal-notebook · accounting-app · realtime-crdt-app · analytics-app
pick a storage backend Storage stores
pick a framework integration Framework integrations
pick an unlock method Unlock methods
pick an export format Export formats
pick a session-share transport Session-share transports
see real workflows showcases/

License

Apache-2.0 © vLannaAi


Your data. Your device. Your keys. None Of Your DataBase.
(Originally, and still occasionally: "None Of Your Damn Business".)

Related Packages

@noy-db/in-nuxt

Nuxt 4 module for noy-db — auto-imports, SSR-safe runtime plugin, and the @noy-d...

18,164 0
@noy-db/in-pinia

Pinia integration for noy-db — defineNoydbStore() and the augmentation plugin fo...

19,220 0
create-graphql-markdown-docs

Create a new GraphQL API documentation site with GraphQL Markdown and Nuxt or Do...

691 181
@geoql/nuxt-doctor

CLI auditor for Nuxt 4 apps. Detects anti-patterns, AI-slop, and best-practice v...

14,295 7
vue-cli-plugin-pinia

Pinia plugin for vue-cli

109,692 41

Version History

Version Released License
0.9.0 Apache-2.0
0.8.0 Apache-2.0
0.3.4 MIT
0.3.2 MIT
0.3.1 MIT
Pre-releases (115)
Version Released License
0.10.0-pre.2 Apache-2.0
0.10.0-pre.1 Apache-2.0
0.10.0-pre.0 Apache-2.0
0.9.0-pre.2 Apache-2.0
0.9.0-pre.1 Apache-2.0