pinokiod 3.9.0 → 3.9.2
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/kernel/api/filepicker/index.js +59 -0
- package/kernel/api/fs/index.js +6 -4
- package/kernel/api/index.js +123 -37
- package/kernel/api/input/index.js +2 -0
- package/kernel/api/web/index.js +6 -0
- package/kernel/bin/caddy.js +127 -0
- package/kernel/bin/cloudflared.js +1 -0
- package/kernel/bin/conda.js +10 -2
- package/kernel/bin/cuda.js +0 -16
- package/kernel/bin/ffmpeg.js +4 -6
- package/kernel/bin/git.js +55 -29
- package/kernel/bin/gxx.js +8 -6
- package/kernel/bin/huggingface.js +4 -5
- package/kernel/bin/index.js +347 -88
- package/kernel/bin/node.js +13 -6
- package/kernel/bin/py.js +1 -1
- package/kernel/bin/setup.js +146 -0
- package/kernel/bin/uv.js +4 -5
- package/kernel/bin/zip.js +7 -8
- package/kernel/connect/index.js +25 -0
- package/kernel/connect/providers/github/README.md +11 -0
- package/kernel/connect/providers/x/README.md +96 -0
- package/kernel/connect/providers/x/index.js +152 -0
- package/kernel/environment.js +50 -1
- package/kernel/index.js +152 -32
- package/kernel/info.js +4 -2
- package/kernel/kv.js +38 -0
- package/kernel/loader.js +13 -3
- package/kernel/peer.js +161 -0
- package/kernel/procs.js +116 -0
- package/kernel/prototype.js +62 -0
- package/kernel/router/common.js +42 -0
- package/kernel/router/connector.js +81 -0
- package/kernel/router/index.js +235 -0
- package/kernel/router/localhost_home_router.js +84 -0
- package/kernel/router/localhost_port_router.js +15 -0
- package/kernel/router/localhost_variable_router.js +37 -0
- package/kernel/router/peer_home_router.js +15 -0
- package/kernel/router/peer_peer_router.js +26 -0
- package/kernel/router/peer_port_router.js +45 -0
- package/kernel/router/peer_variable_router.js +46 -0
- package/kernel/router/processor.js +31 -0
- package/kernel/shell.js +141 -60
- package/kernel/shells.js +32 -17
- package/kernel/store.js +58 -0
- package/kernel/sysinfo.js +0 -1
- package/kernel/util.js +143 -36
- package/package.json +4 -1
- package/pipe/index.js +0 -2
- package/script/index.js +12 -0
- package/server/index.js +1473 -553
- package/server/public/Socket.js +5 -1
- package/server/public/SourceCodePro-Regular.ttf +0 -0
- package/server/public/SpaceMono-Bold.ttf +0 -0
- package/server/public/SpaceMono-BoldItalic.ttf +0 -0
- package/server/public/SpaceMono-Italic.ttf +0 -0
- package/server/public/SpaceMono-Regular.ttf +0 -0
- package/server/public/commander.js +40 -0
- package/server/public/common.js +60 -0
- package/server/public/dropzone-min.js +2 -0
- package/server/public/dropzone.css +1 -0
- package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
- package/server/public/filepond-plugin-image-crop.min.js +9 -0
- package/server/public/filepond-plugin-image-edit.min.css +8 -0
- package/server/public/filepond-plugin-image-edit.min.js +9 -0
- package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
- package/server/public/filepond-plugin-image-preview.min.css +8 -0
- package/server/public/filepond-plugin-image-preview.min.js +9 -0
- package/server/public/filepond-plugin-image-resize.min.js +9 -0
- package/server/public/filepond-plugin-image-transform.min.js +9 -0
- package/server/public/filepond.min.css +8 -0
- package/server/public/filepond.min.js +9 -0
- package/server/public/fscreator.js +174 -0
- package/server/public/fseditor.js +212 -0
- package/server/public/github.png +0 -0
- package/server/public/highlight-js.js +81 -0
- package/server/public/highlight.css +9 -0
- package/server/public/highlight.js +1244 -0
- package/server/public/install.js +17 -20
- package/server/public/modalinput.js +105 -9
- package/server/public/opener.js +3 -1
- package/server/public/pinokio-black.png +0 -0
- package/server/public/pinokio-black2.png +0 -0
- package/server/public/redoc.standalone.js +1832 -0
- package/server/public/style.css +211 -17
- package/server/public/swagger-ui-bundle.js +2 -0
- package/server/public/swagger-ui.css +3 -0
- package/server/public/x.js +63 -0
- package/server/socket.js +136 -39
- package/server/views/404.ejs +0 -1
- package/server/views/app.ejs +356 -90
- package/server/views/bootstrap.ejs +22 -19
- package/server/views/connect/x.ejs +324 -0
- package/server/views/connect.ejs +197 -0
- package/server/views/download.ejs +7 -1
- package/server/views/editor.ejs +68 -9
- package/server/views/explore.ejs +13 -10
- package/server/views/file_explorer.ejs +10 -37
- package/server/views/github.ejs +218 -0
- package/server/views/help.ejs +4 -3
- package/server/views/index.ejs +268 -118
- package/server/views/install.ejs +56 -29
- package/server/views/keys.ejs +276 -0
- package/server/views/network.ejs +889 -0
- package/server/views/partials/dynamic.ejs +9 -0
- package/server/views/partials/menu.ejs +7 -1
- package/server/views/prototype/index.ejs +311 -0
- package/server/views/prototype/show.ejs +383 -0
- package/server/views/redoc.ejs +18 -0
- package/server/views/required_env_editor.ejs +11 -2
- package/server/views/settings.ejs +38 -10
- package/server/views/setup.ejs +254 -0
- package/server/views/setup_home.ejs +192 -0
- package/server/views/shell.ejs +781 -0
- package/server/views/swaggerui.ejs +19 -0
- package/server/views/terminal.ejs +174 -42
- package/LICENSE +0 -7
- package/server/views/proxy.ejs +0 -405
package/server/views/install.ejs
CHANGED
|
@@ -118,17 +118,21 @@ body {
|
|
|
118
118
|
<script src="/xterm-addon-fit.js"></script>
|
|
119
119
|
<script src="/xterm-addon-web-links.js"></script>
|
|
120
120
|
<script src="/xterm-theme.js"></script>
|
|
121
|
-
<script src="/modalinput.js"></script>
|
|
122
121
|
<script src="/Socket.js"></script>
|
|
123
122
|
<!--
|
|
124
123
|
<script src="/install.js"></script>
|
|
125
124
|
-->
|
|
126
125
|
<script src="/timeago.min.js"></script>
|
|
127
126
|
<script src="/common.js"></script>
|
|
127
|
+
<script src="/autoexpand.js"></script>
|
|
128
|
+
<script src="/modalinput.js"></script>
|
|
129
|
+
<script src="/simplemodal.js"></script>
|
|
130
|
+
<script src="/waitmodal.js"></script>
|
|
131
|
+
<script src="/notifyinput.js"></script>
|
|
128
132
|
</head>
|
|
129
133
|
<body class='<%=theme%>'>
|
|
130
134
|
<header class='grabbable'></header>
|
|
131
|
-
<div id='status-screen'></div>
|
|
135
|
+
<div id='status-screen'><b><i class="fas fa-circle-notch fa-spin"></i> Setting up...</b><br>Setting up core modules including conda, uv, git, etc.</div>
|
|
132
136
|
<div class='terminal-container'>
|
|
133
137
|
<div id='terminal'></div>
|
|
134
138
|
</div>
|
|
@@ -138,31 +142,24 @@ body {
|
|
|
138
142
|
//
|
|
139
143
|
// /install_bin?type=bin&uri=conda
|
|
140
144
|
//
|
|
141
|
-
const createTerm = () => {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
theme
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//theme: xtermTheme.AtelierSulphurpool,
|
|
160
|
-
//theme: xtermTheme.Borland,
|
|
161
|
-
fontSize: 12,
|
|
162
|
-
//cursorBlink: false,
|
|
163
|
-
//cursorStyle: 'block'
|
|
164
|
-
|
|
165
|
-
});
|
|
145
|
+
const createTerm = async (_theme) => {
|
|
146
|
+
//const theme = Object.assign({ }, xtermTheme.Terminal_Basic, {
|
|
147
|
+
const theme = Object.assign({ }, _theme, {
|
|
148
|
+
selectionBackground: "red",
|
|
149
|
+
selectionForeground: "white"
|
|
150
|
+
})
|
|
151
|
+
let config = {
|
|
152
|
+
scrollback: 9999999,
|
|
153
|
+
fontSize: 14,
|
|
154
|
+
theme,
|
|
155
|
+
}
|
|
156
|
+
let res = await fetch("/xterm_config").then((res) => {
|
|
157
|
+
return res.json()
|
|
158
|
+
})
|
|
159
|
+
if (res && res.config) {
|
|
160
|
+
config = res.config
|
|
161
|
+
}
|
|
162
|
+
const term = new Terminal(config)
|
|
166
163
|
term.open(document.querySelector("#terminal"))
|
|
167
164
|
|
|
168
165
|
term.attachCustomKeyEventHandler(event => {
|
|
@@ -191,7 +188,11 @@ const createTerm = () => {
|
|
|
191
188
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
192
189
|
const n = new N()
|
|
193
190
|
let socket = new Socket()
|
|
194
|
-
|
|
191
|
+
<% if (theme === "dark") { %>
|
|
192
|
+
let term = await createTerm(xtermTheme.FrontEndDelight)
|
|
193
|
+
<% } else { %>
|
|
194
|
+
let term = await createTerm(xtermTheme.Tomorrow)
|
|
195
|
+
<% } %>
|
|
195
196
|
let params = new URLSearchParams(location.search)
|
|
196
197
|
let entries = [...params.entries()]
|
|
197
198
|
let options;
|
|
@@ -217,7 +218,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
217
218
|
cols: term.cols,
|
|
218
219
|
rows: term.rows,
|
|
219
220
|
}
|
|
220
|
-
}, (packet) => {
|
|
221
|
+
}, async (packet) => {
|
|
221
222
|
console.log("packet", packet)
|
|
222
223
|
if (packet.type === "stream") {
|
|
223
224
|
term.write(packet.data.raw)
|
|
@@ -254,6 +255,32 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
254
255
|
}
|
|
255
256
|
n.Noty(payload)
|
|
256
257
|
}
|
|
258
|
+
} else if (packet.type === "input") {
|
|
259
|
+
let params = packet.data
|
|
260
|
+
/*
|
|
261
|
+
params := {
|
|
262
|
+
title,
|
|
263
|
+
description,
|
|
264
|
+
form: [{
|
|
265
|
+
title,
|
|
266
|
+
description
|
|
267
|
+
}]
|
|
268
|
+
}
|
|
269
|
+
*/
|
|
270
|
+
let type = (params.type ? params.type : "modal")
|
|
271
|
+
let input
|
|
272
|
+
if (type === "modal") {
|
|
273
|
+
input = await ModalInput(packet.data)
|
|
274
|
+
} else if (type === "notify") {
|
|
275
|
+
input = await NotifyInput(packet.data, n)
|
|
276
|
+
}
|
|
277
|
+
console.log("RESPOND", { input, packet })
|
|
278
|
+
if (input) {
|
|
279
|
+
socket.respond({
|
|
280
|
+
response: input,
|
|
281
|
+
uri: packet.id
|
|
282
|
+
})
|
|
283
|
+
}
|
|
257
284
|
}
|
|
258
285
|
})
|
|
259
286
|
})
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
<html class='columns'>
|
|
2
|
+
<head>
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
|
4
|
+
<script src="/hotkeys.min.js"></script>
|
|
5
|
+
<script src="/ace/ace.js"></script>
|
|
6
|
+
<script src="/noty.js"></script>
|
|
7
|
+
<script src="/notyq.js"></script>
|
|
8
|
+
<script src="/xterm.js"></script>
|
|
9
|
+
<script src="/xterm-addon-fit.js"></script>
|
|
10
|
+
<script src="/xterm-addon-web-links.js"></script>
|
|
11
|
+
<script src="/xterm-theme.js"></script>
|
|
12
|
+
<script src="/xterm-addon-search.js"></script>
|
|
13
|
+
<script src="/xterm-addon-search-bar.js"></script>
|
|
14
|
+
<script src="/sweetalert2.js"></script>
|
|
15
|
+
<script src="/Socket.js"></script>
|
|
16
|
+
<script src="/common.js"></script>
|
|
17
|
+
<script src="/he.js"></script>
|
|
18
|
+
<script src="/opener.js"></script>
|
|
19
|
+
<script src="/nav.js"></script>
|
|
20
|
+
<script src="/autoexpand.js"></script>
|
|
21
|
+
<script src="/modalinput.js"></script>
|
|
22
|
+
<script src="/simplemodal.js"></script>
|
|
23
|
+
<script src="/waitmodal.js"></script>
|
|
24
|
+
<script src="/notifyinput.js"></script>
|
|
25
|
+
<script src="/report.js"></script>
|
|
26
|
+
<link href="/xterm.min.css" rel="stylesheet" />
|
|
27
|
+
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
|
28
|
+
<link href="/css/solid.min.css" rel="stylesheet">
|
|
29
|
+
<link href="/css/regular.min.css" rel="stylesheet">
|
|
30
|
+
<link href="/css/brands.min.css" rel="stylesheet">
|
|
31
|
+
<link href="/style.css" rel="stylesheet"/>
|
|
32
|
+
<link href="/noty.css" rel="stylesheet"/>
|
|
33
|
+
<% if (agent === "electron") { %>
|
|
34
|
+
<link href="/electron.css" rel="stylesheet"/>
|
|
35
|
+
<% } %>
|
|
36
|
+
<style>
|
|
37
|
+
body.frozen {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
height: 100%;
|
|
41
|
+
}
|
|
42
|
+
#table > table {
|
|
43
|
+
border-left: 2px solid black;
|
|
44
|
+
padding-left: 5px;
|
|
45
|
+
margin: 10px 0;
|
|
46
|
+
}
|
|
47
|
+
.highlight {
|
|
48
|
+
background: yellow;
|
|
49
|
+
width: 100px;
|
|
50
|
+
}
|
|
51
|
+
th {
|
|
52
|
+
background: rgba(0,0,0,0.1);
|
|
53
|
+
padding: 10px;
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
}
|
|
56
|
+
td {
|
|
57
|
+
font-size: 12px;
|
|
58
|
+
padding: 10px;
|
|
59
|
+
}
|
|
60
|
+
td.val {
|
|
61
|
+
background: rgba(0,0,0,0.06);
|
|
62
|
+
}
|
|
63
|
+
td.key {
|
|
64
|
+
background: rgba(0,0,0,0.1);
|
|
65
|
+
}
|
|
66
|
+
.button {
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
background: rgba(0,0,0,0.8);
|
|
69
|
+
color: white;
|
|
70
|
+
padding: 5px 10px;
|
|
71
|
+
border-radius: 4px;
|
|
72
|
+
}
|
|
73
|
+
.button:hover {
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
#editor {
|
|
77
|
+
width: 100%;
|
|
78
|
+
box-sizing: border-box;
|
|
79
|
+
max-width: 600px;
|
|
80
|
+
padding: 20px;
|
|
81
|
+
margin: 0 auto;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
header .btn {
|
|
85
|
+
font-family: Sans-serif;
|
|
86
|
+
display: block;
|
|
87
|
+
margin-left: 10px;
|
|
88
|
+
font-style: normal;
|
|
89
|
+
font-size: 12px;
|
|
90
|
+
font-weight: normal;
|
|
91
|
+
padding: 5px 10px;
|
|
92
|
+
}
|
|
93
|
+
.disabled {
|
|
94
|
+
opacity: 0.7;
|
|
95
|
+
}
|
|
96
|
+
body.dark .env-item input[type=text] {
|
|
97
|
+
background: white;
|
|
98
|
+
}
|
|
99
|
+
.env-item input[type=text] {
|
|
100
|
+
width: 100%;
|
|
101
|
+
padding: 10px;
|
|
102
|
+
box-sizing: border-box;
|
|
103
|
+
border: none;
|
|
104
|
+
background: rgba(0,0,100, 0.1);
|
|
105
|
+
}
|
|
106
|
+
body.dark .env-item label {
|
|
107
|
+
color: cornflowerblue;
|
|
108
|
+
}
|
|
109
|
+
.env-item label {
|
|
110
|
+
color: royalblue;
|
|
111
|
+
display: block;
|
|
112
|
+
margin-bottom: 5px;
|
|
113
|
+
font-weight: bold;
|
|
114
|
+
font-size: 18px;
|
|
115
|
+
}
|
|
116
|
+
.env-item.highlighted {
|
|
117
|
+
border: 5px solid red;
|
|
118
|
+
}
|
|
119
|
+
.env-item {
|
|
120
|
+
/*
|
|
121
|
+
padding-top: 10px;
|
|
122
|
+
padding-bottom: 30px;
|
|
123
|
+
*/
|
|
124
|
+
padding: 10px;
|
|
125
|
+
margin-bottom: 20px;
|
|
126
|
+
}
|
|
127
|
+
body.dark .comment {
|
|
128
|
+
border-left: 2px solid white;
|
|
129
|
+
}
|
|
130
|
+
.comment {
|
|
131
|
+
opacity: 0.8;
|
|
132
|
+
border-left: 2px solid black;
|
|
133
|
+
padding-left: 10px;
|
|
134
|
+
}
|
|
135
|
+
#save {
|
|
136
|
+
background: royalblue;
|
|
137
|
+
}
|
|
138
|
+
a#customize {
|
|
139
|
+
text-decoration: underline;
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
}
|
|
142
|
+
.e {
|
|
143
|
+
padding: 10px 0;
|
|
144
|
+
}
|
|
145
|
+
#editor {
|
|
146
|
+
padding: 20px 0;
|
|
147
|
+
}
|
|
148
|
+
.center {
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
justify-content: center;
|
|
152
|
+
}
|
|
153
|
+
body {
|
|
154
|
+
display: block;
|
|
155
|
+
}
|
|
156
|
+
.card {
|
|
157
|
+
display: flex;
|
|
158
|
+
padding: 10px 0;
|
|
159
|
+
box-sizing: border-box;
|
|
160
|
+
}
|
|
161
|
+
.card img {
|
|
162
|
+
width: 100px;
|
|
163
|
+
border-radius: 10px;
|
|
164
|
+
}
|
|
165
|
+
.card .description {
|
|
166
|
+
opacity: 0.8;
|
|
167
|
+
}
|
|
168
|
+
.card .title {
|
|
169
|
+
font-weight: bold;
|
|
170
|
+
font-size: 30px;
|
|
171
|
+
letter-spacing: -1px;
|
|
172
|
+
}
|
|
173
|
+
.card .col {
|
|
174
|
+
padding-left: 10px;
|
|
175
|
+
}
|
|
176
|
+
h1 {
|
|
177
|
+
font-size: 50px;
|
|
178
|
+
padding-bottom: 20px;
|
|
179
|
+
}
|
|
180
|
+
footer {
|
|
181
|
+
background: none;
|
|
182
|
+
padding: 0;
|
|
183
|
+
text-align: right;
|
|
184
|
+
display: flex;
|
|
185
|
+
margin: 10px 0 20px 0;
|
|
186
|
+
}
|
|
187
|
+
footer .btn {
|
|
188
|
+
margin-left: 10px;
|
|
189
|
+
display: inline-block;
|
|
190
|
+
-webkit-appearance: button;
|
|
191
|
+
-moz-appearance: button;
|
|
192
|
+
appearance: button;
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
footer .btn.go-home {
|
|
196
|
+
margin-left: 0px;
|
|
197
|
+
}
|
|
198
|
+
.btn.home-button {
|
|
199
|
+
background: none !important;
|
|
200
|
+
margin: 0 !important;
|
|
201
|
+
font-size: 16px !important;
|
|
202
|
+
}
|
|
203
|
+
#editor {
|
|
204
|
+
height: auto;
|
|
205
|
+
}
|
|
206
|
+
.env-title {
|
|
207
|
+
font-weight: bold;
|
|
208
|
+
}
|
|
209
|
+
.env-description {
|
|
210
|
+
margin-bottom: 10px;
|
|
211
|
+
}
|
|
212
|
+
input[type=text] {
|
|
213
|
+
margin-bottom: 5px;
|
|
214
|
+
}
|
|
215
|
+
</style>
|
|
216
|
+
<script>
|
|
217
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
218
|
+
const n = new N()
|
|
219
|
+
let updated = {}
|
|
220
|
+
document.addEventListener("input", (e) => {
|
|
221
|
+
let host = e.target.getAttribute("data-host")
|
|
222
|
+
let index = e.target.getAttribute("data-index")
|
|
223
|
+
if (!updated[host]) {
|
|
224
|
+
updated[host] = {}
|
|
225
|
+
}
|
|
226
|
+
updated[host][index] = e.target.value
|
|
227
|
+
})
|
|
228
|
+
document.querySelector("#save").addEventListener("click", async (e) => {
|
|
229
|
+
console.log({ updated })
|
|
230
|
+
let res = await fetch("/keys", {
|
|
231
|
+
method: "POST",
|
|
232
|
+
headers: {
|
|
233
|
+
"Content-Type": "application/json"
|
|
234
|
+
},
|
|
235
|
+
body: JSON.stringify(updated)
|
|
236
|
+
}).then((res) => {
|
|
237
|
+
return res.json()
|
|
238
|
+
})
|
|
239
|
+
console.log("res" ,res)
|
|
240
|
+
n.Noty({
|
|
241
|
+
text: `Updated!`
|
|
242
|
+
})
|
|
243
|
+
setTimeout(() => {
|
|
244
|
+
location.href = location.href
|
|
245
|
+
}, 1000)
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
</script>
|
|
249
|
+
</head>
|
|
250
|
+
<body class='<%=theme%>'>
|
|
251
|
+
<main>
|
|
252
|
+
<header class='navheader grabbable'>
|
|
253
|
+
<h1>
|
|
254
|
+
<a class='home-button home' href="/"><i class='fa-solid fa-home'></i></a>
|
|
255
|
+
<div class='flexible'></div>
|
|
256
|
+
<div class='nav-btns'>
|
|
257
|
+
<button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> Open in File Explorer</button>
|
|
258
|
+
<div id='save' class='btn'>
|
|
259
|
+
<span class='save'><i class="fa-solid fa-check"></i> Save</span>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</h1>
|
|
263
|
+
</header>
|
|
264
|
+
<div id='editor'>
|
|
265
|
+
<% items.forEach((item) => { %>
|
|
266
|
+
<div class='env-item'>
|
|
267
|
+
<label for="<%=item.host%>"><%=item.host%></label>
|
|
268
|
+
<% item.vals.forEach((val, index) => { %>
|
|
269
|
+
<input data-host="<%=item.host%>" data-index="<%=index%>" type="text" value="<%=val%>">
|
|
270
|
+
<% }) %>
|
|
271
|
+
</div>
|
|
272
|
+
<% }) %>
|
|
273
|
+
</div>
|
|
274
|
+
</main>
|
|
275
|
+
</body>
|
|
276
|
+
</html>
|