From bbde1fe996d0124e7e3ec2bb3c4000c9c4645d47 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Tue, 25 Jun 2024 02:58:35 +0300
Subject: [PATCH 1/7] dev env instructions

---
 ng-app/README.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ng-app/README.md b/ng-app/README.md
index 5a320b3..d5f90d9 100644
--- a/ng-app/README.md
+++ b/ng-app/README.md
@@ -111,6 +111,10 @@ Until I find out how to do this properly, if you are compiling the android app f
 export RANLIB=/Users/[user]/Library/Android/sdk/ndk/[yourNDKversion]/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ranlib
 ```
 
+On a linux setup, you will need to add the `glibc-devel.i386` package, see this [SO article](https://stackoverflow.com/questions/7412548/error-gnu-stubs-32-h-no-such-file-or-directory-while-compiling-nachos-source) for instructions for your distro.
+
+Before you can generate the APK, you will need to [configure Android Studio with your Signing keys.](https://web.archive.org/web/20240222072319/https://next--tauri.netlify.app/next/guides/distribution/sign-android/)
+
 to launch the dev app :
 
 ```

From eb50e2c90f00d3c29e36f3a12fce3a22414fdef8 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Mon, 1 Jul 2024 00:53:01 +0300
Subject: [PATCH 2/7] trying to fix bindgen on alpine

---
 ng-oxigraph/Cargo.toml        | 2 +-
 ng-storage-rocksdb/Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ng-oxigraph/Cargo.toml b/ng-oxigraph/Cargo.toml
index 031375f..e05a3fd 100644
--- a/ng-oxigraph/Cargo.toml
+++ b/ng-oxigraph/Cargo.toml
@@ -49,7 +49,7 @@ base64-url = "2.0.0"
 
 [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies]
 libc = "0.2"
-ng-rocksdb = { version = "0.21.0-ngpreview.4", git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git", branch = "master", features = [  ] }
+ng-rocksdb = { version = "0.21.0-ngpreview.5", git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git", branch = "master", features = [  ] }
 
 [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
 getrandom = "0.2.8"
diff --git a/ng-storage-rocksdb/Cargo.toml b/ng-storage-rocksdb/Cargo.toml
index eb32b25..ee49b54 100644
--- a/ng-storage-rocksdb/Cargo.toml
+++ b/ng-storage-rocksdb/Cargo.toml
@@ -20,4 +20,4 @@ ng-repo = { path = "../ng-repo", version = "0.1.0-preview.1" }
 git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git"
 branch = "master"
 features = [  ]
-version = "0.21.0-ngpreview.4"
+version = "0.21.0-ngpreview.5"

From 2bac7025fe9e8abebbf4b633118b7ce6d9aa871f Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Tue, 2 Jul 2024 00:00:55 +0300
Subject: [PATCH 3/7] Revert "trying to fix bindgen on alpine"

This reverts commit eb50e2c90f00d3c29e36f3a12fce3a22414fdef8.
---
 ng-oxigraph/Cargo.toml        | 2 +-
 ng-storage-rocksdb/Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ng-oxigraph/Cargo.toml b/ng-oxigraph/Cargo.toml
index e05a3fd..031375f 100644
--- a/ng-oxigraph/Cargo.toml
+++ b/ng-oxigraph/Cargo.toml
@@ -49,7 +49,7 @@ base64-url = "2.0.0"
 
 [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies]
 libc = "0.2"
-ng-rocksdb = { version = "0.21.0-ngpreview.5", git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git", branch = "master", features = [  ] }
+ng-rocksdb = { version = "0.21.0-ngpreview.4", git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git", branch = "master", features = [  ] }
 
 [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
 getrandom = "0.2.8"
diff --git a/ng-storage-rocksdb/Cargo.toml b/ng-storage-rocksdb/Cargo.toml
index ee49b54..eb32b25 100644
--- a/ng-storage-rocksdb/Cargo.toml
+++ b/ng-storage-rocksdb/Cargo.toml
@@ -20,4 +20,4 @@ ng-repo = { path = "../ng-repo", version = "0.1.0-preview.1" }
 git = "https://git.nextgraph.org/NextGraph/rust-rocksdb.git"
 branch = "master"
 features = [  ]
-version = "0.21.0-ngpreview.5"
+version = "0.21.0-ngpreview.4"

From 5d9849d8bce355d02e0a5a4be21752398bbafb66 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Thu, 4 Jul 2024 17:13:22 +0300
Subject: [PATCH 4/7] apps, classes, and locales

---
 Cargo.lock                                    |  18 +-
 Cargo.toml                                    |   3 +
 ng-app/src-tauri/Cargo.toml                   |   3 +-
 ng-app/src-tauri/src/lib.rs                   |   7 +
 ng-app/src/App.svelte                         |   6 +-
 ng-app/src/api.ts                             |   9 +
 ng-app/src/apps/JsonLdEditor.svelte           |   0
 ng-app/src/classes.ts                         | 873 ++++++++++++++++++
 ng-app/src/lib/CenteredLayout.svelte          |  11 +
 ng-app/src/lib/DataClassIcon.svelte           | 187 ++++
 ng-app/src/lib/Install.svelte                 |  28 +-
 ng-app/src/lib/Test.svelte                    |   1 +
 ng-app/src/lib/ZeraIcon.svelte                | 120 +++
 ng-app/src/routes/Install.svelte              |   6 +-
 ng-app/src/routes/{URI.svelte => NURI.svelte} |   2 +-
 ng-app/src/store.ts                           |  92 ++
 ng-app/src/zeras.ts                           | 629 +++++++++++++
 ng-net/src/app_protocol.rs                    |   4 +-
 ng-repo/src/types.rs                          |   5 +-
 ng-sdk-js/Cargo.toml                          |   1 +
 ng-sdk-js/src/lib.rs                          |   6 +
 ngone/web/src/routes/Install.svelte           |   2 +-
 22 files changed, 1982 insertions(+), 31 deletions(-)
 create mode 100644 ng-app/src/apps/JsonLdEditor.svelte
 create mode 100644 ng-app/src/classes.ts
 create mode 100644 ng-app/src/lib/DataClassIcon.svelte
 create mode 100644 ng-app/src/lib/ZeraIcon.svelte
 rename ng-app/src/routes/{URI.svelte => NURI.svelte} (95%)
 create mode 100644 ng-app/src/zeras.ts

diff --git a/Cargo.lock b/Cargo.lock
index 4b1ef7d..f550fea 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3290,6 +3290,7 @@ dependencies = [
  "serde",
  "serde_bytes",
  "serde_json",
+ "sys-locale",
  "tauri",
  "tauri-build",
  "tauri-plugin-window",
@@ -3408,7 +3409,7 @@ dependencies = [
  "serde",
  "sha1",
  "sha2 0.10.8",
- "siphasher 0.3.10",
+ "siphasher 1.0.1",
  "thiserror",
  "zstd",
 ]
@@ -3449,7 +3450,7 @@ dependencies = [
 [[package]]
 name = "ng-rocksdb"
 version = "0.21.0-ngpreview.4"
-source = "git+https://git.nextgraph.org/NextGraph/rust-rocksdb.git?branch=master#e566341c319eead6637b1aecce5e92136e946ae5"
+source = "git+https://git.nextgraph.org/NextGraph/rust-rocksdb.git?branch=master#f1ce2e345f3d729350a02bcffb47c526674edd85"
 dependencies = [
  "bindgen",
  "bzip2-sys",
@@ -3482,6 +3483,7 @@ dependencies = [
  "serde_bare",
  "serde_bytes",
  "serde_json",
+ "sys-locale",
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "wasm-bindgen-test",
@@ -5352,6 +5354,18 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "sys-locale"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0"
+dependencies = [
+ "js-sys",
+ "libc",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "system-configuration"
 version = "0.6.0"
diff --git a/Cargo.toml b/Cargo.toml
index bc843f9..aaca5cf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,6 +38,9 @@ documentation = "https://docs.nextgraph.org/"
 lto = true
 opt-level = 's'
 
+[profile.dev]
+opt-level = 2
+
 [patch.crates-io]
 # tauri = { git = "https://github.com/simonhyll/tauri.git",  branch="fix/ipc-mixup"}
 # tauri = { git = "https://git.nextgraph.org/NextGraph/tauri.git", branch="alpha.11-nextgraph", features = ["no-ipc-custom-protocol"] }
diff --git a/ng-app/src-tauri/Cargo.toml b/ng-app/src-tauri/Cargo.toml
index 8db8c84..0c9ba1a 100644
--- a/ng-app/src-tauri/Cargo.toml
+++ b/ng-app/src-tauri/Cargo.toml
@@ -27,7 +27,8 @@ tauri-build = { version = "2.0.0-alpha.8", features = [] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 serde_bytes = "0.11.7"
-async-std = {  version = "1.12.0", features = ["attributes", "unstable"] }
+async-std = { version = "1.12.0", features = ["attributes", "unstable"] }
+sys-locale = { version = "0.3.1" }
 ng-async-tungstenite = {  git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph",  features = ["async-std-runtime", "async-native-tls"] }
 tauri = { version = "2.0.0-alpha.14", features = [] }
 tauri-plugin-window = "2.0.0-alpha.1"
diff --git a/ng-app/src-tauri/src/lib.rs b/ng-app/src-tauri/src/lib.rs
index 8a28099..73db314 100644
--- a/ng-app/src-tauri/src/lib.rs
+++ b/ng-app/src-tauri/src/lib.rs
@@ -13,6 +13,7 @@ use std::fs::write;
 use async_std::stream::StreamExt;
 use serde::{Deserialize, Serialize};
 use serde_json::Value;
+use sys_locale::get_locales;
 use tauri::scope::ipc::RemoteDomainAccessScope;
 use tauri::utils::config::WindowConfig;
 use tauri::{path::BaseDirectory, App, Manager};
@@ -38,6 +39,11 @@ pub use mobile::*;
 
 pub type SetupHook = Box<dyn FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send>;
 
+#[tauri::command(rename_all = "snake_case")]
+async fn locales() -> Result<Vec<String>, ()> {
+    Ok(get_locales().filter(|lang| lang != "C").collect())
+}
+
 #[tauri::command(rename_all = "snake_case")]
 async fn test(app: tauri::AppHandle) -> Result<(), ()> {
     let path = app
@@ -490,6 +496,7 @@ impl AppBuilder {
             .plugin(tauri_plugin_window::init())
             .invoke_handler(tauri::generate_handler![
                 test,
+                locales,
                 wallet_gen_shuffle_for_pazzle_opening,
                 wallet_gen_shuffle_for_pin,
                 wallet_open_with_pazzle,
diff --git a/ng-app/src/App.svelte b/ng-app/src/App.svelte
index 82d63c4..e643f52 100644
--- a/ng-app/src/App.svelte
+++ b/ng-app/src/App.svelte
@@ -24,14 +24,14 @@
   import Home from "./routes/Home.svelte";
   import Test from "./routes/Test.svelte";
 
-  import URI from "./routes/URI.svelte";
+  import NURI from "./routes/NURI.svelte";
   import NotFound from "./routes/NotFound.svelte";
   import WalletCreate from "./routes/WalletCreate.svelte";
   import Invitation from "./routes/Invitation.svelte";
   import WalletLogin from "./routes/WalletLogin.svelte";
   import User from "./routes/User.svelte";
   import UserRegistered from "./routes/UserRegistered.svelte";
-  import Install from "./lib/Install.svelte";
+  import Install from "./routes/Install.svelte";
 
   import ng from "./api";
 
@@ -44,7 +44,7 @@
   routes.set("/user", User);
   routes.set("/user/registered", UserRegistered);
   if (import.meta.env.NG_APP_WEB) routes.set("/install", Install);
-  routes.set(/^\/ng(.*)/i, URI);
+  routes.set(/^\/did:ng(.*)/i, NURI);
   routes.set("*", NotFound);
 
   let unsubscribe = () => {};
diff --git a/ng-app/src/api.ts b/ng-app/src/api.ts
index 9d7da81..abdc710 100644
--- a/ng-app/src/api.ts
+++ b/ng-app/src/api.ts
@@ -97,6 +97,15 @@ const handler = {
                 };
                 //console.log(info,res);
                 return res;
+            } else if (path[0] === "locales") {
+                let from_rust = await tauri.invoke("locales",{});
+                let from_js = window.navigator.languages;
+                console.log(from_rust,from_js);
+                for (let lang of from_js) {
+                    if (!from_rust.includes(lang)) { from_rust.push(lang);}
+                }
+                return from_rust;
+
             } else if (path[0] === "disconnections_subscribe") {
                 let { getCurrent } = await import("@tauri-apps/plugin-window");
                 let callback = args[0];
diff --git a/ng-app/src/apps/JsonLdEditor.svelte b/ng-app/src/apps/JsonLdEditor.svelte
new file mode 100644
index 0000000..e69de29
diff --git a/ng-app/src/classes.ts b/ng-app/src/classes.ts
new file mode 100644
index 0000000..26f4642
--- /dev/null
+++ b/ng-app/src/classes.ts
@@ -0,0 +1,873 @@
+// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
+// All rights reserved.
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
+// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+// "post/rich", "post/md", "post/text", "post/html", "post/asciidoc", "page", "code", "code/*", "app", "app/z", "class", "schema", "schema/owl|rdfs|shacl|shex", "service", "service/rust", "service/deno", "contract", "app/n:xxx.xx.xx:", "app/o:",
+// "query/sparql", "query/graphql", "query/text", "query/web", 
+// "data/graph", "data/json", "data/array", "data/map", "data/xml", "data/table", "data/collection", "data/board", "data/grid", "data/geomap", 
+// "e/email", "e/web", "e/http://[url of class in ontology]", "e/rdf" (read-only cache of RDF fetched from web2.0)
+// "mc/text", "mc/link", "mc/card", "mc/pad", 
+// "doc/diagram","doc/chart", "doc/pdf", "doc/odf", "doc/latex", "doc/ps", "doc/music", "doc/maths", "doc/chemistry", "doc/braille", "doc/ancientscript",
+// "media/image", "media/reel", "media/album", "media/video", "media/audio", "media/song", "media/subtitle", "media/overlay",
+// "social/channel", "social/stream", "social/contact", "social/event", "social/calendar", "social/scheduler", "social/reaction"
+// "prod/task", "prod/project", "prod/issue", "prod/form", "prod/filling", "prod/cad", "prod/slides", "prod/question", "prod/answer", "prod/poll", "prod/vote"
+// "file", "file/iana/*", "file/gimp", "file/inkscape", "file/kdenlive", "file/blender", "file/openscad", "file/lyx", "file/scribus", "file/libreoffice",
+
+
+// application/vnd.api+json
+
+// application/activity+json
+
+// epub, dejavu, 
+// animation: snap, lottie, smil editor: https://github.com/HaikuTeam/animator/
+
+export const official_classes = {
+    "post/rich": {
+        "ng:crdt": "YXml",
+        "ng:n": "Post - Rich Text", // editor: y-ProseMirror, viewer: https://www.npmjs.com/package/prosemirror-to-html-js or https://prosemirror.net/docs/ref/version/0.4.0.html#toDOM https://prosemirror.net/docs/ref/version/0.4.0.html#toHTML
+        "ng:a": "A Post with Rich Text, including images, links, formatted text, and embeds of other content",
+        "ng:o": "n:g:z:post:rich",
+        "ng:w": "n:g:z:post_rich_editor",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["as:Article"],
+    },
+    "post/md": {
+        "ng:crdt": "YXml",
+        "ng:n": "Post - MarkDown", // editor y-MilkDown, viewer: https://github.com/wooorm/markdown-rs
+        "ng:a": "A Post with MarkDown, including images, links, formatted text, and embeds of other content",
+        "ng:o": "n:g:z:post:md",
+        "ng:w": "n:g:z:post_md_editor",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["file/iana/text/markdown", "code/markdown","as:Article"],
+    },
+    "post/text": {
+        "ng:crdt": "YText",
+        "ng:n": "Post - Plain Text",
+        "ng:a": "A Post with Plain Text",
+        "ng:o": "n:g:z:post:text",
+        "ng:w": "n:g:z:code_editor",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["file/iana/text/plain", "code/plaintext","as:Article"],
+    },
+    "post/html": {
+        "ng:crdt": "YXml",
+        "ng:n": "Post - TinyMCE",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:a": "A Post based on TinyMCE, including images, links, formatted text, and embeds of other content",
+        "ng:compat": ["as:Article"],
+    },
+    "post/asciidoc": { // display with https://github.com/asciidoctor/asciidoctor.js/
+        "ng:crdt": "YText",
+        "ng:n": "Post - AsciiDoc",
+        "ng:a": "A Post based on AsciiDoc format",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["as:Article"],
+    },
+    "page": {
+        "ng:crdt": "YXml",
+        "ng:n": "Page", // based on GrapeJS, VvvebJs, or Astro ?
+        "ng:a": "A Page and Site builder",
+        "ng:compat": [],
+    },
+    "code": {
+        "ng:crdt": "YText",
+        "ng:n": "Source Code", // edited with CodeMirror, displayed with highlight.js 
+        "ng:a": "A Source Code file. many languages supported",
+        "ng:o": "n:g:z:pre",
+        "ng:w": "n:g:z:code_editor",
+        "ng:compat": ["code/*","file/iana/text/javascript","file/iana/text/css","file/iana/text/html","file/iana/text/markdown", "file/iana/application/xml", "file/iana/application/yaml", "file/iana/text/xml", "file/iana/application/xhtml+xml"],
+    },
+    "app": {
+        "ng:n": "Official App",
+        "ng:a": "App provided by NextGraph platform",
+    },
+    "app/z": {
+        "ng:crdt": "Elmer",
+        "ng:n": "Application", // Editor: Monaco
+        "ng:a": "Create an Application based on NextGraph Framework",
+        "ng:o": "n:g:z:app_store",
+        "ng:w": "n:g:z:app_editor",
+        "ng:include": ["schema/*","service/*","code","file"],
+        "ng:compat": ["code/svelte"],
+    },
+    "class": {
+        "ng:crdt": "Graph",
+        "ng:n": "Class", 
+        "ng:a": "Define a custom Class for your data",
+        "ng:x": {
+            "rdfs":true,
+        },
+        "ng:compat": ["rdfs:Class"],
+    },
+    "schema/rdfs": {
+        "ng:crdt": "Graph",
+        "ng:n": "Schema - RDFS", 
+        "ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with RDFS",
+        "ng:o": "n:g:z:json_ld_editor", // default viewer
+        "ng:w": "n:g:z:ontology_editor", // default editor
+        "ng:x": {
+            "rdfs":true,
+        },
+        "ng:include": ["data/graph"],
+        "ng:compat": ["rdfs:*","class"],
+    },
+    "schema/owl": { // display with https://github.com/VisualDataWeb/WebVOWL
+        "ng:crdt": "Graph",
+        "ng:n": "Schema - OWL", 
+        "ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with OWL",
+        "ng:o": "n:g:z:owl_viewer", // default viewer
+        "ng:w": "n:g:z:ontology_editor", // default editor
+        "ng:x": {
+            "owl":true,
+        },
+        "ng:include": ["data/graph"],
+        "ng:compat": ["owl:Ontology"],
+    },
+    "schema/shacl": {
+        "ng:crdt": "Graph",
+        "ng:n": "Schema - SHACL", 
+        "ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with SHACL",
+        "ng:o": "n:g:z:json_ld_editor", // default viewer
+        "ng:w": "n:g:z:ontology_editor", // default editor
+        "ng:x": {
+            "sh":true,
+        },
+        "ng:include": ["data/graph"],
+        "ng:compat": ["sh:Shape", "file/iana/text/shaclc" ],
+    },
+    "schema/shex": {
+        "ng:crdt": "Graph",
+        "ng:n": "Schema - SHEX", 
+        "ng:a": "Define the Schema, Ontology or Vocabulary for your data and the relations between them, with SHEX",
+        "ng:o": "n:g:z:json_ld_editor", // default viewer
+        "ng:w": "n:g:z:ontology_editor", // default editor
+        "ng:x": {
+            "shex":true,
+        },
+        "ng:include": ["data/graph"],
+        "ng:compat": ["shex:*", "file/iana/text/shex", "code/shexc" ],
+    },
+    "service": {
+        "ng:n": "Internal Service",
+        "ng:a": "Service provided by NextGraph framework",
+        "ng:o": "n:g:z:service_invoke", // default viewer
+    },
+    "service/rust": {
+        "ng:crdt": "YText",
+        "ng:n": "Service - Rust", // edited with CodeMirror, displayed with highlight.js
+        "ng:a": "Service written in Rust and compiled to WASM",
+        "ng:o": "external_service_invoke", // default viewer
+        "ng:w": "n:g:z:service_editor", // default editor
+        "ng:compat": ["code/rust", "file/iana/application/wasm"],
+    },
+    "service/deno": {
+        "ng:crdt": "YText",
+        "ng:n": "Service - Deno/JS", // edited with CodeMirror, displayed with highlight.js
+        "ng:a": "Service written in JS/TS for Deno or NodeJS",
+        "ng:o": "external_service_invoke", // default viewer
+        "ng:w": "n:g:z:service_editor", // default editor
+        "ng:compat": ["code/javascript", "code/typescript", "file/iana/text/javascript", "file/iana/application/node"],
+    },
+    "contract": {
+        "ng:crdt": "YText",
+        "ng:n": "Contract", // edited with CodeMirror, displayed with highlight.js
+        "ng:a": "Smart Contract with Rust or JS code",
+        "ng:compat": ["code/rust", "file/iana/application/wasm", "code/javascript", "code/typescript", "file/iana/text/javascript", "file/iana/application/node"],
+    },
+    "query/sparql": { 
+        "ng:crdt": "YText",// uses ng:default_graph and ng:named_graph predicates 
+        "ng:n": "SPARQL Query", // edited with YASGUI or Sparnatural, displayed with highlight.js https://github.com/highlightjs/highlightjs-turtle/tree/master
+        "ng:a": "Saved SPARQL Query that can be invoked",
+        "ng:o": "n:g:z:sparql:invoke", 
+        "ng:w": "n:g:z:sparql_query:yasgui",
+        "ng:compat": ["code/sparql", "file/iana/application/sparql-query"],
+    },
+    "query/sparql_update": { 
+        "ng:crdt": "YText",// uses ng:default_graph and ng:named_graph predicates 
+        "ng:n": "SPARQL Update", // edited with YASGUI, displayed with highlight.js https://github.com/highlightjs/highlightjs-turtle/tree/master
+        "ng:a": "Saved SPARQL Update that can be invoked",
+        "ng:o": "n:g:z:sparql:invoke", 
+        "ng:w": "n:g:z:sparql_update:yasgui",
+        "ng:compat": ["code/sparql", "file/iana/application/sparql-update"],
+    },
+    "query/graphql": {
+        "ng:crdt": "YText", // uses ng:default_graph predicate
+        "ng:n": "GraphQL Query", // edited with https://github.com/graphql/graphiql or https://github.com/graphql-editor/graphql-editor, displayed with highlight.js
+        "ng:a": "Saved GraphQL Query that can be invoked",
+        "ng:o": "n:g:z:graphql:invoke", 
+        "ng:w": "n:g:z:graphql_query",
+        "ng:compat": ["code/graphql", "file/iana/application/graphql+json"],
+    }, 
+    "query/text": {
+        "ng:crdt": "Graph",
+        "ng:n": "Text Search", 
+        "ng:a": "Saved Text Search and its results",
+        "ng:compat": [],
+    },
+    "query/web": {
+        "ng:crdt": "Graph",
+        "ng:n": "Web Search", 
+        "ng:a": "Saved Web Search and its results",
+        "ng:compat": [],
+    },
+    "data/graph": {
+        "ng:crdt": "Graph", // https://github.com/highlightjs/highlightjs-turtle/tree/master
+        "ng:n": "Graph", 
+        "ng:a": "Define the Graph of your data with Semantic Web / Linked Data",
+        "ng:o": "n:g:z:json_ld_editor", // default viewer
+        "ng:w": "n:g:z:json_ld_editor", // default editor
+        "ng:x": {
+            "rdf":true,
+            "xsd":true,
+        },
+        "ng:compat": [ "rdf:*", "xsd:*", "file/iana/text/n3", "file/iana/text/rdf+n3", "file/iana/text/turtle", "file/iana/application/n-quads", "file/iana/application/trig", "file/iana/application/n-triples", "file/iana/application/rdf+xml", "file/iana/application/ld+json"],
+    },
+    "data/json": {
+        "ng:crdt": "Automerge",
+        "ng:n": "JSON", 
+        "ng:a": "JSON Data CRDT",
+        "ng:o": "n:g:z:json_editor", // default viewer
+        "ng:w": "n:g:z:json_editor", // default editor
+        "ng:compat": ["file/iana/application/json", "code:json"],
+    },
+    "data/array": {
+        "ng:crdt": "YArray",
+        "ng:n": "JSON Array", 
+        "ng:a": "JSON Array CRDT",
+        "ng:o": "n:g:z:json_editor", // default viewer
+        "ng:w": "n:g:z:json_editor", // default editor
+        "ng:compat": ["file/iana/application/json", "code:json"],
+    },
+    "data/map": {
+        "ng:crdt": "YMap",
+        "ng:n": "JSON Map", 
+        "ng:a": "JSON Map CRDT",
+        "ng:o": "n:g:z:json_editor", // default viewer
+        "ng:w": "n:g:z:json_editor", // default editor
+        "ng:compat": ["file/iana/application/json", "code:json"],
+    },
+    "data/xml": {
+        "ng:crdt": "YXml",
+        "ng:n": "XML", 
+        "ng:a": "XML Data CRDT",
+        "ng:compat": ["file/iana/text/xml","file/iana/application/xml", "code:xml"],
+    },
+    "data/table": {
+        "ng:crdt": "Automerge", // see https://github.com/frappe/datatable
+        "ng:n": "Table", // see https://specs.frictionlessdata.io/table-schema displayed with pivot table see https://activetable.io/docs/data https://www.npmjs.com/package/pivottable https://socket.dev/npm/package/svelte-pivottable/alerts/0.2.0?tab=dependencies
+        "ng:a": "Data in a Table (columns and rows)",
+        "ng:o": "n:g:z:pivot",
+        "ng:compat": ["file/iana/application/sparql-results+json","file/iana/application/sparql-results+xml","file/iana/text/csv"],
+    },
+    "data/collection": {
+        "ng:crdt": "Graph",
+        "ng:n": "Collection",
+        "ng:a": "An ordered list of items",
+        "ng:o": "n:g:z:list",
+        "ng:x": {
+            "as": true,
+            "rdf": true,
+        },
+        "ng:compat": ["as:Collection","rdf:List","rdf:Seq"],
+    },
+    "data/container": {
+        "ng:crdt": "Graph",
+        "ng:n": "Container",
+        "ng:a": "An unordered list of items",
+        "ng:o": "n:g:z:list",
+        "ng:x": {
+            "rdf": true,
+            "rdfs": true,
+            "ldp": true,
+        },
+        "ng:compat": ["rdfs:member","ldp:contains","rdf:Bag","rdf:Alt"],
+    },
+    "data/board": {
+        "ng:crdt": "Graph",
+        "ng:n": "Board",
+        "ng:a": "Whiteboard, infinite canvas to arrange your content in 2D",
+        "ng:o": "n:g:z:board",
+        "ng:include": [],
+        "ng:compat": [], //https://jsoncanvas.org/ https://www.canvasprotocol.org/ https://github.com/orgs/ocwg/discussions/25 https://infinitecanvas.tools/gallery/
+    },
+    "data/grid": {
+        "ng:crdt": "Graph",
+        "ng:n": "Grid",
+        "ng:a": "Grid representation of a collection or container",
+        "ng:o": "n:g:z:grid",
+        "ng:include": ["data/container","data/collection","data/table","media/album"],
+        "ng:compat": [],
+    },
+    "data/geomap": {  // https://github.com/leaflet/leaflet
+        "ng:crdt": "Graph",
+        "ng:n": "Geo Map",
+        "ng:a": "Geographical Map",
+        "ng:x": {
+            "wgs": true,
+            "gn": true,
+            "as": true,
+        },
+        "ng:compat": ["as:Place","wgs:*","gn:*", "file/iana/application/geo+json", "file/iana/application/vnd.mapbox-vector-tile"], // see also https://github.com/topojson/topojson
+    },
+    "e/email": {
+        "ng:crdt": "Graph",
+        "ng:n": "Email",
+        "ng:a": "Email content and headers",
+        "ng:x": {
+            "email": "http://www.invincea.com/ontologies/icas/1.0/email#" //https://raw.githubusercontent.com/twosixlabs/icas-ontology/master/ontology/email.ttl
+        },
+        "ng:compat": ["file/iana/message/rfc822","file/iana/multipart/related"],
+    },
+    "e/web": {
+        "ng:crdt": "Graph",
+        //https://www.npmjs.com/package/warcio https://github.com/N0taN3rd/node-warc
+        "ng:n": "Web Archive",
+        "ng:a": "Archive the content of a web page",
+        "ng:compat": ["file/iana/application/warc","file/iana/multipart/related"],
+    }, 
+    "e/rdf": {
+        "ng:crdt": "Graph",
+        "ng:n": "RDF Archive",
+        "ng:a": "Archive the triples of an RDF resource dereferenced with HTTP",
+        "ng:include": ["data/graph"],
+    },
+    "mc/text": {
+        "ng:crdt": "Graph",
+        "ng:n": "Text Selection",
+        "ng:a": "Text Selection copied into Magic Carpet",
+    }, 
+    "mc/link": {
+        "ng:crdt": "Graph",
+        "ng:n": "Link",
+        "ng:a": "Link to a document kept in Magic Carpet",
+    },
+    "plato/card": {
+        "ng:crdt": "Graph",
+        "ng:n": "Card",
+        "ng:a": "Card representation of a document",
+        "ng:o": "n:g:z:card",
+    },
+    "plato/pad": {
+        "ng:crdt": "Graph",
+        "ng:n": "Pad",
+        "ng:a": "Pad representation of a document",
+        "ng:o": "n:g:z:pad",
+    },
+    "doc/diagram/mermaid" : {
+        "ng:crdt": "YText",
+        "ng:n": "Diagram - Mermaid",
+        "ng:a": "Describe Diagrams with Mermaid",
+        "ng:compat": ["file/iana/application/vnd.mermaid"]
+    },
+    "doc/diagram/drawio" : {
+        "ng:crdt": "YXml",
+        "ng:n": "Diagram - DrawIo",
+        "ng:a": "Draw Diagrams with DrawIo",
+        "ng:compat": ["file/iana/application/vnd.jgraph.mxfile","file/iana/application/x-drawio"]
+    },
+    "doc/diagram/graphviz" : {
+        "ng:crdt": "YText",
+        "ng:n": "Diagram - Graphviz",
+        "ng:a": "Describe Diagrams with Graphviz",
+        "ng:compat": ["file/iana/text/vnd.graphviz"]
+    },
+    "doc/diagram/excalidraw" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Diagram - Excalidraw",
+        "ng:a": "Collaborate on Diagrams with Excalidraw",
+        "ng:compat": ["file/iana/application/vnd.excalidraw+json"]
+    },
+    "doc/diagram/gantt" : { //https://github.com/frappe/gantt
+        "ng:crdt": "Automerge",
+        "ng:n": "Diagram - Gantt",
+        "ng:a": "Interactive gantt chart",
+        "ng:compat": []
+    },
+    "doc/diagram/flowchart" : { //https://github.com/adrai/flowchart.js
+        "ng:crdt": "YText",
+        "ng:n": "Diagram - Flowchart",
+        "ng:a": "flow chart diagrams",
+        "ng:compat": []
+    },
+    "doc/diagram/sequence" : { //https://github.com/bramp/js-sequence-diagrams
+        "ng:crdt": "YText",
+        "ng:n": "Diagram - Sequence",
+        "ng:a": "sequence diagrams",
+        "ng:compat": []
+    },
+    // checkout https://www.mindmaps.app/ but it is AGPL 
+    "doc/diagram/markmap" : { //https://github.com/markmap/markmap
+        "ng:crdt": "YText",
+        "ng:n": "Diagram - Markmap",
+        "ng:a": "mindmaps with markmap",
+        "ng:compat": []
+    },
+    "doc/diagram/mymind" : { //https://github.com/markmap/markmap
+        "ng:crdt": "YText", // see MyMind format, MindMup JSON, FreeMind XML and MindMap Architect XML
+        "ng:n": "Diagram - Mymind",
+        "ng:a": "mindmaps with mymind",
+        "ng:compat": [] // https://github.com/ondras/my-mind/wiki/Saving-and-loading#file-formats
+    },
+    "doc/diagram/jsmind" : { //https://github.com/hizzgdev/jsmind
+        "ng:crdt": "Automerge",
+        "ng:n": "Diagram - jsmind",
+        "ng:a": "mindmaps with jsmind",
+        "ng:compat": [] // https://hizzgdev.github.io/jsmind/docs/en/1.usage.html
+    },
+    // DC and C3 have Crossfilter https://github.com/dc-js/dc.js http://crossfilter.github.io/crossfilter/ https://github.com/c3js/c3 http://dc-js.github.io/dc.js/
+    // take inspiration from https://github.com/metabase/metabase
+    // have a look at https://github.com/observablehq
+    // another open source dashboard with many data sources https://github.com/getredash/redash
+    // and another one https://github.com/apache/superset
+    // https://github.com/Rich-Harris/pancake
+    // https://github.com/williamngan/pts
+    // https://visjs.org/
+    "doc/viz/cytoscape" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Viz - Cytoscape",
+        "ng:a": "Graph theory (network) visualization",
+        "ng:compat": [] // https://github.com/cytoscape/cytoscape.js
+    },
+    "doc/viz/vega" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Viz - Vega",
+        "ng:a": "Grammar for interactive graphics",
+        "ng:compat": [] // https://vega.github.io/vega-lite/docs/ https://github.com/vega/editor
+    },
+    "doc/viz/vizzu" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Viz - Vizzu",
+        "ng:a": "Animated data visualizations and data stories",
+        "ng:compat": [] // https://github.com/vizzuhq/vizzu-lib
+    },
+    "doc/viz/plotly" : { //https://github.com/plotly/plotly.js
+        "ng:crdt": "Automerge",
+        "ng:n": "Viz - Plotly",
+        "ng:a": "Declarative charts",
+        "ng:compat": [] // https://github.com/cytoscape/cytoscape.js
+    },
+    "doc/viz/avail" : { 
+        "ng:crdt": "Automerge",
+        "ng:n": "Viz - Avail",
+        "ng:a": "Time Data Availability Visualization",
+        "ng:compat": [] // https://github.com/flrs/visavail
+    },
+    "doc/chart/frappecharts" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - Frappe",
+        "ng:a": "GitHub-inspired responsive charts",
+        "ng:compat": [] // https://github.com/frappe/charts
+    },
+    "doc/chart/financial" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - Financial",
+        "ng:a": "Financial charts",
+        "ng:compat": [] //https://github.com/tradingview/lightweight-charts
+    },
+    // have a look at https://github.com/cube-js/cube and https://awesome.cube.dev/ and https://frappe.io/products
+    "doc/chart/apexcharts" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - ApexCharts",
+        "ng:a": "Interactive data visualizations",
+        "ng:compat": [] // https://github.com/apexcharts/apexcharts.js
+    },
+    //realtime data with https://github.com/square/cubism
+    "doc/chart/billboard" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - BillBoard",
+        "ng:a": "Interactive data visualizations based on D3",
+        "ng:compat": [] // https://github.com/naver/billboard.js
+    },
+    "doc/chart/echarts" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - ECharts",
+        "ng:a": "Interactive charting and data visualization with Apache ECharts",
+        "ng:compat": [] // https://github.com/apache/echarts
+    },
+    "doc/chart/chartjs" : {
+        "ng:crdt": "Automerge",
+        "ng:n": "Charts - Chart.js",
+        "ng:a": "Simple yet flexible charting for designers & developers with Chart.js",
+        "ng:compat": [] // https://github.com/chartjs/Chart.js
+    },
+    // see if to provide plain D3, and also all the https://github.com/antvis libraries: G2, G6, L7, S2, X6. Have a look at AVA
+    "doc/pdf": {
+        "ng:crdt": "Graph",
+        "ng:n": "PDF",
+        "ng:a": "upload and display a PDF file",
+        "ng:compat": ["file/iana/application/pdf"] // https://github.com/mozilla/pdf.js https://viewerjs.org/
+    },
+    "doc/odf": { //!!! becareful: AGPL
+        "ng:crdt": "Graph",
+        "ng:n": "OpenDocumentFormat (ODF)",
+        "ng:a": "upload and display an ODF file",
+        "ng:compat": ["file/iana/application/vnd.oasis.opendocument*"] // https://webodf.org/ https://github.com/webodf/WebODF https://viewerjs.org/ 
+    },
+    // see also https://github.com/Mathpix/mathpix-markdown-it
+    "doc/latex": {
+        "ng:crdt": "Graph",
+        "ng:n": "Latex",
+        "ng:a": "upload and display a Latex or Tex file",
+        "ng:compat": ["file/iana/application/x-tex","file/iana/text/x-tex"] // https://github.com/michael-brade/LaTeX.js https://github.com/mathjax/MathJax
+    },
+    "doc/ps": { //!!! becareful: AGPL https://github.com/ochachacha/ps-wasm
+        "ng:crdt": "Graph",
+        "ng:n": "Postscript",
+        "ng:a": "upload and display a PostScript file",
+        "ng:compat": ["file/iana/application/postscript"] // https://www.npmjs.com/package/ghostscript4js 
+    },
+    "doc/music/abc": { //https://github.com/paulrosen/abcjs
+        "ng:crdt": "YText",
+        "ng:n": "Music ABC",
+        "ng:a": "sheet music notation",
+        "ng:compat": []
+    },
+    "doc/music/guitar": { //https://github.com/birdca/fretboard
+        "ng:crdt": "YText",
+        "ng:n": "Music - Guitar",
+        "ng:a": "charts for guitar chords and scales",
+        "ng:compat": []
+    },
+    "doc/maths": { //https://github.com/KaTeX/KaTeX
+        "ng:crdt": "YText",
+        "ng:n": "Maths",
+        "ng:a": "TeX math rendering",
+        "ng:compat": ["file/iana/application/x-tex","file/iana/text/x-tex"]
+    },
+    "doc/chemistry": { //GPL!! https://github.com/aeris-data/ChemDoodle/tree/master/ChemDoodleWeb-8.0.0 or https://github.com/aseevia/smiles-3d-vue 
+        "ng:crdt": "YText",
+        "ng:n": "Chemical",
+        "ng:a": "simplified molecular-input line-entry system (SMILES)",
+        "ng:compat": ["file/iana/chemical/x-daylight-smiles"] // https://en.wikipedia.org/wiki/SYBYL_line_notation and http://fileformats.archiveteam.org/wiki/Chemical_data
+    },
+    "doc/ancientscript": { //https://dn-works.com/ufas/ 
+        "ng:crdt": "YText", // use Unicode and special fonts
+        "ng:n": "Ancient Script",
+        "ng:a": "Ancient Script",
+        "ng:compat": [] 
+    },
+    "doc/braille": { //https://en.wikipedia.org/wiki/Braille_Patterns
+        "ng:crdt": "YText", // use Unicode and special fonts
+        "ng:n": "Braille Patterns",
+        "ng:a": "Braille Patterns",
+        "ng:compat": [] 
+    },
+    "media/image": {
+        "ng:crdt": "Graph",
+        "ng:n": "Image",
+        "ng:a": "upload and display an image",
+        "ng:o": "n:g:z:media",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["file/iana/image*","as:Image"]
+    },
+    "media/reel": {
+        "ng:crdt": "Graph",
+        "ng:n": "Reel",
+        "ng:a": "upload and display a Reel (video from mobile)",
+        "ng:o": "n:g:z:media",
+        "ng:compat": ["file/iana/video*"]
+    },
+    "media/video": {
+        "ng:crdt": "Graph",
+        "ng:n": "Video",
+        "ng:a": "upload and display a Video (and film)",
+        "ng:o": "n:g:z:media",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["file/iana/video*","as:Video"]
+    },
+    "media/album": {
+        "ng:crdt": "Graph",
+        "ng:n": "Album",
+        "ng:a": "Assemble several images and/or videos into an ordered Album",
+        "ng:o": "n:g:z:gallery",
+        "ng:include": ["data/collection"],
+        "ng:compat": []
+    },
+    "media/audio": {
+        "ng:crdt": "Graph",
+        "ng:n": "Audio",
+        "ng:a": "upload and play an Audio file, Audio note or Voice message",
+        "ng:o": "n:g:z:media",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["file/iana/audio*","as:Audio"]
+    },
+    "media/song": {
+        "ng:crdt": "Graph",
+        "ng:n": "Song",
+        "ng:a": "A song from an artist,album and/or lyrics",
+        "ng:o": "n:g:z:media",
+        "ng:x": {
+            "music": "http://purl.org/ontology/mo/",
+        },
+        "ng:compat": ["music:MusicalWork","music:MusicArtist", "music:Lyrics"] 
+        // see also https://polifonia-project.eu/wp-content/uploads/2022/01/Polifonia_D2.1_V1.0.pdf
+        // Music ontology http://musicontology.com/docs/faq.html with data based on existing databases https://musicbrainz.org/doc/MusicBrainz_Database/Schema https://github.com/megaconfidence/open-song-database https://www.discogs.com/developers
+    },  
+    "media/subtitle": { //https://captioneasy.com/subtitle-file-formats/
+        "ng:crdt": "YText", 
+        "ng:n": "Subtitles",
+        "ng:a": "Subtitles",
+        "ng:compat": [] // TBD
+    },
+    "media/overlay": {
+        "ng:crdt": "Graph",
+        "ng:n": "Overlay",
+        "ng:a": "Composition of an image, reel, text, icon, link, mention or other content into a layered content",
+        "ng:o": "n:g:z:media",
+        "ng:compat": []
+    },
+    "social/channel": {
+        "ng:crdt": "Graph",
+        "ng:n": "Channel",
+        "ng:a": "Broadcast channel with subscribers",
+        "ng:compat": []
+    }, 
+    "social/stream": {
+        "ng:crdt": "Graph",
+        "ng:n": "Stream",
+        "ng:a": "A document or store's stream branch",
+        "ng:compat": []
+    },
+    "social/contact": {
+        "ng:crdt": "Graph",
+        "ng:n": "Contact", 
+        "ng:a": "Contact: an Individual, Organization or Group",
+        "ng:x": {
+            "vcard":true,
+            "foaf": true,
+        },
+        "ng:include": ["data/graph"],
+        "ng:compat": ["foaf:Person","foaf:Agent","vcard:Individual", "vcard:Organization", "vcard:Group", "file/iana/text/vcard", "file/iana/application/vcard+json", "file/iana/application/vcard+xml" ],
+    },
+    "social/event": {
+        "ng:crdt": "Graph",
+        "ng:n": "Event",
+        "ng:a": "An event occuring in specific location and time",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["as:Event"]
+    },
+    "social/calendar": {
+        "ng:crdt": "Graph",
+        "ng:n": "Calendar",
+        "ng:a": "A calendar where events are gathered",
+        "ng:x": {
+            "as":true,
+            "time": true,
+        },
+        "ng:include": ["data/collection"],
+        "ng:compat": ["time:TemporalEntity", "file/iana/text/calendar", "file/iana/application/calendar+xml", "file/iana/application/calendar+json"] //https://www.rfc-editor.org/rfc/rfc5545
+    }, 
+    "social/scheduler": {
+        "ng:crdt": "Graph",
+        "ng:n": "Scheduler",
+        "ng:a": "Helps finding a common time slot for several participants to a future event",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["as:Invite","as:Reject","as:Accept","as:TentativeAccept","as:TentativeReject"]
+    },
+    "social/reaction": {
+        "ng:crdt": "Graph",
+        "ng:n": "Reaction",
+        "ng:a": "A reaction by user to some content",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["as:Like", "as:Dislike", "as:Listen", "as:Read", "as:View"]
+    },
+    "prod/task": {
+        "ng:crdt": "Graph",
+        "ng:n": "Task",
+        "ng:a": "A task to be done",
+        "ng:x": {
+            "as":true,
+            "pair": "http://virtual-assembly.org/ontologies/pair#",
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["pair:Task"] //see VTODO in iCalendar https://www.cs.utexas.edu/~mfkb/RKF/tree/components/specs/ontologies/Calendar-onto.html
+        // see todo and todoList of Mobilizon https://framagit.org/framasoft/mobilizon/-/blob/main/lib/federation/activity_stream/converter/todo.ex 
+        // https://framagit.org/framasoft/mobilizon/-/blob/main/lib/federation/activity_stream/converter/todo_list.ex
+    },
+    "prod/project": {
+        "ng:crdt": "Graph",
+        "ng:n": "Project",
+        "ng:a": "A project management / KanBan",
+        "ng:x": {
+            "as":true,
+            "pair": "http://virtual-assembly.org/ontologies/pair#",
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["pair:Project"] 
+    },
+    // see SRO https://www.researchgate.net/publication/350158531_From_a_Scrum_Reference_Ontology_to_the_Integration_of_Applications_for_Data-Driven_Software_Development
+    // https://ceur-ws.org/Vol-1442/paper_4.pdf
+    // see focalbaord, specially for their import scripts https://github.com/mattermost/focalboard/tree/main/import
+    // and their data model https://github.com/mattermost/focalboard/tree/main/server/model
+    // https://github.com/leif81/bzkanban
+    // https://github.com/HigorLoren/donko (react)
+    // https://github.com/trobonox/kanri (GPL, Vue)
+    // https://github.com/waterrmalann/kards (vanilla JS)
+    // see also https://github.com/wekan/wekan
+    // see also https://taiga.io/ (for inspiration. as it is AGPL and python)
+    // see also https://github.com/plankanban/planka (for inspiration. as it is AGPL and React)
+    // see also https://kolaente.dev/vikunja/vikunja (for inspiration. AGPL. Vue and Go)
+    // see also https://github.com/laurent22/joplin/ (for inspiration. AGPL)
+    // see also https://github.com/SrGMC/kanbana
+    /// svelte: https://github.com/V-Py/svelte-kanban
+    // https://github.com/supabase-community/svelte-kanban
+    // https://github.com/therosbif/kanban
+    "prod/issue": {
+        "ng:crdt": "Graph",
+        "ng:n": "Issue",
+        "ng:a": "An issue to be solved",
+        "ng:x": {
+            "as":true,
+            "pair": "http://virtual-assembly.org/ontologies/pair#",
+        },
+        "ng:include": ["prod/task"],
+        "ng:compat": ["pair:Challenge"] 
+    },
+    //https://github.com/go-gitea/gitea/issues/20232
+    // datamodel of gitea issues: https://github.com/go-gitea/gitea/blob/165346c15c6d021028a65121e692a17ffc927e2c/models/issue.go#L35-L79
+    "prod/form": {
+        "ng:crdt": "Graph",
+        "ng:n": "Form",
+        "ng:a": "A form to be filled-in",
+        "ng:x": {
+            "form" : "http://rdf.danielbeeke.nl/form/form-dev.ttl#",
+        },
+        "ng:compat": ["form:*","file/iana/application/schema+json"] 
+    },
+    // https://jsonforms.io/docs/
+    // https://github.com/jsonform/jsonform
+    // https://jsonforms.io/docs/integrations/vue
+    // >>> https://github.com/json-editor/json-editor
+    // or >>> https://github.com/webgme/svelte-jsonschema-form
+    // or >>> https://github.com/restspace/svelte-schema-form
+    // see https://ceur-ws.org/Vol-1515/regular14.pdf
+    // and https://github.com/protegeproject/facsimile
+    // https://www.drupal.org/project/webform
+    // see https://www.semantic-mediawiki.org/wiki/Extension:Page_Forms
+    //  https://www.mediawiki.org/wiki/Extension:Page_Forms
+    // https://rdf-form.danielbeeke.nl/
+    // consider using Shapes
+    "prod/filling": {
+        "ng:crdt": "Graph",
+        "ng:n": "Form filling",
+        "ng:a": "A form that has been filled-in",
+        "ng:compat": [] 
+    },
+    "prod/cad": { // https://mattferraro.dev/posts/cadmium
+        "ng:crdt": "Automerge",
+        "ng:n": "CAD",
+        "ng:a": "CADmium",
+        "ng:compat": [] 
+    }, 
+    "prod/slides": { //https://github.com/hakimel/reveal.js
+        //https://pandoc.org/MANUAL.html#slide-shows
+        "ng:crdt": "Graph",
+        "ng:n": "Slides",
+        "ng:a": "Slides and presentations",
+        "ng:include": ["post/*"],
+        "ng:compat": [] 
+    },
+    "prod/question" : {
+        "ng:crdt": "Graph",
+        "ng:n": "Question",
+        "ng:a": "A question that needs answers",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["as:Question"] 
+    }, 
+    "prod/answer" :{
+        "ng:crdt": "Graph",
+        "ng:n": "Answer",
+        "ng:a": "An answer to a question",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["as:Note"] 
+    }, 
+    "prod/poll" : {
+        "ng:crdt": "Graph",
+        "ng:n": "Poll",
+        "ng:a": "A poll where people will vote",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:include": ["post/*"],
+        "ng:compat": ["as:Question"] 
+    }, 
+    "prod/vote" : {
+        "ng:crdt": "Graph",
+        "ng:n": "Vote",
+        "ng:a": "A vote cast for a Poll",
+        "ng:x": {
+            "as":true,
+        },
+        "ng:compat": ["as:Note"] 
+    }, 
+    "file" : {
+        "ng:crdt": "Graph",
+        "ng:n": "File",
+        "ng:a": "Binary file",
+        "ng:o": "n:g:z:file_viewer",
+        "ng:w": "n:g:z:file_viewer",
+        "ng:compat": [] 
+    }, 
+    "file/ng/wallet" : {
+        "ng:n": "NextGraph Wallet File",
+        "ng:a": "NextGraph Wallet File (.ngw)",
+        "ng:compat": [] 
+    }, 
+    "file/ng/doc" : {
+        "ng:n": "NextGraph Document File",
+        "ng:a": "NextGraph Document File (.ngd)",
+        "ng:compat": [] 
+    },
+    "file/ng/html" : {
+        "ng:n": "NextGraph Document Html",
+        "ng:a": "NextGraph Document Html standalone file",
+        "ng:compat": [] 
+    }, 
+    "file/text" : {
+        "ng:crdt": "Graph",
+        "ng:n": "File",
+        "ng:a": "Text file",
+        "ng:o": "n:g:z:file_viewer",
+        "ng:w": "n:g:z:file_viewer",
+        "ng:compat": ["file/iana/text/*", "image/svg+xml", "file/iana/application/n-quads", "file/iana/application/trig", "file/iana/application/n-triples", "file/iana/application/rdf+xml", "file/iana/application/ld+json",
+        "file/iana/application/xml", "file/iana/application/yaml", "file/iana/application/xhtml+xml", "file/iana/application/node","file/iana/application/sparql-results+json","file/iana/application/sparql-results+xml",
+        "file/iana/message/rfc822","file/iana/multipart/related", "file/iana/text/vnd.graphviz", "file/iana/application/vnd.excalidraw+json", "file/iana/application/x-tex","file/iana/text/x-tex",
+        "file/iana/application/vcard+json", "file/iana/application/vcard+xml", "file/iana/text/calendar", "file/iana/application/calendar+xml", "file/iana/application/calendar+json", 
+        "file/iana/application/schema+json", "file/iana/application/geo+json", "file/iana/application/json" ] 
+    }, 
+    
+};
\ No newline at end of file
diff --git a/ng-app/src/lib/CenteredLayout.svelte b/ng-app/src/lib/CenteredLayout.svelte
index 80fe9bd..cc7114b 100644
--- a/ng-app/src/lib/CenteredLayout.svelte
+++ b/ng-app/src/lib/CenteredLayout.svelte
@@ -9,7 +9,18 @@
 // according to those terms.
 -->
 
+<script lang="ts">
+  import ng from "../api";
+  import { onMount } from "svelte";
+
+  let locales = [];
+  onMount(async () => {
+    locales = await ng.locales();
+  });
+</script>
+
 <div class="centered">
+  {locales}
   <slot />
 </div>
 
diff --git a/ng-app/src/lib/DataClassIcon.svelte b/ng-app/src/lib/DataClassIcon.svelte
new file mode 100644
index 0000000..263fbfb
--- /dev/null
+++ b/ng-app/src/lib/DataClassIcon.svelte
@@ -0,0 +1,187 @@
+<!--
+// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
+// All rights reserved.
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
+// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+-->
+
+<script lang="ts">
+  import {
+    Icon,
+    BugAnt,
+    DocumentText,
+    Window,
+    CodeBracket,
+    SquaresPlus,
+    ViewfinderCircle,
+    ArrowsPointingOut,
+    Cube,
+    Briefcase,
+    MagnifyingGlass,
+    RocketLaunch,
+    Sun,
+    TableCells,
+    ListBullet,
+    RectangleGroup,
+    Squares2x2,
+    MapPin,
+    CircleStack,
+    Envelope,
+    GlobeAlt,
+    DocumentChartBar,
+    Document,
+    ClipboardDocumentList,
+    Photo,
+    Film,
+    RectangleStack,
+    Microphone,
+    MusicalNote,
+    Ticket,
+    CursorArrowRays,
+    Megaphone,
+    User,
+    Clock,
+    CalendarDays,
+    Calendar,
+    Stop,
+    Flag,
+    HandRaised,
+    Newspaper,
+    PencilSquare,
+    CubeTransparent,
+    PresentationChartBar,
+    QuestionMarkCircle,
+    CheckCircle,
+    ChartPie,
+    Bars3BottomLeft,
+    Link,
+    Square2Stack,
+    Clipboard,
+    StopCircle,
+    Bolt,
+    Heart,
+  } from "svelte-heros-v2";
+
+  export let config = {};
+  export let dataClass: string;
+
+  const exact_mapping = {
+    page: Window,
+    "app/z": SquaresPlus,
+    class: ViewfinderCircle,
+    contract: Briefcase,
+    "query/text": MagnifyingGlass,
+    "query/web": MagnifyingGlass,
+    "data/graph": Sun,
+    "data/table": TableCells,
+    "data/collection": ListBullet,
+    "data/board": RectangleGroup,
+    "data/grid": Squares2x2,
+    "data/geomap": MapPin,
+    "e/email": Envelope,
+    "mc/text": Bars3BottomLeft,
+    "mc/link": Link,
+    "plato/card": Clipboard,
+    "plato/pad": Square2Stack,
+    "media/image": Photo,
+    "media/reel": Film,
+    "media/video": Film,
+    "media/album": RectangleStack,
+    "media/audio": Microphone,
+    "media/song": MusicalNote,
+    "media/subtitle": Ticket,
+    "media/overlay": CursorArrowRays,
+    "social/channel": Megaphone,
+    "social/stream": Bolt,
+    "social/contact": User,
+    "social/event": Clock,
+    "social/calendar": CalendarDays,
+    "social/scheduler": Calendar,
+    "social/reaction": Heart,
+    "prod/task": Stop,
+    "prod/project": Flag,
+    "prod/issue": HandRaised,
+    "prod/form": Newspaper,
+    "prod/filling": PencilSquare,
+    "prod/cad": CubeTransparent,
+    "prod/slides": PresentationChartBar,
+    "prod/question": QuestionMarkCircle,
+    "prod/answer": CheckCircle,
+    "prod/poll": QuestionMarkCircle,
+    "prod/vote": CheckCircle,
+  };
+
+  const prefix_mapping = {
+    "post/": DocumentText,
+    code: CodeBracket,
+    schema: ArrowsPointingOut,
+    service: Cube,
+    "e/": GlobeAlt,
+    "app/": StopCircle,
+    "query/": RocketLaunch,
+    "data/": CircleStack,
+    "doc/diagram": DocumentChartBar,
+    "doc/chart": ChartPie,
+    "doc/viz": ChartPie,
+    "doc/": ClipboardDocumentList,
+    file: Document,
+  };
+
+  const find = (t) => {
+    let e = exact_mapping[t];
+    if (e) return e;
+    for (let prefix of Object.entries(prefix_mapping)) {
+      if (t.startsWith(prefix[0])) return prefix[1];
+    }
+    return BugAnt;
+  };
+</script>
+
+<!--
+did:ng:n:g:z:[official apps]
+did:ng:n:g:ns
+did:ng:n:g:x list of context used by nextgraph
+  rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
+  rdfs: http://www.w3.org/2000/01/rdf-schema#
+  schema: https://schema.org/
+  skos: http://www.w3.org/2004/02/skos/core#
+  owl: http://www.w3.org/2002/07/owl#
+  foaf: http://xmlns.com/foaf/0.1/
+  relationship: http://purl.org/vocab/relationship/
+  dcterms: http://purl.org/dc/terms/
+  dcmitype: http://purl.org/dc/dcmitype/
+  sh: http://www.w3.org/ns/shacl#
+  shex: http://www.w3.org/ns/shex#
+  xsd: http://www.w3.org/2001/XMLSchema#
+  as: https://www.w3.org/ns/activitystreams#
+  ldp: http://www.w3.org/ns/ldp#
+  vcard: http://www.w3.org/2006/vcard/ns#
+  sec: https://w3id.org/security#
+  wgs: http://www.w3.org/2003/01/geo/wgs84_pos#
+  cc: http://creativecommons.org/ns#
+  gn: https://www.geonames.org/ontology#
+  geo: http://www.opengis.net/ont/geosparql#
+  time: http://www.w3.org/2006/time#
+
+  ng: did:ng:n:g:ns# or http://nextgraph.org/ns#
+
+did:ng:n:g:ns#post/rich
+ng:class => shortcut for did:ng:n:g:ns#class
+a rdfs:Class
+a ng:class
+did:ng:o:xxxx:yy:yy
+did:ng:n:xx.xx#name
+did:ng:n:x: curated list of ontologies
+did:ng:k common list of things (keyword)
+did:ng:n:c common data
+did:ng:n:z: curated list of external apps and services
+http://nextgraph.org/ns# => the ng: ontology (did:ng:n:g:ns#)
+
+ng:compat -> owl:unionOf rdf:List (alphabetical order, including itself as first element)
+
+-->
+<Icon {...config} variation="outline" color="black" icon={find(dataClass)} />
diff --git a/ng-app/src/lib/Install.svelte b/ng-app/src/lib/Install.svelte
index 1b1af5a..1a6e406 100644
--- a/ng-app/src/lib/Install.svelte
+++ b/ng-app/src/lib/Install.svelte
@@ -19,7 +19,7 @@
   import { onMount } from "svelte";
 
   let top;
-  let display_has_wallets_warning: boolean;
+  export let display_has_wallets_warning: boolean;
 
   async function bootstrap() {
     scrollToTop();
@@ -42,7 +42,7 @@
   <p class="max-w-sm">
     <b>NextGraph App</b> is available for download as a native app for your
     mobile, tablet, laptop and desktop.<br /> The app supports iOS, Android, Linux,
-    macOS, Windows and all other platforms that can run a modern web browser.
+    macOS, Windows, or any other platform with a modern browser.
   </p>
   {#if display_has_wallets_warning}
     <Alert color="yellow" class="mt-5 block">
@@ -55,7 +55,7 @@
     <a href="#/">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -75,7 +75,7 @@
     <a href="https://nextgraph.org/download/#android">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -95,7 +95,7 @@
     <a href="#/">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -116,7 +116,7 @@
     <a href="https://nextgraph.org/download/#macos">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -128,7 +128,7 @@
             d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
           /></svg
         >
-        Download DMG for macOS
+        Download for macOS
       </button>
     </a>
   </div>
@@ -137,7 +137,7 @@
     <a href="https://nextgraph.org/download/#linux">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -149,7 +149,7 @@
             d="M12.504 0c-.155 0-.315.008-.48.021-4.226.333-3.105 4.807-3.17 6.298-.076 1.092-.3 1.953-1.05 3.02-.885 1.051-2.127 2.75-2.716 4.521-.278.832-.41 1.684-.287 2.489a.424.424 0 00-.11.135c-.26.268-.45.6-.663.839-.199.199-.485.267-.797.4-.313.136-.658.269-.864.68-.09.189-.136.394-.132.602 0 .199.027.4.055.536.058.399.116.728.04.97-.249.68-.28 1.145-.106 1.484.174.334.535.47.94.601.81.2 1.91.135 2.774.6.926.466 1.866.67 2.616.47.526-.116.97-.464 1.208-.946.587-.003 1.23-.269 2.26-.334.699-.058 1.574.267 2.577.2.025.134.063.198.114.333l.003.003c.391.778 1.113 1.132 1.884 1.071.771-.06 1.592-.536 2.257-1.306.631-.765 1.683-1.084 2.378-1.503.348-.199.629-.469.649-.853.023-.4-.2-.811-.714-1.376v-.097l-.003-.003c-.17-.2-.25-.535-.338-.926-.085-.401-.182-.786-.492-1.046h-.003c-.059-.054-.123-.067-.188-.135a.357.357 0 00-.19-.064c.431-1.278.264-2.55-.173-3.694-.533-1.41-1.465-2.638-2.175-3.483-.796-1.005-1.576-1.957-1.56-3.368.026-2.152.236-6.133-3.544-6.139zm.529 3.405h.013c.213 0 .396.062.584.198.19.135.33.332.438.533.105.259.158.459.166.724 0-.02.006-.04.006-.06v.105a.086.086 0 01-.004-.021l-.004-.024a1.807 1.807 0 01-.15.706.953.953 0 01-.213.335.71.71 0 00-.088-.042c-.104-.045-.198-.064-.284-.133a1.312 1.312 0 00-.22-.066c.05-.06.146-.133.183-.198.053-.128.082-.264.088-.402v-.02a1.21 1.21 0 00-.061-.4c-.045-.134-.101-.2-.183-.333-.084-.066-.167-.132-.267-.132h-.016c-.093 0-.176.03-.262.132a.8.8 0 00-.205.334 1.18 1.18 0 00-.09.4v.019c.002.089.008.179.02.267-.193-.067-.438-.135-.607-.202a1.635 1.635 0 01-.018-.2v-.02a1.772 1.772 0 01.15-.768c.082-.22.232-.406.43-.533a.985.985 0 01.594-.2zm-2.962.059h.036c.142 0 .27.048.399.135.146.129.264.288.344.465.09.199.14.4.153.667v.004c.007.134.006.2-.002.266v.08c-.03.007-.056.018-.083.024-.152.055-.274.135-.393.2.012-.09.013-.18.003-.267v-.015c-.012-.133-.04-.2-.082-.333a.613.613 0 00-.166-.267.248.248 0 00-.183-.064h-.021c-.071.006-.13.04-.186.132a.552.552 0 00-.12.27.944.944 0 00-.023.33v.015c.012.135.037.2.08.334.046.134.098.2.166.268.01.009.02.018.034.024-.07.057-.117.07-.176.136a.304.304 0 01-.131.068 2.62 2.62 0 01-.275-.402 1.772 1.772 0 01-.155-.667 1.759 1.759 0 01.08-.668 1.43 1.43 0 01.283-.535c.128-.133.26-.2.418-.2zm1.37 1.706c.332 0 .733.065 1.216.399.293.2.523.269 1.052.468h.003c.255.136.405.266.478.399v-.131a.571.571 0 01.016.47c-.123.31-.516.643-1.063.842v.002c-.268.135-.501.333-.775.465-.276.135-.588.292-1.012.267a1.139 1.139 0 01-.448-.067 3.566 3.566 0 01-.322-.198c-.195-.135-.363-.332-.612-.465v-.005h-.005c-.4-.246-.616-.512-.686-.71-.07-.268-.005-.47.193-.6.224-.135.38-.271.483-.336.104-.074.143-.102.176-.131h.002v-.003c.169-.202.436-.47.839-.601.139-.036.294-.065.466-.065zm2.8 2.142c.358 1.417 1.196 3.475 1.735 4.473.286.534.855 1.659 1.102 3.024.156-.005.33.018.513.064.646-1.671-.546-3.467-1.089-3.966-.22-.2-.232-.335-.123-.335.59.534 1.365 1.572 1.646 2.757.13.535.16 1.104.021 1.67.067.028.135.06.205.067 1.032.534 1.413.938 1.23 1.537v-.043c-.06-.003-.12 0-.18 0h-.016c.151-.467-.182-.825-1.065-1.224-.915-.4-1.646-.336-1.77.465-.008.043-.013.066-.018.135-.068.023-.139.053-.209.064-.43.268-.662.669-.793 1.187-.13.533-.17 1.156-.205 1.869v.003c-.02.334-.17.838-.319 1.35-1.5 1.072-3.58 1.538-5.348.334a2.645 2.645 0 00-.402-.533 1.45 1.45 0 00-.275-.333c.182 0 .338-.03.465-.067a.615.615 0 00.314-.334c.108-.267 0-.697-.345-1.163-.345-.467-.931-.995-1.788-1.521-.63-.4-.986-.87-1.15-1.396-.165-.534-.143-1.085-.015-1.645.245-1.07.873-2.11 1.274-2.763.107-.065.037.135-.408.974-.396.751-1.14 2.497-.122 3.854a8.123 8.123 0 01.647-2.876c.564-1.278 1.743-3.504 1.836-5.268.048.036.217.135.289.202.218.133.38.333.59.465.21.201.477.335.876.335.039.003.075.006.11.006.412 0 .73-.134.997-.268.29-.134.52-.334.74-.4h.005c.467-.135.835-.402 1.044-.7zm2.185 8.958c.037.6.343 1.245.882 1.377.588.134 1.434-.333 1.791-.765l.211-.01c.315-.007.577.01.847.268l.003.003c.208.199.305.53.391.876.085.4.154.78.409 1.066.486.527.645.906.636 1.14l.003-.007v.018l-.003-.012c-.015.262-.185.396-.498.595-.63.401-1.746.712-2.457 1.57-.618.737-1.37 1.14-2.036 1.191-.664.053-1.237-.2-1.574-.898l-.005-.003c-.21-.4-.12-1.025.056-1.69.176-.668.428-1.344.463-1.897.037-.714.076-1.335.195-1.814.12-.465.308-.797.641-.984l.045-.022zm-10.814.049h.01c.053 0 .105.005.157.014.376.055.706.333 1.023.752l.91 1.664.003.003c.243.533.754 1.064 1.189 1.637.434.598.77 1.131.729 1.57v.006c-.057.744-.48 1.148-1.125 1.294-.645.135-1.52.002-2.395-.464-.968-.536-2.118-.469-2.857-.602-.369-.066-.61-.2-.723-.4-.11-.2-.113-.602.123-1.23v-.004l.002-.003c.117-.334.03-.752-.027-1.118-.055-.401-.083-.71.043-.94.16-.334.396-.4.69-.533.294-.135.64-.202.915-.47h.002v-.002c.256-.268.445-.601.668-.838.19-.201.38-.336.663-.336zm7.159-9.074c-.435.201-.945.535-1.488.535-.542 0-.97-.267-1.28-.466-.154-.134-.28-.268-.373-.335-.164-.134-.144-.333-.074-.333.109.016.129.134.199.2.096.066.215.2.36.333.292.2.68.467 1.167.467.485 0 1.053-.267 1.398-.466.195-.135.445-.334.648-.467.156-.136.149-.267.279-.267.128.016.034.134-.147.332a8.097 8.097 0 01-.69.468zm-1.082-1.583V5.64c-.006-.02.013-.042.029-.05.074-.043.18-.027.26.004.063 0 .16.067.15.135-.006.049-.085.066-.135.066-.055 0-.092-.043-.141-.068-.052-.018-.146-.008-.163-.065zm-.551 0c-.02.058-.113.049-.166.066-.047.025-.086.068-.14.068-.05 0-.13-.02-.136-.068-.01-.066.088-.133.15-.133.08-.031.184-.047.259-.005.019.009.036.03.03.05v.02h.003z"
           /></svg
         >
-        Download Ubuntu package
+        Download Linux package
       </button>
     </a>
   </div>
@@ -158,7 +158,7 @@
     <a href="https://nextgraph.org/download/#windows">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           role="img"
@@ -170,7 +170,7 @@
             d="M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.4H10.949M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-12.9-1.801"
           /></svg
         >
-        Download Windows installer
+        Download for Windows
       </button>
     </a>
   </div>
@@ -179,7 +179,7 @@
     <a href="https://nextgraph.org/self-host">
       <button
         tabindex="-1"
-        class="text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mr-2 mb-2"
+        class="choice-button text-primary-700 bg-primary-100 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
       >
         <svg
           fill="currentColor"
@@ -187,11 +187,11 @@
           role="img"
           viewBox="0 0 24 24"
           xmlns="http://www.w3.org/2000/svg"
-          ><title>Google Chrome</title><path
+          ><path
             d="M12 0C8.21 0 4.831 1.757 2.632 4.501l3.953 6.848A5.454 5.454 0 0 1 12 6.545h10.691A12 12 0 0 0 12 0zM1.931 5.47A11.943 11.943 0 0 0 0 12c0 6.012 4.42 10.991 10.189 11.864l3.953-6.847a5.45 5.45 0 0 1-6.865-2.29zm13.342 2.166a5.446 5.446 0 0 1 1.45 7.09l.002.001h-.002l-5.344 9.257c.206.01.413.016.621.016 6.627 0 12-5.373 12-12 0-1.54-.29-3.011-.818-4.364zM12 16.364a4.364 4.364 0 1 1 0-8.728 4.364 4.364 0 0 1 0 8.728Z"
           /></svg
         >
-        Installation on other platforms
+        Other platforms
       </button>
     </a>
   </div>
diff --git a/ng-app/src/lib/Test.svelte b/ng-app/src/lib/Test.svelte
index 0fd1079..08e915a 100644
--- a/ng-app/src/lib/Test.svelte
+++ b/ng-app/src/lib/Test.svelte
@@ -25,6 +25,7 @@
   import { link } from "svelte-spa-router";
   import { onMount, onDestroy, tick } from "svelte";
   import { Button } from "flowbite-svelte";
+  import DataClassIcon from "./DataClassIcon.svelte";
 
   let is_tauri = import.meta.env.TAURI_PLATFORM;
 
diff --git a/ng-app/src/lib/ZeraIcon.svelte b/ng-app/src/lib/ZeraIcon.svelte
new file mode 100644
index 0000000..61ad4e2
--- /dev/null
+++ b/ng-app/src/lib/ZeraIcon.svelte
@@ -0,0 +1,120 @@
+<!--
+// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
+// All rights reserved.
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
+// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+-->
+
+<script lang="ts">
+  import {
+    Icon,
+    BugAnt,
+    DocumentText,
+    Window,
+    CodeBracket,
+    SquaresPlus,
+    ViewfinderCircle,
+    ArrowsPointingOut,
+    Cube,
+    Briefcase,
+    MagnifyingGlass,
+    RocketLaunch,
+    Sun,
+    TableCells,
+    ListBullet,
+    RectangleGroup,
+    Squares2x2,
+    MapPin,
+    CircleStack,
+    Envelope,
+    GlobeAlt,
+    DocumentChartBar,
+    Document,
+    ClipboardDocumentList,
+    Photo,
+    Film,
+    RectangleStack,
+    Microphone,
+    MusicalNote,
+    Ticket,
+    CursorArrowRays,
+    Megaphone,
+    User,
+    Clock,
+    CalendarDays,
+    Calendar,
+    Stop,
+    Flag,
+    HandRaised,
+    Newspaper,
+    PencilSquare,
+    CubeTransparent,
+    PresentationChartBar,
+    QuestionMarkCircle,
+    CheckCircle,
+    ChartPie,
+    Bars3BottomLeft,
+    Link,
+    Square2Stack,
+    Clipboard,
+    StopCircle,
+    Share,
+    Play,
+    DocumentArrowDown,
+    DocumentArrowUp,
+    CloudArrowUp,
+    CloudArrowDown,
+    Beaker,
+    Eye,
+  } from "svelte-heros-v2";
+
+  export let config = {};
+  export let zera: string;
+
+  const exact_mapping = {
+    json_ld_editor: TableCells,
+    json_editor: TableCells,
+    triple_editor: Share,
+    rdf_viewer: CircleStack,
+    graph_viewer: Sun,
+    sparql_query: RocketLaunch,
+    sparnatural: CursorArrowRays,
+    graphql: Cube,
+    invoke: Play,
+    ontology_viewer: ArrowsPointingOut,
+    download: DocumentArrowDown,
+    post_edit: PencilSquare,
+    file: Document,
+    source: CodeBracket,
+    post: DocumentText,
+    pad: Square2Stack,
+    card: Clipboard,
+    gallery: RectangleStack,
+    load_graph: CloudArrowUp,
+    load: DocumentArrowUp,
+    dump: CloudArrowDown,
+    ext: GlobeAlt,
+    app_store: SquaresPlus,
+    app_editor: Beaker,
+    list: ListBullet,
+    grid: Squares2x2,
+    view: Eye,
+  };
+
+  const prefix_mapping = {};
+
+  const find = (t) => {
+    let e = exact_mapping[t];
+    if (e) return e;
+    for (let prefix of Object.entries(prefix_mapping)) {
+      if (t.startsWith(prefix[0])) return prefix[1];
+    }
+    return BugAnt;
+  };
+</script>
+
+<Icon {...config} variation="outline" color="black" icon={find(zera)} />
diff --git a/ng-app/src/routes/Install.svelte b/ng-app/src/routes/Install.svelte
index 6b6a7c3..38bf2d7 100644
--- a/ng-app/src/routes/Install.svelte
+++ b/ng-app/src/routes/Install.svelte
@@ -18,13 +18,11 @@
   import CenteredLayout from "../lib/CenteredLayout.svelte";
   import { has_wallets } from "../store";
 
-  let display_has_wallets_warning: boolean = $has_wallets != 0;
+  let display_has_wallets_warning = $has_wallets != 0;
   let unsubscribe;
   onMount(() => {});
 
-  onDestroy(() => {
-    unsubscribe();
-  });
+  onDestroy(() => {});
 </script>
 
 <CenteredLayout>
diff --git a/ng-app/src/routes/URI.svelte b/ng-app/src/routes/NURI.svelte
similarity index 95%
rename from ng-app/src/routes/URI.svelte
rename to ng-app/src/routes/NURI.svelte
index dbfa686..3aa692f 100644
--- a/ng-app/src/routes/URI.svelte
+++ b/ng-app/src/routes/NURI.svelte
@@ -19,6 +19,6 @@
   <div
     class="h-screen aspect-[3/5] pazzleline max-w-[720px] bg-yellow-300 inner"
   >
-    <p>nextgraph URI {params[1]}</p>
+    <p>Nextgraph URI {params[1]}</p>
   </div>
 </div>
diff --git a/ng-app/src/store.ts b/ng-app/src/store.ts
index 8771ef8..7478766 100644
--- a/ng-app/src/store.ts
+++ b/ng-app/src/store.ts
@@ -9,9 +9,101 @@
 
 import { writable, readable, readonly, derived, get } from "svelte/store";
 import ng from "./api";
+import { official_classes } from "./classes";
+import { official_apps, official_services } from "./zeras";
 
 let all_branches = {};
 
+
+let loaded_external_apps = {};
+
+export const load_app = async (appName: string) => {
+
+    if (appName.startsWith("n:g:z")) {
+        let app = official_apps[appName];
+        if (!app) throw new Error("Unknown official app");
+        return await import(`./apps/${app["ng:b"]}.svelte`);
+    } else {
+        //TODO: load external app from its repo
+        // TODO: return IFrame component
+    }
+
+};
+
+export const invoke_service = async (serviceName: string, nuri:string, args: object) => {
+
+    if (serviceName.startsWith("n:g:z")) {
+        let service = official_services[serviceName];
+        if (!service) throw new Error("Unknown official service");
+        // TODO: do this in WebWorker
+        // TODO: if on native app or CLI: use deno
+        //return await ng.app_invoke(serviceName[6..], nuri, args);
+    } else {
+        // TODO: if on webapp: only allow those invocations from IFrame of external app or from n:g:z:external_service_invoke (which runs in an IFrame) and run it from webworker
+        // TODO: if on native app or CLI: use deno
+        // TODO: load external service from its repo
+    }
+
+};
+
+
+export const cur_tab = writable({
+    cur_store: {
+        has_outer : {
+            nuri_trail: ":v:l"
+        },
+        type: "public", // "protected", "private", "group", "dialog",
+        favicon: "",
+        title: "Group B",
+    },
+    cur_branch: {
+        b: "b:xxx", //branch id (can be null if not of type "branch")
+        c: "c:xxx", //commit(s) id
+        type: "main", // "stream", "detached", "branch", "in_memory" (does not save)
+        display: "c:X", // or main or stream or a:xx or branch:X (only 7 chars)
+        attachments: 1,
+        class: "data/graph",
+        title: false,
+        icon: false,
+        description: "",
+        app: "n:g:z:json_ld_editor", // current app being used
+    },
+    view_or_edit: false,
+    graph_viewer: "n:g:z:json_ld_editor", // selected viewer
+    graph_editor: "n:g:z:json_ld_editor", // selected editor
+    discrete_viewer: "n:g:z:json_ld_editor", // selected viewer
+    discrete_editor: "n:g:z:json_ld_editor", // selected editor
+    graph_viewers: ["n:g:z:json_ld_editor"], // list of available viewers
+    graph_editors: ["n:g:z:json_ld_editor"], // list of available editors
+    discrete_viewers: [], // list of available viewers
+    discrete_editors: [], // list of available editors
+    find: false,//or string to find
+    graph_or_discrete: true,
+    read_cap: 'r:',
+    doc: {
+        is_store: false,
+        is_member: false,
+        can_edit: false,
+        live_edit: true,
+        title: "Doc A",
+        authors: "",
+        icon: "",
+        description: "",
+        stream : {
+            notif: 1,
+            last: "",
+        },
+        live_editors: {
+
+        },
+    },
+    folders_pane: false,
+    toc_pane: false,
+    right_pane: false, // "folders", "toc", "branches", "files", "history", "comments", "info", "chat"
+    action: false, // "view_as", "edit_with", "share", "react", "repost", "copy", "dm_author", "new_block", "notifs", "schema", "signature", "permissions", "query",
+
+});
+
 export const opened_wallets = writable({});
 
 /// { wallet:, id: }
diff --git a/ng-app/src/zeras.ts b/ng-app/src/zeras.ts
new file mode 100644
index 0000000..683b517
--- /dev/null
+++ b/ng-app/src/zeras.ts
@@ -0,0 +1,629 @@
+
+// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
+// All rights reserved.
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
+// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+// "n:g:z:hide" >> hides when in viewer mode
+//"n:g:z:json_ld_editor", "n:g:z:json_editor", "n:g:z:triple_editor", "n:g:z:rdf_viewer:turtle", "n:g:z:rdf_viewer:n3", "n:g:z:rdf_viewer:json_ld", "n:g:z:rdf_viewer:graph",
+//"n:g:z:sparql_query:yasgui", "n:g:z:sparql_query:sparnatural", "n:g:z:graphql_query", "n:g:z:sparql_update:yasgui", "n:g:z:ontology_editor", "n:g:z:owl_viewer", "n:g:z:sparql:invoke", "n:g:z:graphql:invoke", "n:g:z:dump_download",
+// "n:g:z:post_rich_editor", "n:g:z:post_md_editor", "n:g:z:code_editor", "n:g:z:file_viewer", "n:g:z:file_source", "n:g:z:crdt_source_viewer:xml", "n:g:z:crdt_source_viewer:json", "n:g:z:crdt_source_viewer:text", "n:g:z:crdt_source_viewer:rdf"
+//"n:g:z:post:rich", "n:g:z:post:md", "n:g:z:text", "n:g:z:pre", "n:g:z:pad", "n:g:z:card", "n:g:z:gallery", "n:g:z:columns", "n:g:z:tree", "n:g:z:summary", "n:g:z:list", "n:g:z:grid", "n:g:z:list_n_post", "n:g:z:grid_n_post", "n:g:z:board", 
+//"n:g:z:map", "n:g:z:chart", "n:g:z:pivot", "n:g:z:timeline", "n:g:z:email", "n:g:z:web_archive", "n:g:z:diagram_editor", "n:g:z:pdf", "n:g:z:latex", "n:g:z:media", "n:g:z:media_editor", 
+//"n:g:z:service_editor", "n:g:z:service_invoke", "n:g:z:external_service_invoke", "n:g:z:contract", "n:g:z:text_query", "n:g:z:web_query", "n:g:z:scan_qrcode", "n:g:z:upload_file",
+//"n:g:z:messenger", "n:g:z:group", "n:g:z:contact", "n:g:z:event", "n:g:z:calendar", "n:g:z:scheduler",
+//"n:g:z:task", "n:g:z:project", "n:g:z:issue", "n:g:z:form_editor", "n:g:z:form_filler", "n:g:z:cad", "n:g:z:slides", "n:g:z:question", "n:g:z:poll",
+//"n:g:z:app_store", "n:g:z:app_editor", "n:xxx.xx.xx:yy", "o:xx:yy:zz"
+
+export const official_apps = {
+    "n:g:z:json_ld_editor": {
+        "ng:n": "JSON-LD editor",
+        "ng:a": "View and edit the RDF Graph as JSON-LD",
+        "ng:c": "app", 
+        "ng:u": "json_ld_editor",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:json_ld_editor",
+        "ng:b": "JsonLdEditor",
+        "ng:o": ["data/graph"],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:json_editor": {
+        "ng:n": "JSON editor",
+        "ng:a": "View and edit your JSON data",
+        "ng:c": "app", 
+        "ng:u": "json_editor",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:json_editor",
+        "ng:b": "JsonEditor",
+        "ng:o": ["data/json","data/array","data/map"],
+        "ng:w": ["data/json","data/array","data/map"],
+    },
+    "n:g:z:triple_editor": {
+        "ng:n": "Graph triples",
+        "ng:a": "Edit your RDF Graph as triples",
+        "ng:c": "app", 
+        "ng:u": "triple_editor",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:triple_editor",
+        "ng:b": "TripleEditor",
+        "ng:o": ["data/graph"],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:rdf_viewer:turtle": { // https://github.com/highlightjs/highlightjs-turtle/tree/master
+        "ng:n": "Turtle",
+        "ng:a": "View your RDF Graph in Turtle format",
+        "ng:c": "app", 
+        "ng:u": "rdf_viewer",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:rdf_viewer:turtle",
+        "ng:b": "TurtleViewer",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+    },
+    "n:g:z:rdf_viewer:n3": { // ?
+        "ng:n": "N3",
+        "ng:a": "View your RDF Graph in N3 format",
+        "ng:c": "app", 
+        "ng:u": "rdf_viewer",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:rdf_viewer:n3",
+        "ng:b": "N3Viewer",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+    },
+    "n:g:z:rdf_viewer:json_ld": { // highlight.js JSON
+        "ng:n": "JSON-LD",
+        "ng:a": "View your RDF Graph in N3 format",
+        "ng:c": "app", 
+        "ng:u": "rdf_viewer",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:rdf_viewer:json_ld",
+        "ng:b": "JsonLdViewer",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+    },
+    "n:g:z:rdf_viewer:graph": {
+        "ng:n": "Graph Explorer",
+        "ng:a": "View your RDF Graph as interactive visualization",
+        "ng:c": "app", 
+        "ng:u": "graph_viewer",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:rdf_viewer:graph",
+        "ng:b": "GraphViewer", // GraphExplorer https://github.com/zazuko/graph-explorer !! AGPL
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+    },
+    "n:g:z:sparql_query:yasgui": {
+        "ng:n": "SPARQL Query",
+        "ng:a": "View, edit and invoke your Graph SPARQL query",
+        "ng:c": "app", 
+        "ng:u": "sparql_query",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql_query:yasgui",
+        "ng:b": "SparqlQueryEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
+        "ng:o": [],
+        "ng:w": ["query/sparql"],
+    },
+    "n:g:z:sparql_query:sparnatural": {
+        "ng:n": "SPARQL natural Query",
+        "ng:a": "View, edit and invoke your Graph SPARQL query with SPARnatural tool",
+        "ng:c": "app", 
+        "ng:u": "sparnatural",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql_query:sparnatural",
+        "ng:b": "SparNaturalEditor",
+        "ng:o": [],
+        "ng:w": ["query/sparql"],
+    },
+    "n:g:z:graphql_query": {
+        "ng:n": "GraphQL Query",
+        "ng:a": "View, edit and invoke your GraphQL query",
+        "ng:c": "app", 
+        "ng:u": "graphql",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:graphql_query",
+        "ng:b": "GraphqlEditor",
+        "ng:o": [],
+        "ng:w": ["query/graphql"],
+    },
+    "n:g:z:sparql_update:yasgui": {
+        "ng:n": "SPARQL Update",
+        "ng:a": "View, edit and invoke your Graph SPARQL Update",
+        "ng:c": "app",
+        "ng:u": "sparql_query",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql_update:yasgui",
+        "ng:b": "SparqlUpdateEditor", // YASGUI of Zazuko https://github.com/zazuko/trifid/tree/main/packages/yasgui
+        "ng:o": [],
+        "ng:w": ["query/sparql_update"],
+    },
+    "n:g:z:ontology_editor": {
+        "ng:n": "Ontology editor",
+        "ng:a": "Edit your Ontology",
+        "ng:c": "app",
+        "ng:u": "json_ld_editor",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:ontology_editor",
+        "ng:b": "JsonLdEditor",
+        "ng:o": [],
+        "ng:w": ["schema/*"],
+    },
+    "n:g:z:owl_viewer": {
+        "ng:n": "OWL Ontology",
+        "ng:a": "View your OWL Ontology",
+        "ng:c": "app",
+        "ng:u": "ontology_viewer",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:owl_viewer",
+        "ng:b": "OwlViewer", // display with https://github.com/VisualDataWeb/WebVOWL
+        "ng:o": ["schema/owl"],
+        "ng:w": [],
+    },
+    "n:g:z:sparql:invoke": { // displayed with highlight.js https://github.com/highlightjs/highlightjs-turtle/tree/master
+        "ng:n": "SPARQL Invoke",
+        "ng:a": "View and invoke your saved SPARQL query",
+        "ng:c": "app", 
+        "ng:u": "invoke",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql:invoke",
+        "ng:b": "SparqlInvoker",
+        "ng:o": ["query/sparql","query/sparql_update"],
+        "ng:w": [],
+    },
+    "n:g:z:graphql:invoke": { 
+        "ng:n": "GraphQL Invoke",
+        "ng:a": "View and invoke your saved GraphQL query",
+        "ng:c": "app", 
+        "ng:u": "invoke",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:graphql:invoke",
+        "ng:b": "GraphqlInvoker",
+        "ng:o": ["query/graphql"],
+        "ng:w": [],
+    },
+    "n:g:z:dump_download": {
+        "ng:n": "Download",
+        "ng:a": "Download a file containing a document export data",
+        "ng:c": "app", 
+        "ng:u": "download",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_download",
+        "ng:b": "Downloader",
+        "ng:o": ["data/graph","file*","data/*"],
+        "ng:w": [],
+    },
+    "n:g:z:post_rich_editor": {
+        "ng:n": "Post Editor",
+        "ng:a": "Edit your post with ProseMirror",
+        "ng:c": "app", 
+        "ng:u": "post_edit",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:post_rich_editor",
+        "ng:b": "ProseMirrorEditor",
+        "ng:o": [],
+        "ng:w": ["post/rich"],
+    },
+    "n:g:z:post_md_editor": {
+        "ng:n": "Post Editor",
+        "ng:a": "Edit your post with MilkDown",
+        "ng:c": "app", 
+        "ng:u": "post_edit",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:post_md_editor",
+        "ng:b": "MilkDownEditor",
+        "ng:o": [],
+        "ng:w": ["post/md"],
+    },
+    "n:g:z:code_editor": {
+        "ng:n": "Code and Text Editor",
+        "ng:a": "Edit your code/text with CodeMirror",
+        "ng:c": "app", 
+        "ng:u": "post_edit",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:code_editor",
+        "ng:b": "CodeMirrorEditor",
+        "ng:o": [],
+        "ng:w": ["code*","post/text"],
+    },
+    "n:g:z:file_viewer": {
+        "ng:n": "File details",
+        "ng:a": "See details about this file",
+        "ng:c": "app", 
+        "ng:u": "file",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:file_viewer",
+        "ng:b": "FileDetails",
+        "ng:o": ["file*"],
+        "ng:w": ["file*"], // in editor mode: can change the name, and delete the file
+    },
+    "n:g:z:file_source": { // only works for files containing text source (SVG, HTML, JS, CSS, etc...)
+        "ng:n": "File source",
+        "ng:a": "See the source code of this file",
+        "ng:c": "app", 
+        "ng:u": "source",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:file_source",
+        "ng:b": "FileSource",
+        "ng:o": ["file/text"],
+        "ng:w": [],
+    },
+    "n:g:z:crdt_source_viewer:xml": { 
+        "ng:n": "XML source",
+        "ng:a": "See the source code of this document, in XML",
+        "ng:c": "app", 
+        "ng:u": "source",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:crdt_source_viewer:xml",
+        "ng:b": "XmlSource", // displayed with highlight.js , with option to download
+        "ng:o": ["post/rich","post/md","post/html","page","data/xml", "doc/diagram/drawio"],
+        "ng:w": [],
+    },
+    "n:g:z:crdt_source_viewer:json": { 
+        "ng:n": "JSON source",
+        "ng:a": "See the source code of this document, in JSON",
+        "ng:c": "app", 
+        "ng:u": "source",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:crdt_source_viewer:json",
+        "ng:b": "JsonSource", // displayed with highlight.js , with option to download
+        "ng:o": ["data/json", "data/map", "data/array", "data/table", "doc/diagram/jsmind", "doc/diagram/gantt", "doc/diagram/excalidraw", "doc/viz/*", "doc/chart/*", "prod/cad"],
+        "ng:w": [],
+    },
+    "n:g:z:crdt_source_viewer:text": {
+        "ng:n": "Text source",
+        "ng:a": "See the source code of this document, in plain-text",
+        "ng:c": "app", 
+        "ng:u": "source",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:crdt_source_viewer:text",
+        "ng:b": "TextViewer", // displayed with highlight.js , with option to download
+        "ng:o": ["post/text", "post/asciidoc", "code*", "service*", "contract", "query/sparql*","query/graphql","doc/diagram/mermaid","doc/diagram/graphviz","doc/diagram/flowchart",
+                "doc/diagram/sequence","doc/diagram/markmap","doc/diagram/mymind","doc/music*", "doc/maths", "doc/chemistry", "doc/ancientscript", "doc/braille", "media/subtitle"],
+        "ng:w": [],
+    },
+    "n:g:z:crdt_source_viewer:rdf": {
+        "ng:n": "RDF source",
+        "ng:a": "See the source graph of this document, in RDF (turtle)",
+        "ng:c": "app", 
+        "ng:u": "source",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:crdt_source_viewer:rdf",
+        "ng:b": "TurtleViewer", //, with option to download
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+    },
+    "n:g:z:post:rich": {
+        "ng:n": "Post",
+        "ng:a": "View a Rich Post",
+        "ng:c": "app", 
+        "ng:u": "post",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:post:rich",
+        "ng:b": "PostRichViewer", // https://www.npmjs.com/package/prosemirror-to-html-js or https://prosemirror.net/docs/ref/version/0.4.0.html#toDOM https://prosemirror.net/docs/ref/version/0.4.0.html#toHTML
+        "ng:o": ["post/rich"],
+        "ng:w": [],
+    },
+    "n:g:z:post:md": {
+        "ng:n": "Post",
+        "ng:a": "View a Markdown Post",
+        "ng:c": "app", 
+        "ng:u": "post",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:post:md",
+        "ng:b": "PostMdViewer", // https://github.com/wooorm/markdown-rs
+        "ng:o": ["post/md"],
+        "ng:w": [],
+    },
+    "n:g:z:post:text": {
+        "ng:n": "Text",
+        "ng:a": "View a Text Post",
+        "ng:c": "app", 
+        "ng:u": "post",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:post:text", 
+        "ng:b": "TextViewer", // displayed with a <p>
+        "ng:o": ["post/text"],
+        "ng:w": [],
+    },
+    "n:g:z:pre": {
+        "ng:n": "Source Code",
+        "ng:a": "View a Source Code",
+        "ng:c": "app", 
+        "ng:u": "post",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:pre", 
+        "ng:b": "PreTextViewer", // displayed with highlight.js 
+        "ng:o": ["code*","post/text"],
+        "ng:w": [],
+    },
+    "n:g:z:pad": {
+        "ng:n": "Pad",
+        "ng:a": "Pad view of a document",
+        "ng:c": "app", 
+        "ng:u": "pad",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:pad", 
+        "ng:b": "Pad",
+        "ng:o": ["plato/pad"],
+        "ng:w": [],
+    },
+    "n:g:z:card": {
+        "ng:n": "Card",
+        "ng:a": "Card view of a document",
+        "ng:c": "app", 
+        "ng:u": "card",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:card", 
+        "ng:b": "Card",
+        "ng:o": ["plato/card"],
+        "ng:w": [],
+    },
+    "n:g:z:gallery": {
+        "ng:n": "Gallery",
+        "ng:a": "Gallery view of an album or collection",
+        "ng:c": "app", 
+        "ng:u": "gallery",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:gallery", 
+        "ng:b": "Gallery",
+        "ng:o": ["media/album","data/collection"],
+        "ng:w": [],
+    },
+    "n:g:z:app_store": {
+        "ng:n": "App Store",
+        "ng:a": "Install or remove Apps of NextGraph ecosystem",
+        "ng:c": "app", 
+        "ng:u": "app_store",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:app_store", 
+        "ng:b": "AppStore",
+        "ng:o": ["app/z"],
+        "ng:w": [],
+    },
+    "n:g:z:app_editor": {
+        "ng:n": "App editor",
+        "ng:a": "Create and modify your App with NextGraph IDE",
+        "ng:c": "app", 
+        "ng:u": "app_editor",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:app_editor", 
+        "ng:b": "AppEditor",
+        "ng:o": ["app/z"],
+        "ng:w": ["app/z"],
+    },
+    "n:g:z:list": {
+        "ng:n": "List view",
+        "ng:a": "See the content of document as a list",
+        "ng:c": "app", 
+        "ng:u": "list",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:list", 
+        "ng:b": "ListView",
+        "ng:o": ["data/graph"],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:grid": {
+        "ng:n": "Grid view",
+        "ng:a": "See the content of document as a grid",
+        "ng:c": "app", 
+        "ng:u": "grid",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:grid", 
+        "ng:b": "GridView",
+        "ng:o": ["data/graph"],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:media": {
+        "ng:n": "Media view",
+        "ng:a": "View media",
+        "ng:c": "app", 
+        "ng:u": "view",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:media", 
+        "ng:b": "MediaView",
+        "ng:o": ["media/*"],
+        "ng:w": [],
+    },
+    "n:g:z:service_editor": {
+        "ng:n": "Service Editor",
+        "ng:a": "Write and define your Service in Rust or JS/Deno",
+        "ng:c": "app", 
+        "ng:u": "post_edit",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:service_editor",
+        "ng:b": "CodeMirrorEditor",
+        "ng:o": [],
+        "ng:w": ["service/*"],
+    },
+    "n:g:z:service_invoke": {
+        "ng:n": "Service Invoker",
+        "ng:a": "Invoke internal Service, with optional arguments",
+        "ng:c": "app", 
+        "ng:u": "invoke",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:service_invoke",
+        "ng:b": "ServiceInvoker",
+        "ng:o": ["service"],
+        "ng:w": [],
+    },
+    "n:g:z:external_service_invoke": {
+        "ng:n": "Service Invoker",
+        "ng:a": "Invoke the Service, with optional arguments",
+        "ng:c": "app", 
+        "ng:u": "invoke",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:external_service_invoke",
+        "ng:b": "ExternalServiceInvoker",
+        "ng:o": ["service/*"],
+        "ng:w": [],
+    },
+    "n:g:z:upload_file": {
+        "ng:n": "Upload file",
+        "ng:a": "Upload a binary file into a document",
+        "ng:c": "app", 
+        "ng:u": "load",//favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:upload_file",
+        "ng:b": "UploadFile",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    // TODO: "n:g:z:columns", "n:g:z:tree", "n:g:z:summary", "n:g:z:list_n_post", "n:g:z:grid_n_post", "n:g:z:board", 
+    // TODO: "n:g:z:map", "n:g:z:chart", "n:g:z:pivot", "n:g:z:timeline", "n:g:z:email", "n:g:z:web_archive", "n:g:z:diagram_editor", "n:g:z:pdf", "n:g:z:latex", "n:g:z:media_editor", 
+    // TODO: "n:g:z:contract", "n:g:z:text_query", "n:g:z:web_query", "n:g:z:scan_qrcode", 
+    // TODO: "n:g:z:messenger", "n:g:z:group", "n:g:z:contact", "n:g:z:event", "n:g:z:calendar", "n:g:z:scheduler",
+    // TODO: "n:g:z:task", "n:g:z:project", "n:g:z:issue", "n:g:z:form_editor", "n:g:z:form_filler", "n:g:z:cad", "n:g:z:slides", "n:g:z:question", "n:g:z:poll",
+
+};
+
+
+// OFFICIAL SERVICES
+//"n:g:z:dump_rdf:turtle", "n:g:z:dump_rdf:n3", "n:g:z:dump_rdf:json_ld", "n:g:z:load_rdf:turtle", "n:g:z:load_rdf:n3", "n:g:z:load_rdf:json_ld", "n:g:z:load_file", "n:g:z:dump_file", 
+//"n:g:z:dump_json", "n:g:z:dump_xml", "n:g:z:dump_text", "n:g:z:load_json", "n:g:z:load_xml", "n:g:z:load_text", "n:g:z:load_md", "n:g:z:sparql_query", "n:g:z:sparql_update", "n:g:z:dump_crdt_source", "n:g:z:dump_ng_html_file", "n:g:z:dump_ng_file"
+
+export const official_services = {
+    "n:g:z:dump_rdf:turtle": {
+        "ng:n": "Turtle export",
+        "ng:a": "Export quads of RDF Graphs in Turtle format",
+        "ng:c": "service",
+        "ng:u": "data",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_rdf:turtle",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/text/turtle"],
+    },
+    "n:g:z:dump_rdf:n3": {
+        "ng:n": "N3 export",
+        "ng:a": "Export quads of RDF Graphs in N3 format",
+        "ng:c": "service",
+        "ng:u": "data",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_rdf:n3",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/text/n3"],
+    },
+    "n:g:z:dump_rdf:json_ld": {
+        "ng:n": "JSON-LD export",
+        "ng:a": "Export quads of RDF Graphs in JSON-LD format",
+        "ng:c": "service",
+        "ng:u": "data",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_rdf:json_ld",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/application/ld+json"],
+    },
+    "n:g:z:load_rdf:turtle": {
+        "ng:n": "Import Turtle triples",
+        "ng:a": "Import Turtle triples into the document",
+        "ng:c": "service",
+        "ng:u": "load_graph",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_rdf:turtle",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:load_rdf:n3": {
+        "ng:n": "Import N3 triples",
+        "ng:a": "Import N3 triples into the document",
+        "ng:c": "service",
+        "ng:u": "load_graph",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_rdf:n3",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:load_rdf:json_ld": {
+        "ng:n": "Import JSON-LD triples",
+        "ng:a": "Import JSON-LD triples into the document",
+        "ng:c": "service",
+        "ng:u": "load_graph",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_rdf:json_ld",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:load_file": {
+        "ng:n": "Add file",
+        "ng:a": "Add a binary file in the document",
+        "ng:c": "service",
+        "ng:u": "load",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_file",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:dump_file": {
+        "ng:n": "Export file",
+        "ng:a": "Get the binary content of a file",
+        "ng:c": "service",
+        "ng:u": "dump",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_file",
+        "ng:o": ["file*"],
+        "ng:result": ["file/iana/*"],
+    },
+    "n:g:z:dump_json": {
+        "ng:n": "JSON export",
+        "ng:a": "Export JSON content of document",
+        "ng:c": "service",
+        "ng:u": "data",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_json",
+        "ng:o": ["data/json", "data/map", "data/array", "data/table", "doc/diagram/jsmind", "doc/diagram/gantt", "doc/diagram/excalidraw", "doc/viz/*", "doc/chart/*", "prod/cad"],
+        "ng:w": [],
+        "ng:result": ["file/iana/application/json"],
+    },
+    "n:g:z:dump_xml": {
+        "ng:n": "XML export",
+        "ng:a": "Export XML content of document",
+        "ng:c": "service",
+        "ng:u": "data",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_xml",
+        "ng:o": ["post/rich","post/md","post/html","page","data/xml", "doc/diagram/drawio"],
+        "ng:w": [],
+        "ng:result": ["file/iana/text/xml"],
+    },
+    "n:g:z:dump_text": {
+        "ng:n": "Text export",
+        "ng:a": "Export plain-text content of document",
+        "ng:c": "service",
+        "ng:u": "dump",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_text",
+        "ng:o": ["post/text", "post/asciidoc", "code*", "service*", "contract", "query/sparql*","query/graphql","doc/diagram/mermaid","doc/diagram/graphviz","doc/diagram/flowchart",
+        "doc/diagram/sequence","doc/diagram/markmap","doc/diagram/mymind","doc/music*", "doc/maths", "doc/chemistry", "doc/ancientscript", "doc/braille", "media/subtitle"],
+        "ng:w": [],
+        "ng:result": ["file/iana/text/plain"],
+    },
+    "n:g:z:dump_ng_html_file": {
+        "ng:n": "NextGraph Standalone file",
+        "ng:a": "Get a standalone HTML file of this Document",
+        "ng:c": "service",
+        "ng:u": "ext",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_ng_html_file",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/text/html"],
+    },
+    "n:g:z:load_json": {
+        "ng:n": "Import JSON",
+        "ng:a": "Import some JSON into the document",
+        "ng:c": "service",
+        "ng:u": "load",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_json",
+        "ng:o": [],
+        "ng:w": ["data/json","data/map", "data/array"],
+    },
+    "n:g:z:load_xml": {
+        "ng:n": "Import XML",
+        "ng:a": "Import some XML into the document",
+        "ng:c": "service",
+        "ng:u": "load",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_xml",
+        "ng:o": [],
+        "ng:w": ["data/xml"],
+    },
+    "n:g:z:load_text": {
+        "ng:n": "Import Text",
+        "ng:a": "Import some text into the document",
+        "ng:c": "service",
+        "ng:u": "load",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_text",
+        "ng:o": [],
+        "ng:w": ["post/text","post/rich","post/md"],
+    },
+    "n:g:z:load_md": {
+        "ng:n": "Import Markdown",
+        "ng:a": "Import some Markdown into the document",
+        "ng:c": "service",
+        "ng:u": "load",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:load_md",
+        "ng:o": [],
+        "ng:w": ["post/md"],
+    },
+    "n:g:z:sparql_query": {
+        "ng:n": "SPARQL query",
+        "ng:a": "Invoke a SPARQL Query",
+        "ng:c": "service",
+        "ng:u": "sparql_query",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql_query",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/application/sparql-results+json","file/iana/application/json"]
+    },
+    "n:g:z:sparql_update": {
+        "ng:n": "SPARQL update",
+        "ng:a": "Invoke a SPARQL Update",
+        "ng:c": "service",
+        "ng:u": "sparql_query",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:sparql_update",
+        "ng:o": [],
+        "ng:w": ["data/graph"],
+    },
+    "n:g:z:dump_crdt_source": { // uses dump_rdf, dump_text, dump_json or dump_xml depending on the CRDT type
+        "ng:n": "Export source",
+        "ng:a": "Export source of document as text file",
+        "ng:c": "service",
+        "ng:u": "source",// favicon. can be a did:ng:j 
+        "ng:g": "n:g:z:dump_crdt_source",
+        "ng:o": ["data/graph"],
+        "ng:w": [],
+        "ng:result": ["file/iana/*"]
+    },
+};
\ No newline at end of file
diff --git a/ng-net/src/app_protocol.rs b/ng-net/src/app_protocol.rs
index a062888..70dfd44 100644
--- a/ng-net/src/app_protocol.rs
+++ b/ng-net/src/app_protocol.rs
@@ -560,7 +560,7 @@ pub struct DocAddFile {
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub struct DocCreate {
     store: StoreRepo,
-    content_type: BranchContentType,
+    class: String,
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize)]
@@ -579,7 +579,7 @@ pub enum AppRequestPayloadV0 {
     Delete(DocDelete),
     //Invoke(InvokeArguments),
     SmallFilePut(SmallFile),
-    RandomAccessFilePut(String),                           // content_type
+    RandomAccessFilePut(String), // content_type (iana media type)
     RandomAccessFilePutChunk((u32, serde_bytes::ByteBuf)), // end the upload with an empty vec
 }
 
diff --git a/ng-repo/src/types.rs b/ng-repo/src/types.rs
index d9c4f2e..dcbdbb4 100644
--- a/ng-repo/src/types.rs
+++ b/ng-repo/src/types.rs
@@ -1293,7 +1293,7 @@ pub enum Quorum {
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
 pub enum BranchContentType {
-    GraphOnly,
+    Graph,
     YMap,
     YXml,
     YText,
@@ -1302,8 +1302,7 @@ pub enum BranchContentType {
     //Owl,
     //Shacl,
     //Shex,
-    None, // this is used by Store, Overlay and User BranchTypes
-          //Chat,
+    None, // this is used by Overlay and User BranchTypes
 }
 
 /// Branch definition
diff --git a/ng-sdk-js/Cargo.toml b/ng-sdk-js/Cargo.toml
index d9c2455..74f5393 100644
--- a/ng-sdk-js/Cargo.toml
+++ b/ng-sdk-js/Cargo.toml
@@ -29,6 +29,7 @@ once_cell = "1.17.1"
 getrandom = { version = "0.1.1", features = ["wasm-bindgen"] }
 rand =  { version = "0.7", features = ["getrandom"] }
 wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
+sys-locale = { version = "0.3.1", features = ["js"] }
 ng-repo = { path = "../ng-repo" }
 ng-net = { path = "../ng-net" }
 ng-client-ws = { path = "../ng-client-ws" }
diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs
index 73161d0..5d1bcbf 100644
--- a/ng-sdk-js/src/lib.rs
+++ b/ng-sdk-js/src/lib.rs
@@ -26,6 +26,7 @@ use serde_json::json;
 use async_std::stream::StreamExt;
 use js_sys::Array;
 use oxrdf::Triple;
+use sys_locale::get_locales;
 use wasm_bindgen::prelude::*;
 use wasm_bindgen_futures::future_to_promise;
 use wasm_bindgen_futures::JsFuture;
@@ -54,6 +55,11 @@ use nextgraph::local_broker::*;
 
 use crate::model::*;
 
+#[wasm_bindgen]
+pub async fn locales() -> Result<JsValue, JsValue> {
+    Ok(serde_wasm_bindgen::to_value(&get_locales().collect::<Vec<_>>()).unwrap())
+}
+
 #[wasm_bindgen]
 pub async fn get_local_bootstrap(location: String, invite: JsValue) -> JsValue {
     let res = retrieve_local_bootstrap(location, invite.as_string(), false).await;
diff --git a/ngone/web/src/routes/Install.svelte b/ngone/web/src/routes/Install.svelte
index ea196e8..57e9d4e 100644
--- a/ngone/web/src/routes/Install.svelte
+++ b/ngone/web/src/routes/Install.svelte
@@ -21,7 +21,7 @@
   onMount(() => {});
 
   onDestroy(() => {
-    unsubscribe();
+    //unsubscribe();
   });
 </script>
 

From 1e3b6455fe5549604848bea0fb6c859a1043d004 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Thu, 4 Jul 2024 21:21:44 +0300
Subject: [PATCH 5/7] set useDefineForClassFields to false in tsconfig.json for
 dev env on old macos/safari

---
 ng-app/tsconfig.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ng-app/tsconfig.json b/ng-app/tsconfig.json
index d383031..5895c4b 100644
--- a/ng-app/tsconfig.json
+++ b/ng-app/tsconfig.json
@@ -2,7 +2,7 @@
   "extends": "@tsconfig/svelte/tsconfig.json",
   "compilerOptions": {
     "target": "ESNext",
-    "useDefineForClassFields": true,
+    "useDefineForClassFields": false,
     "module": "ESNext",
     "resolveJsonModule": true,
     "baseUrl": ".",

From 6667fcd37f100d85b64cbb1329a47cc10756d934 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Fri, 5 Jul 2024 15:31:49 +0300
Subject: [PATCH 6/7] locales

---
 ng-app/src-tauri/src/lib.rs          | 18 +++++++++++++++++-
 ng-app/src/api.ts                    |  4 ++++
 ng-app/src/lib/CenteredLayout.svelte |  4 +++-
 ng-repo/src/utils.rs                 | 28 ++++++++++++++++++++++++++++
 4 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/ng-app/src-tauri/src/lib.rs b/ng-app/src-tauri/src/lib.rs
index 73db314..58c1e1f 100644
--- a/ng-app/src-tauri/src/lib.rs
+++ b/ng-app/src-tauri/src/lib.rs
@@ -41,7 +41,23 @@ pub type SetupHook = Box<dyn FnOnce(&mut App) -> Result<(), Box<dyn std::error::
 
 #[tauri::command(rename_all = "snake_case")]
 async fn locales() -> Result<Vec<String>, ()> {
-    Ok(get_locales().filter(|lang| lang != "C").collect())
+    Ok(get_locales()
+        .filter_map(|lang| {
+            if lang == "C" || lang == "c" {
+                None
+            } else {
+                let mut split = lang.split('.');
+                let code = split.next().unwrap();
+                let code = code.replace("_", "-");
+                let mut split = code.rsplitn(2, '-');
+                let country = split.next().unwrap();
+                Some(match split.next() {
+                    Some(next) => format!("{}-{}", next, country.to_uppercase()),
+                    None => country.to_string(),
+                })
+            }
+        })
+        .collect())
 }
 
 #[tauri::command(rename_all = "snake_case")]
diff --git a/ng-app/src/api.ts b/ng-app/src/api.ts
index abdc710..7891d6f 100644
--- a/ng-app/src/api.ts
+++ b/ng-app/src/api.ts
@@ -102,6 +102,10 @@ const handler = {
                 let from_js = window.navigator.languages;
                 console.log(from_rust,from_js);
                 for (let lang of from_js) {
+                    let split = lang.split("-");
+                    if (split[1]) {
+                        lang = split[0] + "-" + split[1].toUpperCase();
+                    }
                     if (!from_rust.includes(lang)) { from_rust.push(lang);}
                 }
                 return from_rust;
diff --git a/ng-app/src/lib/CenteredLayout.svelte b/ng-app/src/lib/CenteredLayout.svelte
index cc7114b..4db2a7b 100644
--- a/ng-app/src/lib/CenteredLayout.svelte
+++ b/ng-app/src/lib/CenteredLayout.svelte
@@ -20,7 +20,9 @@
 </script>
 
 <div class="centered">
-  {locales}
+  {#each locales as loc}
+    {loc}&nbsp;
+  {/each}
   <slot />
 </div>
 
diff --git a/ng-repo/src/utils.rs b/ng-repo/src/utils.rs
index c1eb1db..971e012 100644
--- a/ng-repo/src/utils.rs
+++ b/ng-repo/src/utils.rs
@@ -230,3 +230,31 @@ pub fn display_timestamp(ts: &Timestamp) -> String {
 }
 
 pub(crate) type Receiver<T> = mpsc::UnboundedReceiver<T>;
+
+#[cfg(test)]
+mod test {
+    use crate::log::*;
+    #[test]
+    pub fn test_locales() {
+        let list = vec!["C", "c", "aa-bb-cc-dd", "aa-ff_bb.456d"];
+        let res: Vec<String> = list
+            .iter()
+            .filter_map(|lang| {
+                if *lang == "C" || *lang == "c" {
+                    None
+                } else {
+                    let mut split = lang.split('.');
+                    let code = split.next().unwrap();
+                    let code = code.replace("_", "-");
+                    let mut split = code.rsplitn(2, '-');
+                    let country = split.next().unwrap();
+                    Some(match split.next() {
+                        Some(next) => format!("{}-{}", next, country.to_uppercase()),
+                        None => country.to_string(),
+                    })
+                }
+            })
+            .collect();
+        log_debug!("{:?}", res);
+    }
+}

From 91a3a0f36aab27c4aef6beae7d1fc413209a8252 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Fri, 5 Jul 2024 22:59:20 +0300
Subject: [PATCH 7/7] language selection for i18n

---
 ng-app/src/App.svelte                     |  2 +
 ng-app/src/lib/CenteredLayout.svelte      | 93 ++++++++++++++++++++---
 ng-app/src/lib/NoWallet.svelte            |  2 +-
 ng-app/src/routes/Install.svelte          |  2 +-
 ng-app/src/routes/NotFound.svelte         |  2 +-
 ng-app/src/routes/UserRegistered.svelte   |  2 +-
 ng-app/src/routes/WalletCreate.svelte     |  6 +-
 ng-app/src/routes/WalletLogin.svelte      |  4 +-
 ng-app/src/store.ts                       | 28 +++++++
 ng-oxigraph/src/oxigraph/sparql/update.rs |  4 +-
 ngaccount/web/src/routes/Create.svelte    |  2 +-
 ngaccount/web/src/routes/Delete.svelte    |  2 +-
 12 files changed, 125 insertions(+), 24 deletions(-)

diff --git a/ng-app/src/App.svelte b/ng-app/src/App.svelte
index e643f52..7edc732 100644
--- a/ng-app/src/App.svelte
+++ b/ng-app/src/App.svelte
@@ -19,6 +19,7 @@
     active_session,
     close_active_session,
     disconnections_subscribe,
+    select_default_lang,
   } from "./store";
 
   import Home from "./routes/Home.svelte";
@@ -59,6 +60,7 @@
 
   onMount(async () => {
     try {
+      await select_default_lang();
       await disconnections_subscribe();
     } catch (e) {
       //console.log("called disconnections_subscribe twice");
diff --git a/ng-app/src/lib/CenteredLayout.svelte b/ng-app/src/lib/CenteredLayout.svelte
index 4db2a7b..42d7abf 100644
--- a/ng-app/src/lib/CenteredLayout.svelte
+++ b/ng-app/src/lib/CenteredLayout.svelte
@@ -11,19 +11,89 @@
 
 <script lang="ts">
   import ng from "../api";
-  import { onMount } from "svelte";
+  import { onMount, tick } from "svelte";
+  import { current_lang, available_languages } from "../store";
+  import { Language } from "svelte-heros-v2";
 
-  let locales = [];
-  onMount(async () => {
-    locales = await ng.locales();
-  });
+  export let displayFooter = false;
+
+  let changingLang = false;
+
+  const changeLang = () => {
+    changingLang = true;
+    scrollToTop();
+  };
+
+  let top;
+  function scrollToTop() {
+    top.scrollIntoView();
+  }
+
+  const selectLang = async (lang) => {
+    current_lang.set(lang);
+    changingLang = false;
+    await tick();
+    scrollToTop();
+  };
+
+  let tauri_platform = import.meta.env.TAURI_PLATFORM;
+
+  const displayPopup = async (url, title) => {
+    if (!tauri_platform || tauri_platform == "android") {
+      window.open(url, "_blank").focus();
+    } else {
+      await ng.open_window(url, "viewer", title);
+    }
+  };
+
+  const displayNextgraphOrg = async () => {
+    await displayPopup("https://nextgraph.org", "NextGraph.org");
+  };
 </script>
 
-<div class="centered">
-  {#each locales as loc}
-    {loc}&nbsp;
-  {/each}
-  <slot />
+<div bind:this={top}>
+  {#if !changingLang}
+    <div class="centered">
+      <slot />
+    </div>
+    {#if displayFooter}
+      <div class="centered">
+        <div class="mb-20 mt-10">
+          <button
+            on:click={changeLang}
+            class="text-primary-700 bg-[#f6f6f6] bg-none ring-0 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55"
+          >
+            <Language
+              tabindex="-1"
+              class="w-7 h-7 mr-2 transition duration-75  "
+            />Change language <!--note to translator: DO NOT TRANSLATE! it should stay in english always-->
+          </button>
+          <br />
+          <button
+            on:click={displayNextgraphOrg}
+            class="text-primary-700 bg-[#f6f6f6] bg-none ring-0 hover:bg-primary-100/90 focus:ring-4 focus:ring-primary-100/50 font-medium rounded-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-100/55 mb-2"
+            >About NextGraph
+          </button>
+        </div>
+      </div>
+    {/if}
+  {:else}
+    <div class="centered">
+      <ul class="mb-20 mt-10">
+        {#each Object.entries(available_languages) as lang}
+          <li
+            tabindex="0"
+            role="menuitem"
+            class="flex items-center p-2 text-lg mb-2 font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
+            on:keypress={() => selectLang(lang[0])}
+            on:click={() => selectLang(lang[0])}
+          >
+            <span class="mx-3">{lang[1]}</span>
+          </li>
+        {/each}
+      </ul>
+    </div>
+  {/if}
 </div>
 
 <style>
@@ -34,4 +104,7 @@
     text-align: center;
     width: fit-content;
   }
+  li.clickable {
+    cursor: pointer;
+  }
 </style>
diff --git a/ng-app/src/lib/NoWallet.svelte b/ng-app/src/lib/NoWallet.svelte
index 12aa7a1..60fb913 100644
--- a/ng-app/src/lib/NoWallet.svelte
+++ b/ng-app/src/lib/NoWallet.svelte
@@ -16,7 +16,7 @@
   import CenteredLayout from "./CenteredLayout.svelte";
 </script>
 
-<CenteredLayout>
+<CenteredLayout displayFooter={true}>
   <div class="container3">
     <div class="row">
       <Logo class="logo block h-40" alt="NextGraph Logo" />
diff --git a/ng-app/src/routes/Install.svelte b/ng-app/src/routes/Install.svelte
index 38bf2d7..a63edfe 100644
--- a/ng-app/src/routes/Install.svelte
+++ b/ng-app/src/routes/Install.svelte
@@ -25,6 +25,6 @@
   onDestroy(() => {});
 </script>
 
-<CenteredLayout>
+<CenteredLayout displayFooter={true}>
   <Install {display_has_wallets_warning} />
 </CenteredLayout>
diff --git a/ng-app/src/routes/NotFound.svelte b/ng-app/src/routes/NotFound.svelte
index 906e146..4b233b9 100644
--- a/ng-app/src/routes/NotFound.svelte
+++ b/ng-app/src/routes/NotFound.svelte
@@ -14,7 +14,7 @@
   import CenteredLayout from "../lib/CenteredLayout.svelte";
 </script>
 
-<CenteredLayout>
+<CenteredLayout displayFooter={true}>
   <div class="p-8">
     <Alert color="red">
       <span class="font-medium">404</span> Page not found.
diff --git a/ng-app/src/routes/UserRegistered.svelte b/ng-app/src/routes/UserRegistered.svelte
index 870308d..d0aa237 100644
--- a/ng-app/src/routes/UserRegistered.svelte
+++ b/ng-app/src/routes/UserRegistered.svelte
@@ -45,7 +45,7 @@
   });
 </script>
 
-<CenteredLayout>
+<CenteredLayout displayFooter={true}>
   <div class="container3">
     <div class="row">
       <a href="#/">
diff --git a/ng-app/src/routes/WalletCreate.svelte b/ng-app/src/routes/WalletCreate.svelte
index 0e0dfa1..ddfebf2 100644
--- a/ng-app/src/routes/WalletCreate.svelte
+++ b/ng-app/src/routes/WalletCreate.svelte
@@ -396,7 +396,7 @@
   };
 </script>
 
-<CenteredLayout>
+<CenteredLayout displayFooter={true}>
   {#if wait}
     <div class=" max-w-6xl lg:px-8 mx-auto px-4 text-primary-700">
       {#if wait === true}
@@ -705,7 +705,7 @@
             </ul>
           </div>
         </div>
-        <div class="row mb-20">
+        <div class="row mb-10">
           <button
             on:click|once={create_wallet}
             class="text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
@@ -1424,7 +1424,7 @@
           {/if}
           <button
             on:click|once={do_wallet}
-            class="mt-10 mb-20 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
+            class="mt-10 mb-10 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
           >
             <svg
               class="w-8 h-8 mr-2 -ml-1"
diff --git a/ng-app/src/routes/WalletLogin.svelte b/ng-app/src/routes/WalletLogin.svelte
index fe54473..6a1f027 100644
--- a/ng-app/src/routes/WalletLogin.svelte
+++ b/ng-app/src/routes/WalletLogin.svelte
@@ -186,7 +186,7 @@
 </script>
 
 <div bind:this={top}>
-  <CenteredLayout>
+  <CenteredLayout displayFooter={!wallet}>
     {#if error}
       <div class=" max-w-6xl lg:px-8 mx-auto px-4 text-red-800">
         <svg
@@ -232,7 +232,7 @@
         <Logo class="logo block h-40" alt="NextGraph Logo" />
       </div>
       <h2 class="pb-5 text-xl">Select a wallet to login with</h2>
-      <div class="flex flex-wrap justify-center gap-5 mb-20">
+      <div class="flex flex-wrap justify-center gap-5 mb-10">
         {#each Object.entries($wallets) as wallet_entry}
           <div
             class="wallet-box"
diff --git a/ng-app/src/store.ts b/ng-app/src/store.ts
index 7478766..dffb46e 100644
--- a/ng-app/src/store.ts
+++ b/ng-app/src/store.ts
@@ -14,6 +14,34 @@ import { official_apps, official_services } from "./zeras";
 
 let all_branches = {};
 
+export const available_languages = {
+    "en": "English",
+    "de": "Deutsch",
+    "fr": "Français",
+    "ru": "Русский",
+    "es": "Español",
+    "it": "Italiano",
+    "zh": "中文",
+    "pt": "Português",
+};
+
+export const current_lang = writable("en");
+
+export const select_default_lang = async() => {
+    let locales = await ng.locales();
+    for (let lo of locales) {
+        if (available_languages[lo]) {
+            // exact match (if locales is a 2 chars lang code, or if we support regionalized translations)
+            current_lang.set(lo);
+            return;
+        }
+        lo = lo.substr(0,2);
+        if (available_languages[lo]) {
+            current_lang.set(lo);
+            return;
+        }
+    }
+};
 
 let loaded_external_apps = {};
 
diff --git a/ng-oxigraph/src/oxigraph/sparql/update.rs b/ng-oxigraph/src/oxigraph/sparql/update.rs
index 996238a..6943dea 100644
--- a/ng-oxigraph/src/oxigraph/sparql/update.rs
+++ b/ng-oxigraph/src/oxigraph/sparql/update.rs
@@ -214,9 +214,7 @@ impl<'a, 'b: 'a> SimpleUpdateEvaluator<'a, 'b> {
             GraphName::NamedNode(graph_name) => graph_name.into(),
             GraphName::DefaultGraph => {
                 if let Some(default_graph) = &self.options.query_options.default_graph {
-                    crate::oxrdf::GraphNameRef::NamedNode(NamedNodeRef::new_unchecked(
-                        &default_graph,
-                    ))
+                    GraphNameRef::NamedNode(NamedNodeRef::new_unchecked(&default_graph))
                 } else {
                     return Err(EvaluationError::NoDefaultGraph);
                 }
diff --git a/ngaccount/web/src/routes/Create.svelte b/ngaccount/web/src/routes/Create.svelte
index cf7ffe6..7aba033 100644
--- a/ngaccount/web/src/routes/Create.svelte
+++ b/ngaccount/web/src/routes/Create.svelte
@@ -375,7 +375,7 @@
         </div>
       </div>
       {#if ca}
-        <div class="row mb-20">
+        <div class="row mb-10">
           <button
             on:click|once={accept}
             class="mr-5 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
diff --git a/ngaccount/web/src/routes/Delete.svelte b/ngaccount/web/src/routes/Delete.svelte
index 874bfa7..c1585eb 100644
--- a/ngaccount/web/src/routes/Delete.svelte
+++ b/ngaccount/web/src/routes/Delete.svelte
@@ -154,7 +154,7 @@
         </ul>
       </div>
     </div>
-    <div class="row mb-20">
+    <div class="row mb-10">
       <button
         on:click|once={accept}
         class="mr-5 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"