windows-development-sandbox 1.25.1 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.example.json +12 -3
- package/dist/app/features/accounts/services.def.d.ts +1 -1
- package/dist/app/features/accounts/services.def.js +1 -1
- package/dist/app/features/defs.d.ts +198 -3
- package/dist/app/features/defs.js +8 -0
- package/dist/app/features/settings/categories.def.js +1 -0
- package/dist/app/features/unity/index.d.ts +2 -0
- package/dist/app/features/unity/index.js +3 -0
- package/dist/app/features/unity/unity.def.d.ts +294 -0
- package/dist/app/features/unity/unity.def.js +471 -0
- package/dist/app/features/unity/unity.run.d.ts +142 -0
- package/dist/app/features/unity/unity.run.js +363 -0
- package/dist/app/features/unreal/unreal.run.js +13 -3
- package/dist/app/registry.js +6 -0
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-G3TG4ZT7.js → chunk-4TLSWPG7.js} +1 -1
- package/dist/bin/{chunk-3GAXLATK.js → chunk-QUHNXHVG.js} +72 -5
- package/dist/bin/{chunk-F4PVBN23.js → chunk-RSIX7C6D.js} +3633 -1972
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/launch/launch.js +14 -1
- package/dist/cli/commands/registry.js +3 -0
- package/dist/cli/manifest.d.ts +33 -1
- package/dist/cli/manifest.js +32 -1
- package/dist/cli/menu/coverage-exempt.js +1 -0
- package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
- package/dist/cli/menu/pages/sandbox-page.js +40 -3
- package/dist/cli/menu/views.js +2 -0
- package/dist/core/config/defaults.js +16 -3
- package/dist/core/schema/accounts.d.ts +3 -0
- package/dist/core/schema/accounts.js +1 -0
- package/dist/core/schema/config.d.ts +29 -13
- package/dist/core/schema/github.d.ts +1 -0
- package/dist/core/schema/github.js +3 -0
- package/dist/core/schema/pc-installs.d.ts +2 -1
- package/dist/core/schema/pc-installs.js +6 -1
- package/dist/core/schema/toolchains.d.ts +8 -0
- package/dist/core/schema/toolchains.js +19 -4
- package/dist/guest/accounts/adapters.js +2 -0
- package/dist/guest/accounts/apply.d.ts +4 -2
- package/dist/guest/accounts/kinds/perplexityapp.d.ts +7 -0
- package/dist/guest/accounts/kinds/perplexityapp.js +53 -0
- package/dist/guest/accounts/kinds/unity.d.ts +27 -0
- package/dist/guest/accounts/kinds/unity.js +164 -7
- package/dist/guest/apps/app-installer.js +18 -0
- package/dist/guest/apps/store-app.d.ts +4 -0
- package/dist/guest/apps/store-app.js +19 -0
- package/dist/guest/apps/store-check.d.ts +8 -0
- package/dist/guest/apps/store-check.js +33 -0
- package/dist/guest/boot/boot.js +1 -1
- package/dist/guest/boot/guide.js +18 -0
- package/dist/guest/browser/comet.d.ts +3 -1
- package/dist/guest/browser/comet.js +1 -1
- package/dist/guest/browser/perplexity-app.d.ts +12 -0
- package/dist/guest/browser/perplexity-app.js +60 -0
- package/dist/guest/daemon/daemon.js +2 -0
- package/dist/guest/devtools/devtool.d.ts +1 -1
- package/dist/guest/devtools/registry.js +1 -2
- package/dist/guest/entries/tool.js +1 -1
- package/dist/guest/setup/addon-mcp.d.ts +7 -2
- package/dist/guest/setup/addon-mcp.js +19 -9
- package/dist/guest/setup/github-token.js +4 -4
- package/dist/guest/setup/unity-agent.d.ts +11 -0
- package/dist/guest/setup/unity-agent.js +39 -0
- package/dist/guest/toolchains/engines/epic-launcher.d.ts +1 -1
- package/dist/guest/toolchains/engines/epic-launcher.js +11 -7
- package/dist/guest/toolchains/engines/unity-cli.d.ts +24 -0
- package/dist/guest/toolchains/engines/unity-cli.js +74 -0
- package/dist/guest/toolchains/engines/unity-hub.d.ts +2 -0
- package/dist/guest/toolchains/engines/unity-hub.js +27 -0
- package/dist/guest/toolchains/engines/unity-release.d.ts +4 -15
- package/dist/guest/toolchains/engines/unity-release.js +17 -5
- package/dist/guest/toolchains/engines/unity-status.d.ts +11 -0
- package/dist/guest/toolchains/engines/unity-status.js +39 -0
- package/dist/guest/toolchains/engines/unity.d.ts +20 -1
- package/dist/guest/toolchains/engines/unity.js +250 -3
- package/dist/guest/toolchains/engines/unreal-status.js +1 -1
- package/dist/guest/toolchains/native/mesa.js +35 -11
- package/dist/guest/toolchains/native/unreal.js +1 -0
- package/dist/guest/toolchains/plan.js +5 -1
- package/dist/guest/toolchains/tools/cli.js +2 -2
- package/dist/host/accounts/deliver.d.ts +3 -0
- package/dist/host/accounts/deliver.js +23 -0
- package/dist/host/accounts/kinds/perplexityapp.d.ts +2 -0
- package/dist/host/accounts/kinds/perplexityapp.js +8 -0
- package/dist/host/accounts/kinds/unity.d.ts +1 -1
- package/dist/host/accounts/kinds/unity.js +60 -8
- package/dist/host/accounts/leases.d.ts +2 -1
- package/dist/host/accounts/source.d.ts +2 -0
- package/dist/host/accounts/source.js +2 -0
- package/dist/host/accounts/sources.js +2 -0
- package/dist/host/apps/index.d.ts +1 -0
- package/dist/host/apps/index.js +2 -0
- package/dist/host/apps/store-package.d.ts +51 -0
- package/dist/host/apps/store-package.js +209 -0
- package/dist/host/github/deliver.d.ts +8 -3
- package/dist/host/github/deliver.js +42 -29
- package/dist/host/github/index.d.ts +1 -0
- package/dist/host/github/index.js +1 -0
- package/dist/host/github/pc-login.d.ts +27 -0
- package/dist/host/github/pc-login.js +129 -0
- package/dist/host/pc-installs/discover.d.ts +4 -0
- package/dist/host/pc-installs/discover.js +19 -6
- package/dist/host/pc-installs/epic.js +3 -0
- package/dist/host/pc-installs/source.d.ts +1 -1
- package/dist/host/pc-installs/unity-assets.d.ts +5 -0
- package/dist/host/pc-installs/unity-assets.js +18 -0
- package/dist/host/pc-installs/unity.d.ts +22 -0
- package/dist/host/pc-installs/unity.js +144 -2
- package/dist/host/pc-installs/unreal.d.ts +2 -0
- package/dist/host/pc-installs/unreal.js +24 -8
- package/dist/runtime/agent.js +116 -11
- package/dist/runtime/daemon.js +2205 -987
- package/dist/runtime/db.js +116 -11
- package/dist/runtime/main.js +2578 -1375
- package/dist/runtime/netproxy.js +116 -11
- package/dist/runtime/tool.js +133 -31
- package/dist/runtime/view.js +116 -11
- package/dist/selftest/agents-web.test.js +2 -1
- package/dist/selftest/engines.test.js +32 -3
- package/dist/selftest/github.test.js +64 -1
- package/dist/selftest/index.js +10 -0
- package/dist/selftest/menu-screens.js +3 -1
- package/dist/selftest/mixamo.test.js +1 -1
- package/dist/selftest/persisted-installs.test.js +1 -1
- package/dist/selftest/service-accounts.test.js +13 -2
- package/dist/selftest/store-app.test.d.ts +2 -0
- package/dist/selftest/store-app.test.js +162 -0
- package/dist/selftest/support/engine-golden.js +7 -0
- package/dist/selftest/support/fixtures.d.ts +10 -1
- package/dist/selftest/support/unity-sample.d.ts +2 -0
- package/dist/selftest/support/unity-sample.js +80 -0
- package/dist/selftest/unity-accounts.test.d.ts +2 -0
- package/dist/selftest/unity-accounts.test.js +106 -0
- package/dist/selftest/unity-agent.test.d.ts +2 -0
- package/dist/selftest/unity-agent.test.js +47 -0
- package/dist/selftest/unity-page.test.d.ts +2 -0
- package/dist/selftest/unity-page.test.js +177 -0
- package/dist/selftest/unity-setup.test.d.ts +2 -0
- package/dist/selftest/unity-setup.test.js +49 -0
- package/dist/selftest/unity.test.js +238 -3
- package/dist/shared/accounts/index.d.ts +1 -0
- package/dist/shared/accounts/index.js +1 -0
- package/dist/shared/accounts/kinds/unity.d.ts +28 -0
- package/dist/shared/accounts/kinds/unity.js +88 -0
- package/dist/shared/accounts/kinds.d.ts +2 -2
- package/dist/shared/accounts/kinds.js +23 -1
- package/dist/shared/accounts/payloads.d.ts +52 -0
- package/dist/shared/accounts/payloads.js +14 -2
- package/dist/shared/apps/catalogue-agents-web.d.ts +7 -0
- package/dist/shared/apps/catalogue-agents-web.js +23 -0
- package/dist/shared/apps/catalogue-gamedev.d.ts +3 -0
- package/dist/shared/apps/catalogue-gamedev.js +31 -0
- package/dist/shared/apps/catalogue.d.ts +8 -0
- package/dist/shared/apps/index.d.ts +3 -2
- package/dist/shared/apps/index.js +3 -2
- package/dist/shared/apps/selection.d.ts +6 -0
- package/dist/shared/apps/selection.js +9 -0
- package/dist/shared/apps/store-package.d.ts +31 -0
- package/dist/shared/apps/store-package.js +34 -0
- package/dist/shared/channel/schema.d.ts +24 -0
- package/dist/shared/channel/secrets.d.ts +17 -0
- package/dist/shared/paths/pc-installs.d.ts +1 -1
- package/dist/shared/paths/pc-installs.js +1 -0
- package/dist/shared/readiness.d.ts +2 -2
- package/dist/shared/readiness.js +2 -2
- package/dist/shared/unity/asset-cache.d.ts +20 -0
- package/dist/shared/unity/asset-cache.js +44 -0
- package/dist/shared/unity/cli.d.ts +40 -0
- package/dist/shared/unity/cli.js +77 -0
- package/dist/shared/unity/editors.d.ts +46 -0
- package/dist/shared/unity/editors.js +89 -0
- package/dist/shared/unity/guide.d.ts +9 -0
- package/dist/shared/unity/guide.js +84 -0
- package/dist/shared/unity/index.d.ts +9 -0
- package/dist/shared/unity/index.js +11 -0
- package/dist/shared/unity/manifest.d.ts +10 -0
- package/dist/shared/unity/manifest.js +53 -0
- package/dist/shared/unity/mcp.d.ts +8 -0
- package/dist/shared/unity/mcp.js +12 -0
- package/dist/shared/unity/release.d.ts +28 -0
- package/dist/shared/unity/release.js +83 -0
- package/dist/shared/unity/status.d.ts +59 -0
- package/dist/shared/unity/status.js +45 -0
- package/dist/shared/unity/version.d.ts +27 -0
- package/dist/shared/unity/version.js +75 -0
- package/dist/shared/unreal/status.d.ts +1 -0
- package/dist/shared/unreal/status.js +2 -0
- package/dist/web/index.html +1 -1
- package/dist/web/{main-FNE6XEHA.js → main-VPMYTSUL.js} +67 -67
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/native/scripts/get-store-package.ps1 +58 -0
- package/package.json +1 -1
- package/sandbox/addons/openupm-cli/package-lock.json +2921 -0
- package/sandbox/addons/openupm-cli/package.json +7 -0
- package/sandbox/addons/unity-mcp/requirements.in +1 -0
- package/sandbox/addons/unity-mcp/requirements.txt +1165 -0
- package/sandbox/csharp/AppActivation.cs +38 -0
- package/sandbox/scripts/install-store-package.ps1 +28 -0
- package/sandbox/scripts/start-store-app.ps1 +29 -0
- package/schemas/config.schema.json +61 -6
- package/schemas/sandbox-config.schema.json +38 -5
- package/dist/guest/devtools/unity.d.ts +0 -2
- package/dist/guest/devtools/unity.js +0 -7
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// What the sandbox last found for Unity (tools\unity\status.json): the CLI, the editors, which editor each project
|
|
2
|
+
// opens with, the licence, the Asset Store cache. The sandbox writes it; the Unity page on this PC reads it with this
|
|
3
|
+
// schema (bounded strings and lists) and prints its text through safeText.
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/** The file in tools\unity. */
|
|
6
|
+
export const UNITY_STATUS_FILE = 'status.json';
|
|
7
|
+
const Text = (max = 400) => z.string().max(max);
|
|
8
|
+
export const UnityStatusSchema = z.object({
|
|
9
|
+
updatedAt: Text(40),
|
|
10
|
+
cli: z.object({ version: Text(40), path: Text() }).nullable(),
|
|
11
|
+
editors: z
|
|
12
|
+
.array(z.object({
|
|
13
|
+
version: Text(40),
|
|
14
|
+
root: Text(),
|
|
15
|
+
origin: z.enum(['pc', 'data']),
|
|
16
|
+
writable: z.boolean(),
|
|
17
|
+
modules: z.array(Text(60)).max(20),
|
|
18
|
+
sizeBytes: z.number().int().min(0).nullable(),
|
|
19
|
+
}))
|
|
20
|
+
.max(32),
|
|
21
|
+
projects: z
|
|
22
|
+
.array(z.object({
|
|
23
|
+
workspace: Text(),
|
|
24
|
+
/** The version its ProjectVersion.txt asks for. */
|
|
25
|
+
version: Text(40).nullable(),
|
|
26
|
+
/** The root of the editor it opens with, null when there is none for it. */
|
|
27
|
+
editor: Text().nullable(),
|
|
28
|
+
reason: Text(),
|
|
29
|
+
bridge: z.enum(['pipeline', 'coplay']).nullable(),
|
|
30
|
+
}))
|
|
31
|
+
.max(64),
|
|
32
|
+
licence: z.object({
|
|
33
|
+
state: z.enum(['active', 'none', 'invalid', 'unknown']),
|
|
34
|
+
kind: Text(60),
|
|
35
|
+
detail: Text(),
|
|
36
|
+
user: Text(256).nullable(),
|
|
37
|
+
}),
|
|
38
|
+
assetCache: z.object({ mode: z.enum(['persisted', 'pc', 'local']), dir: Text().nullable() }),
|
|
39
|
+
pcAssets: z.array(Text()).max(4),
|
|
40
|
+
hub: z.object({ installed: z.boolean(), path: Text().nullable() }),
|
|
41
|
+
/** The MCP server's name when it was registered. */
|
|
42
|
+
mcp: Text(100).nullable(),
|
|
43
|
+
skills: z.boolean(),
|
|
44
|
+
problem: Text(600).nullable(),
|
|
45
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const UNITY_VERSION: RegExp;
|
|
2
|
+
/** A changeset (short revision) as Unity prints it. */
|
|
3
|
+
export declare const UNITY_CHANGESET: RegExp;
|
|
4
|
+
export interface UnityVersion {
|
|
5
|
+
readonly major: number;
|
|
6
|
+
readonly minor: number;
|
|
7
|
+
readonly patch: number;
|
|
8
|
+
/** a (alpha), b (beta), f (final), p (patch). */
|
|
9
|
+
readonly stage: 'a' | 'b' | 'f' | 'p';
|
|
10
|
+
readonly build: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function parseUnityVersion(text: string): UnityVersion | null;
|
|
13
|
+
/** Negative when a is older than b, 0 when equal; an unreadable version sorts first. */
|
|
14
|
+
export declare function compareUnityVersions(a: string, b: string): number;
|
|
15
|
+
export interface ProjectVersion {
|
|
16
|
+
readonly version: string;
|
|
17
|
+
readonly changeset: string | null;
|
|
18
|
+
}
|
|
19
|
+
/** The editor a ProjectVersion.txt asks for: m_EditorVersion, and the changeset of m_EditorVersionWithRevision. */
|
|
20
|
+
export declare function parseProjectVersion(text: string): ProjectVersion | null;
|
|
21
|
+
/**
|
|
22
|
+
* The editor to open a project with: its own ProjectVersion.txt always wins (another version upgrades its files); the
|
|
23
|
+
* setting's version ("project" or e.g. "6000.0.32f1") is only for folders without one.
|
|
24
|
+
*/
|
|
25
|
+
export declare function wantedVersion(projectFile: string | null, setting: string): ProjectVersion | null;
|
|
26
|
+
/** The Unity Pipeline package (and so `unity command` / `unity eval`) needs Unity 6 or later. */
|
|
27
|
+
export declare function supportsPipeline(version: string): boolean;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Unity editor versions ("6000.0.58f2") and the ProjectSettings/ProjectVersion.txt that names one. Pure; the text read
|
|
2
|
+
// from a project is bounded (the first 50 lines of at most 64 KB).
|
|
3
|
+
export const UNITY_VERSION = /^(\d{1,4})\.(\d{1,3})\.(\d{1,3})([abfp])(\d{1,3})$/;
|
|
4
|
+
/** A changeset (short revision) as Unity prints it. */
|
|
5
|
+
export const UNITY_CHANGESET = /^[0-9a-f]{12}$/;
|
|
6
|
+
const MAX_PROJECT_VERSION_BYTES = 64 * 1024;
|
|
7
|
+
const MAX_PROJECT_VERSION_LINES = 50;
|
|
8
|
+
const STAGES = 'abfp';
|
|
9
|
+
export function parseUnityVersion(text) {
|
|
10
|
+
const m = UNITY_VERSION.exec(text);
|
|
11
|
+
if (!m)
|
|
12
|
+
return null;
|
|
13
|
+
return {
|
|
14
|
+
major: Number(m[1]),
|
|
15
|
+
minor: Number(m[2]),
|
|
16
|
+
patch: Number(m[3]),
|
|
17
|
+
stage: m[4],
|
|
18
|
+
build: Number(m[5]),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Negative when a is older than b, 0 when equal; an unreadable version sorts first. */
|
|
22
|
+
export function compareUnityVersions(a, b) {
|
|
23
|
+
const x = parseUnityVersion(a);
|
|
24
|
+
const y = parseUnityVersion(b);
|
|
25
|
+
if (!x || !y)
|
|
26
|
+
return x ? 1 : y ? -1 : a.localeCompare(b);
|
|
27
|
+
return (x.major - y.major ||
|
|
28
|
+
x.minor - y.minor ||
|
|
29
|
+
x.patch - y.patch ||
|
|
30
|
+
STAGES.indexOf(x.stage) - STAGES.indexOf(y.stage) ||
|
|
31
|
+
x.build - y.build);
|
|
32
|
+
}
|
|
33
|
+
/** The editor a ProjectVersion.txt asks for: m_EditorVersion, and the changeset of m_EditorVersionWithRevision. */
|
|
34
|
+
export function parseProjectVersion(text) {
|
|
35
|
+
let version = null;
|
|
36
|
+
let changeset = null;
|
|
37
|
+
const lines = text.slice(0, MAX_PROJECT_VERSION_BYTES).split('\n', MAX_PROJECT_VERSION_LINES);
|
|
38
|
+
for (const raw of lines) {
|
|
39
|
+
const line = raw.replace(/^\uFEFF/, '').trim();
|
|
40
|
+
if (line.startsWith('m_EditorVersionWithRevision:')) {
|
|
41
|
+
const rest = line.slice('m_EditorVersionWithRevision:'.length).trim();
|
|
42
|
+
const open = rest.indexOf('(');
|
|
43
|
+
const close = rest.indexOf(')', open);
|
|
44
|
+
const v = (open < 0 ? rest : rest.slice(0, open)).trim();
|
|
45
|
+
if (UNITY_VERSION.test(v))
|
|
46
|
+
version ??= v;
|
|
47
|
+
if (open >= 0 && close > open) {
|
|
48
|
+
const cs = rest.slice(open + 1, close).trim();
|
|
49
|
+
if (UNITY_CHANGESET.test(cs))
|
|
50
|
+
changeset = cs;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (line.startsWith('m_EditorVersion:')) {
|
|
54
|
+
const v = line.slice('m_EditorVersion:'.length).trim();
|
|
55
|
+
if (UNITY_VERSION.test(v))
|
|
56
|
+
version = v;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return version ? { version, changeset } : null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The editor to open a project with: its own ProjectVersion.txt always wins (another version upgrades its files); the
|
|
63
|
+
* setting's version ("project" or e.g. "6000.0.32f1") is only for folders without one.
|
|
64
|
+
*/
|
|
65
|
+
export function wantedVersion(projectFile, setting) {
|
|
66
|
+
const own = projectFile === null ? null : parseProjectVersion(projectFile);
|
|
67
|
+
if (own)
|
|
68
|
+
return own;
|
|
69
|
+
return setting !== 'project' && UNITY_VERSION.test(setting) ? { version: setting, changeset: null } : null;
|
|
70
|
+
}
|
|
71
|
+
/** The Unity Pipeline package (and so `unity command` / `unity eval`) needs Unity 6 or later. */
|
|
72
|
+
export function supportsPipeline(version) {
|
|
73
|
+
const v = parseUnityVersion(version);
|
|
74
|
+
return v !== null && v.major >= 6000;
|
|
75
|
+
}
|
|
@@ -28,6 +28,7 @@ export declare const UnrealStatusSchema: z.ZodObject<{
|
|
|
28
28
|
}, z.core.$strip>>;
|
|
29
29
|
launcher: z.ZodObject<{
|
|
30
30
|
installed: z.ZodBoolean;
|
|
31
|
+
exe: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
31
32
|
installLocation: z.ZodNullable<z.ZodString>;
|
|
32
33
|
problem: z.ZodNullable<z.ZodString>;
|
|
33
34
|
freeBytes: z.ZodNullable<z.ZodNumber>;
|
|
@@ -30,6 +30,8 @@ export const UnrealStatusSchema = z.object({
|
|
|
30
30
|
.max(64),
|
|
31
31
|
launcher: z.object({
|
|
32
32
|
installed: z.boolean(),
|
|
33
|
+
/** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
|
|
34
|
+
exe: Text().nullable().default(null),
|
|
33
35
|
/** Where the launcher installs engines; null when it could not be set. */
|
|
34
36
|
installLocation: Text().nullable(),
|
|
35
37
|
/** Why engines would not go to the data disk (shown loudly), null when they do. */
|
package/dist/web/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>Sandbox</title>
|
|
7
7
|
<link rel="icon" href="data:," />
|
|
8
8
|
<link rel="stylesheet" href="/main-XT7T6ODM.css" />
|
|
9
|
-
<script type="module" src="/main-
|
|
9
|
+
<script type="module" src="/main-VPMYTSUL.js"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|