# Qortal Q-Apps & QDN Websites — Developer & LLM Guide
**Revision:** 2026-07-14
**Audience:** Developers and AI assistants building Q-Apps and WEBSITE resources on [Qortal](https://github.com/qortal)
**Scope:** `qortalRequest`, QDN, packaging, Hub deployment, and common production patterns
---
## Navigation
| § | Topic | Read when… |
|---|--------|------------|
| [0](#0-for-llms-start-here) | For LLMs | You are an AI loading this as context |
| [1](#1-mental-model) | Mental model | First time on Qortal / QDN |
| [2](#2-website-vs-app) | WEBSITE vs APP | Choosing service type or debugging 404 vs SPA routing |
| [3](#3-qdn-coordinates) | QDN coordinates | Publishing, fetching, or linking resources |
| [4](#4-service-types) | Service types | Picking IMAGE / JSON / DOCUMENT / APP / … |
| [5](#5-qortalrequest-bridge) | `qortalRequest` | Wallet, publish, encrypt, navigate |
| [6](#6-fetch-and-rest) | `fetch` & REST | Public reads without wallet |
| [7](#7-packaging-and-publishing) | Packaging | Zip layout, Vite, grey-screen fixes |
| [8](#8-linking-and-deep-links) | Linking | `qortal://`, SPA routing, hash deep links |
| [9](#9-hub-integration) | Hub integration | Auth, iframes, mobile, bridge patterns |
| [10](#10-ecosystem-and-conventions) | Ecosystem | Cross-app identifiers and reference Q-Apps |
| [11](#11-source-repos) | Source repos | Gitea, GitHub, official docs |
| [12](#12-pitfalls) | Pitfalls | Debugging checklist |
| [13](#13-security) | Security | Trust model |
| [14](#14-workflows) | Workflows | Step-by-step new Q-App / WEBSITE |
| [15](#15-skeleton) | Skeleton | Copy-paste starter |
| [16](#16-llm-system-prompt) | System prompt | Paste into another LLM |
---
## 0. For LLMs: start here
1. Read **§1–§2** before generating architecture — confusing WEBSITE and APP causes most routing bugs.
2. Use **`qortalRequest`** for wallet, signing, publish, encrypt, and payments; use **relative `fetch()`** for anonymous public reads (§6).
3. Before publish/search code: read **§3, §6, §12** (identifiers, search normalization, UTF-8 base64).
4. Before shipping a zip: read **§7** (flat `dist/`, `base: "./"`, no CDN).
5. When the user's Hub/Core version matters, **verify action names** in [qortal.dev/docs/q-apps](https://qortal.dev/docs/q-apps) or Core `q-apps.js` — do not invent parameters.
**Default artifact:** single-file HTML for small tools; **Vite + flat zip** for production SPAs.
**Authority order when sources conflict:**
1. User's running **Qortal Core + Hub version**
2. [Q-Apps.md](https://github.com/Qortal/qortal/blob/master/Q-Apps.md) in Core
3. [qortal.dev/docs/q-apps](https://qortal.dev/docs/q-apps)
4. This guide (patterns and pitfalls — not a byte-perfect API dump)
---
## 1. Mental model
| Term | Meaning |
|------|---------|
| **Qortal Core** | Node software: chain validation, QDN storage, **REST API** |
| **Hub / Mobile / Extension** | User UIs that embed Q-Apps and inject **`qortalRequest`** |
| **QDN** | Qortal Data Network — resources indexed on-chain, payload mostly off-chain (SHA-256 verified) |
| **Registered name** | On-chain name tied to an account; **required to publish** from a Q-App |
| **Resource** | `{ name, service, identifier? }` + data; **latest publish wins** for the same triple |
| **Q-App** | Static web app (HTML/JS/CSS), usually a **zip** with **`index.html` at root**, service **`APP`** |
| **WEBSITE** | Multi-file site on QDN, service **`WEBSITE`** — different routing (§2) |
**Typical Q-App constraints:** no private backend with secrets; identity is **wallet address** + optional **name**; ship assets **in the zip** (offline/CSP-safe).
---
## 2. WEBSITE vs APP
| | **WEBSITE** | **APP** |
|---|-------------|---------|
| **Missing file path** | **404** | Falls through to **`index.html`** (SPA) |
| **Use for** | Visitor-facing static or multi-page sites | Interactive apps, builders, marketplaces, client routers |
| **Examples** | Portfolio site, published blog layout | Wallet UI, map tool, shop front-end |
**Rule:** Client-side router + app behaviour → **`APP`**. Mostly static pages with real 404s for bad URLs → **`WEBSITE`**.
**SPA asset trap:** Hub may open `/render/APP/YourName` **without** a trailing slash, so `./assets/index.js` resolves against `/render/APP/` and **404s**. Fixes:
- Ensure a **trailing slash** on the app URL, or
- Inject `` pointing at the app root (only when you understand the URL shape), or
- Use absolute-to-root paths that match how your Hub serves the resource.
Rebuild and re-zip after any HTML or bundler config change.
---
## 3. QDN coordinates
Every QDN object:
- **`name`** — publisher's registered name (controls update rights)
- **`service`** — `IMAGE`, `JSON`, `APP`, `WEBSITE`, `DOCUMENT`, `BLOG_POST`, …
- **`identifier`** — optional; distinguishes multiple resources per name+service
**Default resource:** main website or app for a name — omit `identifier` or use `"default"`.
**Shared identifiers:** deterministic cross-app locations (e.g. avatar: service `THUMBNAIL`, identifier `qortal_avatar` + user `name`).
**App namespaces:** prefix identifiers with your app slug: `myapp_config_v1`, `myapp_post_`. QDN is permissionless — **validate payload schema**; never trust identifier alone.
---
## 4. Service types
Condensed from [qortal.dev](https://qortal.dev/docs/q-apps). Sizes are per-service limits where documented.
| Service | Role | Typical limit |
|---------|------|----------------|
| `JSON` | Small structured metadata | **25 KB** |
| `DOCUMENT` | Larger text/JSON documents | 500 MB general cap |
| `DOCUMENT_PRIVATE` (801) | Encrypted documents | Private |
| `IMAGE` / `THUMBNAIL` | Media | 10 MB / 500 KB |
| `FILE` / `VIDEO` / `AUDIO` | Binaries | Large |
| `WEBSITE` / `APP` | Multi-file zips | APP **50 MB** |
| `BLOG_POST` / `MAIL` / `MESSAGE` | Ecosystem apps | varies |
| `CHAIN_COMMENT` | Tiny on-chain payload | **239 B** |
**Single-file vs multi-file:** `JSON`, `IMAGE`, etc. → one payload (`data64` or `file`). `WEBSITE`, `APP`, `GIF_REPOSITORY` → many files; **`filepath`** required on fetch.
**Publishing multi-file WEBSITE/APP from inside a Q-App:** still **limited or unavailable** in many Hub builds — publish via Hub UI; **fetch** multi-file resources **is** supported. Verify your target version.
**Private services** (`*_PRIVATE`, numeric 801, etc.): encrypted for recipient; decrypt with wallet via `DECRYPT_DATA` or group variants.
---
## 5. `qortalRequest` bridge
Injected by Core/Hub into embedded pages. Returns a **Promise** — always **`try/catch`**. Timeouts are **per-action** in Core `q-apps.js`; fix payload size and batching rather than wrapping everything in long timeouts.
**Host variables:** `window._qdnTheme` (`light`|`dark`), `window._qdnContext` (e.g. `gateway`).
### 5.1 Feature detection
```javascript
async function qr(payload) {
const req = window.qortalRequest ?? window.parent?.qortalRequest;
if (typeof req !== "function") throw new Error("Open inside Qortal Hub");
return req(payload);
}
```
Resolve the bridge from `window`, then `parent`, then `top` when running in nested iframes.
### 5.2 Identity (gesture-gated)
| Action | Purpose |
|--------|---------|
| `GET_USER_ACCOUNT` | Wallet address + public key — **user approval**; call from a **button**, not on first paint |
| `GET_ACCOUNT_NAMES` | Names for an address |
| `GET_ACCOUNT_DATA` | Account record |
| `GET_NAME_DATA` | Name owner and metadata |
**Publish gate:** user must **own** a registered name.
### 5.3 QDN read
| Action | Purpose |
|--------|---------|
| `FETCH_QDN_RESOURCE` | Load resource; add `filepath` for multi-file; `encoding: "base64"` when needed |
| `SEARCH_QDN_RESOURCES` | Discover resources; use `prefix: true` for identifier prefixes; **minimal payload** |
| `LIST_QDN_RESOURCES` | List by name/service (richer filters than search in some builds) |
| `GET_QDN_RESOURCE_URL` | URL for `` / fetch (e.g. `/arbitrary/...`) |
| `GET_QDN_RESOURCE_STATUS` | Build/load status (`READY`, percent loaded) — probe without full fetch |
| `GET_QDN_RESOURCE_METADATA` | Title, tags, category without full payload |
| `GET_QDN_RESOURCE_PROPERTIES` | filename, mimeType, size |
**Search normalization:** cores return array **or** `{ resources | results | entries | hits | data: [...] }` — coerce to array. Unknown JSON keys on search → **empty results**; strip optional fields if search mysteriously fails.
### 5.4 QDN write
| Action | Purpose |
|--------|---------|
| `PUBLISH_QDN_RESOURCE` | Single file / `data64`; `name` must be owned |
| `PUBLISH_MULTIPLE_QDN_RESOURCES` | Batch publish — feature-detect; fewer approval rounds |
**UTF-8 JSON → base64** — never raw `btoa(JSON.stringify(obj))` on Unicode text:
```javascript
function b64Utf8(obj) {
const bytes = new TextEncoder().encode(JSON.stringify(obj));
let bin = "";
for (const b of bytes) bin += String.fromCharCode(b);
return btoa(bin);
}
```
### 5.5 Navigation & Hub UI
| Action / pattern | Purpose |
|------------------|---------|
| `LINK_TO_QDN_RESOURCE` | Open QDN resource in Hub |
| `OPEN_NEW_TAB` | New tab with URL or `qortal://` link |
| `OPEN_PROFILE` | Open peer profile |
| `SET_TAB` (via `postMessage`) | Hub tab switch — `{ action: 'SET_TAB', requestedHandler: 'UI', payload: { service, name, identifier?, path? } }` |
| `QDN_RESOURCE_DISPLAYED` | Tell Hub what resource is shown (address bar / copy-link) — `{ action, service, name, path? }` |
| `SET_TAB_NOTIFICATIONS` | Badge count on tab |
| `NAVIGATION_HISTORY` | Back/forward integration (Hub-dependent) |
### 5.6 Groups, polls, payments
| Action | Notes |
|--------|-------|
| `LIST_GROUPS` / `JOIN_GROUP` / `GET_GROUPS_WITH_MEMBER` | Group membership |
| `CREATE_POLL` / `VOTE_ON_POLL` | `pollOptions` must be **array**; `pollName` must be unique |
| `SEND_COIN` / `TRANSFER_ASSET` / `SEND_PAYMENT` | User approval; **confirm params** on target Hub version |
| `SIGN_TRANSACTION` | Hub-signed tx, then broadcast via REST `/transactions/process` |
| `SEARCH_TRANSACTIONS` | Payment matching — `message` field often missing; match by reference/type |
### 5.7 Encryption
| Action | Purpose |
|--------|---------|
| `ENCRYPT_DATA` | `file` or `base64`; optional `publicKeys` for group |
| `DECRYPT_DATA` | Ciphertext base64 + counterparty `publicKey` |
| `ENCRYPT_QORTAL_GROUP_DATA` / `DECRYPT_QORTAL_GROUP_DATA` | Group-scoped encryption |
Use **separate identifier namespaces** for encrypted blobs.
### 5.8 Lists (local UI state)
`GET_LIST_ITEMS`, `ADD_LIST_ITEMS`, `DELETE_LIST_ITEM` — per-user lists in Hub, not global QDN.
### 5.9 Mobile (Qortal Go)
| Action / URL | Purpose |
|--------------|---------|
| `SAVE_FILE` | Save `blob` + `filename` natively — mobile WebViews often **ignore** anchor/blob downloads |
| `/arbitrary/…?attachment=true` | Native download listener on some mobile builds |
Detect mobile via user-agent when choosing download strategy.
### 5.10 Chain & misc
`FETCH_BLOCK`, `GET_BALANCE`, `GET_BLOCK_HEIGHT`, `GET_PRICE`, `DEPLOY_AT`, `GET_AT`, notifications permission actions — see [qortal.dev](https://qortal.dev/docs/q-apps) for the full list.
---
## 6. `fetch` and REST
Inside Hub, **relative** `fetch("/names/foo")` hits the user's node API — good for **public reads** (blocks, names, arbitrary endpoints).
**Limitation:** `fetch` does not know the logged-in wallet; personalized or signing flows need **`qortalRequest`**.
Do **not** hardcode `http://127.0.0.1:12391` in shipped apps.
**QDN search modes (REST):** `mode=ALL` vs `mode=LATEST` — wrong mode → duplicates or wrong counts.
**Reference:** [api.qortal.org/api-documentation](https://api.qortal.org/api-documentation/) — cross-check field names when debugging bridge vs REST.
**Local preview (varies by Core):** `http://localhost:12391/render/APP/?preview=true`
---
## 7. Packaging and publishing
### 7.1 Zip layout (non-negotiable)
```
my-app.zip
├── index.html ← at zip root
├── manifest.json
├── assets/
│ ├── index-xxxxx.js
│ └── index-xxxxx.css
└── … (fonts, images, workers)
```
- Zip **contents** of `dist/`, not a `dist/` folder wrapper.
- **`manifest.json`:** `"main": "index.html"`, title, version, category.
- Paths: **`./assets/...`**, never `/assets/...`.
- Avoid `` unless you are deliberately fixing APP path resolution (§2).
- Vite: `base: "./"`.
- **Ship fonts/JS in-bundle** — no required CDN.
- Case-sensitive paths; prefer `[a-z0-9._-]`.
### 7.2 Workflow
1. `npm run build` → `dist/` (or equivalent)
2. `(cd dist && zip -r ../MyApp.zip .)`
3. Hub → load zip → **Preview** before QDN publish
4. Publish service **`APP`** (or **`WEBSITE`** via Hub for end-user sites)
5. Open `qortal://APP/` or `qortal://WEBSITE//`
### 7.3 Grey screen / eternal “Loading…”
| Cause | Fix |
|-------|-----|
| `assets/index-*.js` 404 | Flat zip, `base: "./"`, rebuild |
| Absolute `/assets/` paths | Relative `./assets/` |
| Stale hashed files | Full rebuild + fresh zip |
| `crossorigin` on scripts | Some Hub builds fail script load — remove if needed |
---
## 8. Linking and deep links
### 8.1 `qortal://` protocol
```text
qortal://{service}/{name}/{identifier?}/{path?}
```
Examples:
- `qortal://WEBSITE/MySite` — home
- `qortal://WEBSITE/MySite/gallery` — sub-page
- `qortal://APP/MyQApp`
- `qortal://THUMBNAIL/MyName/qortal_avatar`
Use `default` in path when you need explicit no-identifier semantics.
### 8.2 SPA routing inside Hub
Published apps often run under paths like `/render/WEBSITE//` or `/render/APP//`. Use **pathname** segments for sub-pages and **`history.pushState` / `popstate`** for in-app navigation without leaving the Hub.
**Hash deep links (optional):** SPAs may use `location.hash` for anchors (e.g. `#section-id`). If you use multiple hash prefixes (e.g. `#folder-…` and `#folderdir-…`), parse **longest match first** — naive `startsWith('folder-')` breaks when one prefix is a substring of another.
Preserve intentional hash fragments when calling `history.replaceState` for pathname cleanup.
### 8.3 Programmatic navigation
Prefer `LINK_TO_QDN_RESOURCE` or `SET_TAB` postMessage for cross-app opens.
---
## 9. Hub integration
### 9.1 Authentication
- `GET_USER_ACCOUNT` only works **inside Hub** (or via a bridge stub that forwards to `parent`).
- Opening built `index.html` in a normal browser **cannot** complete wallet auth.
- If `parent === top` and only a stub exists, wallet calls fail — user must open the app from Hub.
- **Do not** auto-call `GET_USER_ACCOUNT` on page load; use an explicit **Connect** / **Authenticate** button.
- **Embedded Q-Apps in iframes:** parent page may need a **message relay** that forwards `qortalRequest` to the Hub; if inner auth still fails, open the target in a **new Hub tab**.
### 9.2 Bridge wrapper pattern
Centralize all bridge calls in one module. Typical resolution order:
```text
window.qortalRequest → parent.qortalRequest → top.qortalRequest
```
Wrap with short-timeout and long-timeout helpers (publishes and payments often need longer limits). Always `try/catch`.
### 9.3 Preview mode
```javascript
if (typeof qortalRequest !== "function" && typeof window.parent?.qortalRequest !== "function") {
// Show "Preview mode" — mock reads only; never fake successful payments
}
```
### 9.4 Hub copy-link / address bar
Multi-page WEBSITE apps can notify the Hub what sub-path is displayed via `QDN_RESOURCE_DISPLAYED`, so copy-link matches the page the user sees. Optionally maintain `` with the matching `qortal://WEBSITE//` form.
---
## 10. Ecosystem and conventions
Well-known **reference Q-Apps** on GitHub (study zip layout and `qortalRequest` usage):
| Project | Repo | Typical services |
|---------|------|------------------|
| Q-Mail | [Qortal/q-mail](https://github.com/Qortal/q-mail) | `MAIL`, `MAIL_PRIVATE` |
| Q-Share | [Qortal/q-share](https://github.com/Qortal/q-share) | `FILE`, `DOCUMENT` |
| Q-Tube | [Qortal/q-tube](https://github.com/Qortal/q-tube) | `VIDEO`, `BLOG_POST` |
| Q-Shop | [Qortal/q-shop](https://github.com/Qortal/q-shop) | `STORE`, `PRODUCT`, payments |
**Cross-app conventions:**
| Identifier / pattern | Used for |
|---------------------|----------|
| `qortal_avatar` + `THUMBNAIL` | User avatar image |
| `myapp_` prefix on identifiers | App-scoped JSON search |
| `BLOG_POST` + Q-Blog identifiers | Blog content blocks |
| `FILE` + `qfile_…` identifiers | File attachments in blog/mail apps |
**Multi-app ecosystems:** Some products publish a **WEBSITE** for visitors plus separate **APP** tools plus **JSON/DOCUMENT** indexes for discovery. Use versioned schema strings in JSON (e.g. `myapp-index-v1`) and document identifiers in your app's README.
---
## 11. Source repos
### 11.1 Gitea (community)
| URL | Use |
|-----|-----|
| [gitea.qortal.link](https://gitea.qortal.link) | Community Gitea — browse and host Qortal-related projects |
Search Gitea for Q-Apps, Hub forks, and site builders. Clone URLs follow `https://gitea.qortal.link//.git`.
### 11.2 GitHub (official org)
| Repo | Use |
|------|-----|
| [Qortal/qortal](https://github.com/Qortal/qortal) | Core, **`Q-Apps.md`**, **`q-apps.js`** (timeouts, actions) |
| [Qortal/Qortal-Hub](https://github.com/Qortal/Qortal-Hub) | Desktop Hub |
| [Qortal/qapp-core](https://github.com/Qortal/qapp-core) | Optional npm helpers |
| [Qortal/q-mail](https://github.com/Qortal/q-mail), [q-share](https://github.com/Qortal/q-share), [q-tube](https://github.com/Qortal/q-tube), [q-shop](https://github.com/Qortal/q-shop) | Reference apps |
### 11.3 Official documentation
| URL | Use |
|-----|-----|
| [qortal.dev/docs/q-apps](https://qortal.dev/docs/q-apps) | **`qortalRequest`** reference (authoritative for actions) |
| [api.qortal.org/api-documentation](https://api.qortal.org/api-documentation/) | REST / node API |
| [Q-Apps.md](https://github.com/Qortal/qortal/blob/master/Q-Apps.md) | Protocol: routing, resources, linking |
---
## 12. Pitfalls
| Problem | Fix |
|---------|-----|
| Grey screen / Loading forever | Network tab: `assets/index-*.js` must be **200**; flat zip, `base: "./"` |
| `/assets/...` 404 on APP | Trailing slash / `` / relative paths |
| Auto `GET_USER_ACCOUNT` on load | Use **Connect** button |
| `btoa(JSON.stringify)` on Unicode | §5.4 UTF-8 safe base64 |
| `SEARCH_*` not an array | Normalize to array |
| Extra fields on search → `[]` | Minimal search payload |
| `JSON` service > 25 KB | Use `FILE` / `DOCUMENT` |
| Unprefixed identifiers | `appslug_type_id` |
| Multi-file publish from Q-App | Use Hub UI; verify version |
| `CREATE_POLL` options as string | **Array** of `{ optionName }` |
| Hardcoded localhost API | Relative `fetch` only |
| External CDN for core JS | Bundle in zip |
| Unsanitized QDN HTML → XSS | Escape / sanitize |
| `Promise.all` on hundreds of fetches | Bounded concurrency |
| Hub iframe wallet isolation | Open in new tab / message relay |
| Mobile blob download | `SAVE_FILE` or `?attachment=true` |
| Overlapping hash prefixes | Parse longest prefix first |
| Payment succeeded, notify failed | Treat payment and notification as separate steps |
---
## 13. Security
- **Never** collect seed phrases or private keys.
- Treat all QDN JSON as **untrusted** — validate schema and sizes.
- Explain publishes, payments, and decrypt actions **before** calling `qortalRequest`.
- Rate-limit retries; distinguish user cancel vs technical errors.
---
## 14. Workflows
### 14.1 New Q-App
1. Choose stack: single HTML vs Vite/React (or similar).
2. Scaffold `index.html`, `manifest.json`, relative paths only.
3. Central bridge module for all `qortalRequest` calls.
4. Connect button → `GET_USER_ACCOUNT` → `GET_ACCOUNT_NAMES` → gate publish.
5. Design identifier scheme + JSON schemas.
6. Reads: `FETCH_QDN_RESOURCE` / `SEARCH_QDN_RESOURCES` with normalization.
7. Writes: `PUBLISH_QDN_RESOURCE` with UTF-8 `data64`.
8. Test: root URL, deep link, no-name wallet, publish propagation delay.
9. Build → flat zip → Hub Preview → publish `APP`.
### 14.2 New WEBSITE (visitor site)
1. Static HTML/CSS/JS, relative paths.
2. Publish via Hub under an owned name → service **`WEBSITE`**.
3. Link: `qortal://WEBSITE//...`
4. If the product needs SPA routing and heavy `qortalRequest` use throughout, consider **`APP`** instead (§2).
### 14.3 Inter-app integration
1. Define stable **identifier prefixes** and JSON schema versions.
2. Publish discovery metadata as small **JSON** or **DOCUMENT** resources.
3. Read partner apps via `SEARCH_QDN_RESOURCES` with `prefix: true`.
4. Open partner resources with `qortal://` links or `LINK_TO_QDN_RESOURCE`.
5. Never assume identifier alone proves origin — validate payload shape.
---
## 15. Skeleton
Minimal single-file Q-App (teaching reference):
```html
My Q-App
My Q-App
```
---
## 16. LLM system prompt
Paste as system instructions for another model:
```text
You build Qortal Q-Apps: static web apps using qortalRequest for wallet/QDN/signing and relative fetch() for public Core reads.
Official API: https://qortal.dev/docs/q-apps — verify action names against the user's Hub/Core version.
Protocol reference: https://github.com/Qortal/qortal/blob/master/Q-Apps.md
REST reference: https://api.qortal.org/api-documentation/
Community repos: https://gitea.qortal.link and https://github.com/qortal
Rules:
- No unless deliberately fixing Hub APP path resolution.
- Relative paths (./assets/...) and bundler base "./".
- index.html at zip root; ship fonts/JS in-bundle; no required CDN.
- GET_USER_ACCOUNT only after explicit user gesture. No registered name → explain publish cannot proceed.
- Prefix QDN identifiers with app slug; validate all fetched JSON; UTF-8 safe base64 for publishes.
- Normalize SEARCH_QDN_RESOURCES to an array; minimal search payload if results empty.
- JSON service ≤25 KB; large data → FILE/IMAGE/DOCUMENT.
- try/catch all qortalRequest; never handle seeds/private keys.
- Preview mode when bridge missing — mock reads only, never fake payments.
- WEBSITE = 404 on bad paths; APP = SPA fallback to index.html.
- Mobile: SAVE_FILE for blob downloads when anchor download fails.
```
---
## Maintenance
- Bump **revision date** when Core/Hub changes `qortalRequest` contracts materially.
- Re-check multi-file publish support after major Hub releases.
- Keep links to [qortal.dev](https://qortal.dev/docs/q-apps), [api.qortal.org](https://api.qortal.org/api-documentation/), and [gitea.qortal.link](https://gitea.qortal.link) current.
---
*End of guide.*