@shieldedtech/moth-cli 0.2.0

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.
Files changed (173) hide show
  1. package/README.md +67 -0
  2. package/dist/adapters/passphrase.d.ts +2 -0
  3. package/dist/adapters/passphrase.d.ts.map +1 -0
  4. package/dist/adapters/passphrase.js +62 -0
  5. package/dist/adapters/passphrase.js.map +1 -0
  6. package/dist/base-command.d.ts +155 -0
  7. package/dist/base-command.d.ts.map +1 -0
  8. package/dist/base-command.js +497 -0
  9. package/dist/base-command.js.map +1 -0
  10. package/dist/commands/airdrop.d.ts +18 -0
  11. package/dist/commands/airdrop.d.ts.map +1 -0
  12. package/dist/commands/airdrop.js +36 -0
  13. package/dist/commands/airdrop.js.map +1 -0
  14. package/dist/commands/balance.d.ts +18 -0
  15. package/dist/commands/balance.d.ts.map +1 -0
  16. package/dist/commands/balance.js +124 -0
  17. package/dist/commands/balance.js.map +1 -0
  18. package/dist/commands/call.d.ts +26 -0
  19. package/dist/commands/call.d.ts.map +1 -0
  20. package/dist/commands/call.js +102 -0
  21. package/dist/commands/call.js.map +1 -0
  22. package/dist/commands/config.d.ts +22 -0
  23. package/dist/commands/config.d.ts.map +1 -0
  24. package/dist/commands/config.js +50 -0
  25. package/dist/commands/config.js.map +1 -0
  26. package/dist/commands/daemon/call.d.ts +27 -0
  27. package/dist/commands/daemon/call.d.ts.map +1 -0
  28. package/dist/commands/daemon/call.js +108 -0
  29. package/dist/commands/daemon/call.js.map +1 -0
  30. package/dist/commands/daemon/deploy.d.ts +27 -0
  31. package/dist/commands/daemon/deploy.d.ts.map +1 -0
  32. package/dist/commands/daemon/deploy.js +105 -0
  33. package/dist/commands/daemon/deploy.js.map +1 -0
  34. package/dist/commands/daemon/dust/deregister.d.ts +19 -0
  35. package/dist/commands/daemon/dust/deregister.d.ts.map +1 -0
  36. package/dist/commands/daemon/dust/deregister.js +52 -0
  37. package/dist/commands/daemon/dust/deregister.js.map +1 -0
  38. package/dist/commands/daemon/dust/register.d.ts +20 -0
  39. package/dist/commands/daemon/dust/register.d.ts.map +1 -0
  40. package/dist/commands/daemon/dust/register.js +60 -0
  41. package/dist/commands/daemon/dust/register.js.map +1 -0
  42. package/dist/commands/daemon/key/gen.d.ts +19 -0
  43. package/dist/commands/daemon/key/gen.d.ts.map +1 -0
  44. package/dist/commands/daemon/key/gen.js +66 -0
  45. package/dist/commands/daemon/key/gen.js.map +1 -0
  46. package/dist/commands/daemon/key/list.d.ts +17 -0
  47. package/dist/commands/daemon/key/list.d.ts.map +1 -0
  48. package/dist/commands/daemon/key/list.js +43 -0
  49. package/dist/commands/daemon/key/list.js.map +1 -0
  50. package/dist/commands/daemon/key/revoke.d.ts +20 -0
  51. package/dist/commands/daemon/key/revoke.d.ts.map +1 -0
  52. package/dist/commands/daemon/key/revoke.js +37 -0
  53. package/dist/commands/daemon/key/revoke.js.map +1 -0
  54. package/dist/commands/daemon/maintenance/insert-vk.d.ts +24 -0
  55. package/dist/commands/daemon/maintenance/insert-vk.d.ts.map +1 -0
  56. package/dist/commands/daemon/maintenance/insert-vk.js +87 -0
  57. package/dist/commands/daemon/maintenance/insert-vk.js.map +1 -0
  58. package/dist/commands/daemon/maintenance/insert-vks-batch.d.ts +24 -0
  59. package/dist/commands/daemon/maintenance/insert-vks-batch.d.ts.map +1 -0
  60. package/dist/commands/daemon/maintenance/insert-vks-batch.js +117 -0
  61. package/dist/commands/daemon/maintenance/insert-vks-batch.js.map +1 -0
  62. package/dist/commands/daemon/serve.d.ts +23 -0
  63. package/dist/commands/daemon/serve.d.ts.map +1 -0
  64. package/dist/commands/daemon/serve.js +289 -0
  65. package/dist/commands/daemon/serve.js.map +1 -0
  66. package/dist/commands/daemon/submit-tx.d.ts +22 -0
  67. package/dist/commands/daemon/submit-tx.d.ts.map +1 -0
  68. package/dist/commands/daemon/submit-tx.js +89 -0
  69. package/dist/commands/daemon/submit-tx.js.map +1 -0
  70. package/dist/commands/daemon/transfer.d.ts +24 -0
  71. package/dist/commands/daemon/transfer.d.ts.map +1 -0
  72. package/dist/commands/daemon/transfer.js +135 -0
  73. package/dist/commands/daemon/transfer.js.map +1 -0
  74. package/dist/commands/deploy.d.ts +26 -0
  75. package/dist/commands/deploy.d.ts.map +1 -0
  76. package/dist/commands/deploy.js +135 -0
  77. package/dist/commands/deploy.js.map +1 -0
  78. package/dist/commands/dust/deregister.d.ts +18 -0
  79. package/dist/commands/dust/deregister.d.ts.map +1 -0
  80. package/dist/commands/dust/deregister.js +48 -0
  81. package/dist/commands/dust/deregister.js.map +1 -0
  82. package/dist/commands/dust/register.d.ts +21 -0
  83. package/dist/commands/dust/register.d.ts.map +1 -0
  84. package/dist/commands/dust/register.js +120 -0
  85. package/dist/commands/dust/register.js.map +1 -0
  86. package/dist/commands/dust/status.d.ts +17 -0
  87. package/dist/commands/dust/status.d.ts.map +1 -0
  88. package/dist/commands/dust/status.js +47 -0
  89. package/dist/commands/dust/status.js.map +1 -0
  90. package/dist/commands/info.d.ts +17 -0
  91. package/dist/commands/info.d.ts.map +1 -0
  92. package/dist/commands/info.js +37 -0
  93. package/dist/commands/info.js.map +1 -0
  94. package/dist/commands/maintenance/insert-vk.d.ts +23 -0
  95. package/dist/commands/maintenance/insert-vk.d.ts.map +1 -0
  96. package/dist/commands/maintenance/insert-vk.js +92 -0
  97. package/dist/commands/maintenance/insert-vk.js.map +1 -0
  98. package/dist/commands/maintenance/insert-vks-batch.d.ts +23 -0
  99. package/dist/commands/maintenance/insert-vks-batch.d.ts.map +1 -0
  100. package/dist/commands/maintenance/insert-vks-batch.js +130 -0
  101. package/dist/commands/maintenance/insert-vks-batch.js.map +1 -0
  102. package/dist/commands/mint.d.ts +24 -0
  103. package/dist/commands/mint.d.ts.map +1 -0
  104. package/dist/commands/mint.js +116 -0
  105. package/dist/commands/mint.js.map +1 -0
  106. package/dist/commands/state.d.ts +20 -0
  107. package/dist/commands/state.d.ts.map +1 -0
  108. package/dist/commands/state.js +36 -0
  109. package/dist/commands/state.js.map +1 -0
  110. package/dist/commands/transfer/batch.d.ts +21 -0
  111. package/dist/commands/transfer/batch.d.ts.map +1 -0
  112. package/dist/commands/transfer/batch.js +71 -0
  113. package/dist/commands/transfer/batch.js.map +1 -0
  114. package/dist/commands/transfer.d.ts +24 -0
  115. package/dist/commands/transfer.d.ts.map +1 -0
  116. package/dist/commands/transfer.js +123 -0
  117. package/dist/commands/transfer.js.map +1 -0
  118. package/dist/commands/tui.d.ts +17 -0
  119. package/dist/commands/tui.d.ts.map +1 -0
  120. package/dist/commands/tui.js +18 -0
  121. package/dist/commands/tui.js.map +1 -0
  122. package/dist/commands/wallet/address.d.ts +25 -0
  123. package/dist/commands/wallet/address.d.ts.map +1 -0
  124. package/dist/commands/wallet/address.js +47 -0
  125. package/dist/commands/wallet/address.js.map +1 -0
  126. package/dist/commands/wallet/generate.d.ts +20 -0
  127. package/dist/commands/wallet/generate.d.ts.map +1 -0
  128. package/dist/commands/wallet/generate.js +75 -0
  129. package/dist/commands/wallet/generate.js.map +1 -0
  130. package/dist/commands/wallet/import.d.ts +20 -0
  131. package/dist/commands/wallet/import.d.ts.map +1 -0
  132. package/dist/commands/wallet/import.js +85 -0
  133. package/dist/commands/wallet/import.js.map +1 -0
  134. package/dist/commands/wallet/list.d.ts +17 -0
  135. package/dist/commands/wallet/list.d.ts.map +1 -0
  136. package/dist/commands/wallet/list.js +23 -0
  137. package/dist/commands/wallet/list.js.map +1 -0
  138. package/dist/commands/wallet/remove.d.ts +21 -0
  139. package/dist/commands/wallet/remove.d.ts.map +1 -0
  140. package/dist/commands/wallet/remove.js +31 -0
  141. package/dist/commands/wallet/remove.js.map +1 -0
  142. package/dist/commands/wallet/status.d.ts +18 -0
  143. package/dist/commands/wallet/status.d.ts.map +1 -0
  144. package/dist/commands/wallet/status.js +62 -0
  145. package/dist/commands/wallet/status.js.map +1 -0
  146. package/dist/commands/wallet/use.d.ts +20 -0
  147. package/dist/commands/wallet/use.d.ts.map +1 -0
  148. package/dist/commands/wallet/use.js +19 -0
  149. package/dist/commands/wallet/use.js.map +1 -0
  150. package/dist/formatters/index.d.ts +5 -0
  151. package/dist/formatters/index.d.ts.map +1 -0
  152. package/dist/formatters/index.js +68 -0
  153. package/dist/formatters/index.js.map +1 -0
  154. package/dist/index.d.ts +3 -0
  155. package/dist/index.d.ts.map +1 -0
  156. package/dist/index.js +4 -0
  157. package/dist/index.js.map +1 -0
  158. package/package.json +53 -0
  159. package/templates/dapp/api/package.json +21 -0
  160. package/templates/dapp/api/src/index.ts +2 -0
  161. package/templates/dapp/api/src/providers.ts +23 -0
  162. package/templates/dapp/api/src/types.ts +23 -0
  163. package/templates/dapp/api/tsconfig.json +11 -0
  164. package/templates/dapp/root/README.md +20 -0
  165. package/templates/dapp/root/tsconfig.json +15 -0
  166. package/templates/dapp/ui/index.html +13 -0
  167. package/templates/dapp/ui/package.json +24 -0
  168. package/templates/dapp/ui/public/vite.svg +1 -0
  169. package/templates/dapp/ui/src/App.tsx +36 -0
  170. package/templates/dapp/ui/src/index.css +29 -0
  171. package/templates/dapp/ui/src/main.tsx +10 -0
  172. package/templates/dapp/ui/tsconfig.json +8 -0
  173. package/templates/dapp/ui/vite.config.ts +14 -0
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@shieldedtech/moth-cli",
3
+ "version": "0.2.0",
4
+ "description": "CLI tool for Midnight Network wallet operations and contract deployments. USE AT YOUR OWN RISK. Experimental software provided AS-IS with no warranty. Not audited. For development and testing purposes only.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "publishConfig": {
8
+ "access": "restricted"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "templates"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/shieldedtech/moth-wallet.git",
17
+ "directory": "packages/cli"
18
+ },
19
+ "bin": {
20
+ "moth": "./dist/index.js"
21
+ },
22
+ "exports": {
23
+ ".": "./dist/index.js",
24
+ "./adapters/*": "./dist/adapters/*.js"
25
+ },
26
+ "types": "./dist/index.d.ts",
27
+ "scripts": {
28
+ "build": "tsc && chmod +x dist/index.js",
29
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest"
32
+ },
33
+ "dependencies": {
34
+ "@oclif/core": "^4.2.0",
35
+ "@shieldedtech/moth-tui": "^0.2.0",
36
+ "@shieldedtech/moth-wallet": "^0.2.0",
37
+ "dotenv": "17.4.2",
38
+ "ink": "^7.0.1"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^25.6.0",
42
+ "typescript": "^5.5.0",
43
+ "vitest": "^3.1.0"
44
+ },
45
+ "oclif": {
46
+ "bin": "moth",
47
+ "commands": {
48
+ "strategy": "pattern",
49
+ "target": "./dist/commands"
50
+ },
51
+ "topicSeparator": " "
52
+ }
53
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "{{API_PACKAGE_NAME}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "dev": "tsc --watch"
11
+ },
12
+ "dependencies": {
13
+ "@midnight-ntwrk/midnight-js-contracts": "{{SDK_CONTRACTS_VERSION}}",
14
+ "@midnight-ntwrk/midnight-js-types": "{{SDK_TYPES_VERSION}}",
15
+ "@midnight-ntwrk/midnight-js-network-id": "{{SDK_NETWORK_ID_VERSION}}",
16
+ "@midnight-ntwrk/compact-runtime": "{{SDK_COMPACT_RUNTIME_VERSION}}"
17
+ },
18
+ "devDependencies": {
19
+ "typescript": "^6.0.0"
20
+ }
21
+ }
@@ -0,0 +1,2 @@
1
+ export { type ContractProviders, createProviders } from './providers.js';
2
+ export { type ImpureCircuitKeys } from './types.js';
@@ -0,0 +1,23 @@
1
+ import type { DeployConfig } from './types.js';
2
+
3
+ /**
4
+ * SDK providers needed for contract interaction.
5
+ * Fill in after connecting a compiled contract.
6
+ */
7
+ export interface ContractProviders {
8
+ // TODO: Add your provider types here after connecting a contract.
9
+ // Example:
10
+ // publicDataProvider: ...
11
+ // privateStateProvider: ...
12
+ // zkConfigProvider: ...
13
+ // proofProvider: ...
14
+ }
15
+
16
+ /**
17
+ * Create the set of providers for contract deployment and interaction.
18
+ */
19
+ export function createProviders(_config: DeployConfig): ContractProviders {
20
+ // TODO: Implement after connecting a contract.
21
+ // See: https://docs.midnight.network/develop/tutorial/building/providers
22
+ throw new Error('Not implemented — connect a compiled contract first');
23
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Union of impure circuit names exported by the contract.
3
+ * Replace with actual circuit names after connecting a compiled contract.
4
+ */
5
+ export type ImpureCircuitKeys = string;
6
+
7
+ /**
8
+ * Contract deployment configuration.
9
+ */
10
+ export type ProverConfig =
11
+ | { type: 'server'; url: string }
12
+ | { type: 'wasm' };
13
+
14
+ export interface DeployConfig {
15
+ /** Indexer GraphQL URL */
16
+ indexerUrl: string;
17
+ /** Indexer WebSocket URL */
18
+ indexerWsUrl: string;
19
+ /** Node WebSocket URL */
20
+ nodeUrl: string;
21
+ /** Proof generation configuration */
22
+ prover: ProverConfig;
23
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true
9
+ },
10
+ "include": ["src"]
11
+ }
@@ -0,0 +1,20 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ A Midnight DApp built with [Compact](https://docs.midnight.network/) smart contracts.
4
+
5
+ ## Structure
6
+
7
+ - `api/` — Contract API layer: providers, witnesses, and contract deployment
8
+ - `ui/` — React frontend with Vite
9
+
10
+ ## Development
11
+
12
+ ```bash
13
+ {{PACKAGE_MANAGER}} run dev
14
+ ```
15
+
16
+ ## Build
17
+
18
+ ```bash
19
+ {{PACKAGE_MANAGER}} run build
20
+ ```
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "jsx": "react-jsx"
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{{PROJECT_NAME}}</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "{{UI_PACKAGE_NAME}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "preview": "vite preview",
10
+ "test": "echo \"No tests configured yet\""
11
+ },
12
+ "dependencies": {
13
+ "{{API_PACKAGE_NAME}}": "{{WORKSPACE_PROTOCOL}}",
14
+ "react": "^19.0.0",
15
+ "react-dom": "^19.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/react": "^19.0.0",
19
+ "@types/react-dom": "^19.0.0",
20
+ "@vitejs/plugin-react": "^6.0.0",
21
+ "typescript": "^6.0.0",
22
+ "vite": "^8.0.0"
23
+ }
24
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFBD4F"></stop><stop offset="100%" stop-color="#FF9640"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
@@ -0,0 +1,36 @@
1
+ import { useState } from 'react';
2
+
3
+ export function App() {
4
+ const [status, setStatus] = useState<'disconnected' | 'connecting' | 'connected'>('disconnected');
5
+
6
+ const handleConnect = async () => {
7
+ setStatus('connecting');
8
+ try {
9
+ // TODO: Connect to Midnight wallet via DApp Connector API
10
+ // const api = await window.midnight.mnLace.enable();
11
+ setStatus('connected');
12
+ } catch {
13
+ setStatus('disconnected');
14
+ }
15
+ };
16
+
17
+ return (
18
+ <main style={{ maxWidth: 600, margin: '4rem auto', fontFamily: 'system-ui' }}>
19
+ <h1>{{PROJECT_NAME}}</h1>
20
+ <p>A Midnight DApp. Connect your wallet to get started.</p>
21
+
22
+ <button onClick={handleConnect} disabled={status === 'connecting'}>
23
+ {status === 'disconnected' && 'Connect Wallet'}
24
+ {status === 'connecting' && 'Connecting...'}
25
+ {status === 'connected' && 'Connected'}
26
+ </button>
27
+
28
+ {status === 'connected' && (
29
+ <section style={{ marginTop: '2rem' }}>
30
+ <h2>Contract Interaction</h2>
31
+ <p>Wire up your contract circuits here.</p>
32
+ </section>
33
+ )}
34
+ </main>
35
+ );
36
+ }
@@ -0,0 +1,29 @@
1
+ :root {
2
+ color-scheme: light dark;
3
+ }
4
+
5
+ body {
6
+ margin: 0;
7
+ font-family: system-ui, -apple-system, sans-serif;
8
+ -webkit-font-smoothing: antialiased;
9
+ }
10
+
11
+ button {
12
+ padding: 0.6rem 1.2rem;
13
+ font-size: 1rem;
14
+ border: 1px solid #646cff;
15
+ border-radius: 6px;
16
+ background: #646cff;
17
+ color: white;
18
+ cursor: pointer;
19
+ transition: background 0.2s;
20
+ }
21
+
22
+ button:hover:not(:disabled) {
23
+ background: #535bf2;
24
+ }
25
+
26
+ button:disabled {
27
+ opacity: 0.6;
28
+ cursor: not-allowed;
29
+ }
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { App } from './App.js';
4
+ import './index.css';
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ );
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ build: {
7
+ target: 'esnext',
8
+ },
9
+ optimizeDeps: {
10
+ esbuildOptions: {
11
+ target: 'esnext',
12
+ },
13
+ },
14
+ });