cfei1994 commited on
Commit
b33ca75
·
verified ·
1 Parent(s): a05ec38

Upload 5 files

Browse files
Files changed (5) hide show
  1. Dockerfile +11 -0
  2. Manifest.toml +558 -0
  3. Project.toml +10 -0
  4. index.html +498 -0
  5. server.jl +161 -0
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM julia:1.9
2
+
3
+ WORKDIR /app
4
+
5
+ COPY . .
6
+
7
+ RUN julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()'
8
+
9
+ EXPOSE 7860
10
+
11
+ CMD ["julia", "--project=.", "server.jl"]
Manifest.toml ADDED
@@ -0,0 +1,558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is machine-generated - editing it directly is not advised
2
+
3
+ julia_version = "1.9.3"
4
+ manifest_format = "2.0"
5
+ project_hash = "b83afd87647a69c61287d3f2945d7025e21be452"
6
+
7
+ [[deps.Adapt]]
8
+ deps = ["LinearAlgebra", "Requires"]
9
+ git-tree-sha1 = "7e35fca2bdfba44d797c53dfe63a51fabf39bfc0"
10
+ uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
11
+ version = "4.4.0"
12
+ weakdeps = ["SparseArrays", "StaticArrays"]
13
+
14
+ [deps.Adapt.extensions]
15
+ AdaptSparseArraysExt = "SparseArrays"
16
+ AdaptStaticArraysExt = "StaticArrays"
17
+
18
+ [[deps.ArgTools]]
19
+ uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
20
+ version = "1.1.1"
21
+
22
+ [[deps.Artifacts]]
23
+ uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
24
+
25
+ [[deps.AxisAlgorithms]]
26
+ deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
27
+ git-tree-sha1 = "01b8ccb13d68535d73d2b0c23e39bd23155fb712"
28
+ uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
29
+ version = "1.1.0"
30
+
31
+ [[deps.Base64]]
32
+ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
33
+
34
+ [[deps.BitFlags]]
35
+ git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d"
36
+ uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
37
+ version = "0.1.9"
38
+
39
+ [[deps.CSV]]
40
+ deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"]
41
+ git-tree-sha1 = "deddd8725e5e1cc49ee205a1964256043720a6c3"
42
+ uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
43
+ version = "0.10.15"
44
+
45
+ [[deps.ChainRulesCore]]
46
+ deps = ["Compat", "LinearAlgebra"]
47
+ git-tree-sha1 = "06ee8d1aa558d2833aa799f6f0b31b30cada405f"
48
+ uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
49
+ version = "1.25.2"
50
+ weakdeps = ["SparseArrays"]
51
+
52
+ [deps.ChainRulesCore.extensions]
53
+ ChainRulesCoreSparseArraysExt = "SparseArrays"
54
+
55
+ [[deps.CodecZlib]]
56
+ deps = ["TranscodingStreams", "Zlib_jll"]
57
+ git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9"
58
+ uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
59
+ version = "0.7.8"
60
+
61
+ [[deps.Compat]]
62
+ deps = ["TOML", "UUIDs"]
63
+ git-tree-sha1 = "9d8a54ce4b17aa5bdce0ea5c34bc5e7c340d16ad"
64
+ uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
65
+ version = "4.18.1"
66
+ weakdeps = ["Dates", "LinearAlgebra"]
67
+
68
+ [deps.Compat.extensions]
69
+ CompatLinearAlgebraExt = "LinearAlgebra"
70
+
71
+ [[deps.CompilerSupportLibraries_jll]]
72
+ deps = ["Artifacts", "Libdl"]
73
+ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
74
+ version = "1.0.5+0"
75
+
76
+ [[deps.ConcurrentUtilities]]
77
+ deps = ["Serialization", "Sockets"]
78
+ git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd"
79
+ uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb"
80
+ version = "2.5.0"
81
+
82
+ [[deps.Crayons]]
83
+ git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
84
+ uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
85
+ version = "4.1.1"
86
+
87
+ [[deps.DataAPI]]
88
+ git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe"
89
+ uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
90
+ version = "1.16.0"
91
+
92
+ [[deps.DataFrames]]
93
+ deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
94
+ git-tree-sha1 = "a37ac0840a1196cd00317b57e39d6586bf0fd6f6"
95
+ uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
96
+ version = "1.7.1"
97
+
98
+ [[deps.DataStructures]]
99
+ deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
100
+ git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0"
101
+ uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
102
+ version = "0.18.22"
103
+
104
+ [[deps.DataValueInterfaces]]
105
+ git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
106
+ uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
107
+ version = "1.0.0"
108
+
109
+ [[deps.Dates]]
110
+ deps = ["Printf"]
111
+ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
112
+
113
+ [[deps.Distributed]]
114
+ deps = ["Random", "Serialization", "Sockets"]
115
+ uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
116
+
117
+ [[deps.Downloads]]
118
+ deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
119
+ uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
120
+ version = "1.6.0"
121
+
122
+ [[deps.ExceptionUnwrapping]]
123
+ deps = ["Test"]
124
+ git-tree-sha1 = "d36f682e590a83d63d1c7dbd287573764682d12a"
125
+ uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4"
126
+ version = "0.1.11"
127
+
128
+ [[deps.FilePathsBase]]
129
+ deps = ["Compat", "Dates"]
130
+ git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2"
131
+ uuid = "48062228-2e41-5def-b9a4-89aafe57970f"
132
+ version = "0.9.24"
133
+ weakdeps = ["Mmap", "Test"]
134
+
135
+ [deps.FilePathsBase.extensions]
136
+ FilePathsBaseMmapExt = "Mmap"
137
+ FilePathsBaseTestExt = "Test"
138
+
139
+ [[deps.FileWatching]]
140
+ uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
141
+
142
+ [[deps.Future]]
143
+ deps = ["Random"]
144
+ uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"
145
+
146
+ [[deps.HTTP]]
147
+ deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"]
148
+ git-tree-sha1 = "5e6fe50ae7f23d171f44e311c2960294aaa0beb5"
149
+ uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
150
+ version = "1.10.19"
151
+
152
+ [[deps.InlineStrings]]
153
+ git-tree-sha1 = "8f3d257792a522b4601c24a577954b0a8cd7334d"
154
+ uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48"
155
+ version = "1.4.5"
156
+
157
+ [deps.InlineStrings.extensions]
158
+ ArrowTypesExt = "ArrowTypes"
159
+ ParsersExt = "Parsers"
160
+
161
+ [deps.InlineStrings.weakdeps]
162
+ ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
163
+ Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
164
+
165
+ [[deps.InteractiveUtils]]
166
+ deps = ["Markdown"]
167
+ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
168
+
169
+ [[deps.Interpolations]]
170
+ deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
171
+ git-tree-sha1 = "65d505fa4c0d7072990d659ef3fc086eb6da8208"
172
+ uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
173
+ version = "0.16.2"
174
+
175
+ [deps.Interpolations.extensions]
176
+ InterpolationsForwardDiffExt = "ForwardDiff"
177
+ InterpolationsUnitfulExt = "Unitful"
178
+
179
+ [deps.Interpolations.weakdeps]
180
+ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
181
+ Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
182
+
183
+ [[deps.InvertedIndices]]
184
+ git-tree-sha1 = "6da3c4316095de0f5ee2ebd875df8721e7e0bdbe"
185
+ uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f"
186
+ version = "1.3.1"
187
+
188
+ [[deps.IteratorInterfaceExtensions]]
189
+ git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
190
+ uuid = "82899510-4779-5014-852e-03e436cf321d"
191
+ version = "1.0.0"
192
+
193
+ [[deps.JLLWrappers]]
194
+ deps = ["Artifacts", "Preferences"]
195
+ git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2"
196
+ uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
197
+ version = "1.7.1"
198
+
199
+ [[deps.JSON3]]
200
+ deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"]
201
+ git-tree-sha1 = "411eccfe8aba0814ffa0fdf4860913ed09c34975"
202
+ uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
203
+ version = "1.14.3"
204
+
205
+ [deps.JSON3.extensions]
206
+ JSON3ArrowExt = ["ArrowTypes"]
207
+
208
+ [deps.JSON3.weakdeps]
209
+ ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
210
+
211
+ [[deps.LaTeXStrings]]
212
+ git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c"
213
+ uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
214
+ version = "1.4.0"
215
+
216
+ [[deps.LibCURL]]
217
+ deps = ["LibCURL_jll", "MozillaCACerts_jll"]
218
+ uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
219
+ version = "0.6.3"
220
+
221
+ [[deps.LibCURL_jll]]
222
+ deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
223
+ uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
224
+ version = "7.84.0+0"
225
+
226
+ [[deps.LibGit2]]
227
+ deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
228
+ uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
229
+
230
+ [[deps.LibSSH2_jll]]
231
+ deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
232
+ uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
233
+ version = "1.10.2+0"
234
+
235
+ [[deps.Libdl]]
236
+ uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
237
+
238
+ [[deps.LinearAlgebra]]
239
+ deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
240
+ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
241
+
242
+ [[deps.Logging]]
243
+ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
244
+
245
+ [[deps.LoggingExtras]]
246
+ deps = ["Dates", "Logging"]
247
+ git-tree-sha1 = "f00544d95982ea270145636c181ceda21c4e2575"
248
+ uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
249
+ version = "1.2.0"
250
+
251
+ [[deps.MIMEs]]
252
+ git-tree-sha1 = "c64d943587f7187e751162b3b84445bbbd79f691"
253
+ uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65"
254
+ version = "1.1.0"
255
+
256
+ [[deps.Markdown]]
257
+ deps = ["Base64"]
258
+ uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
259
+
260
+ [[deps.MbedTLS]]
261
+ deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"]
262
+ git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf"
263
+ uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
264
+ version = "1.1.9"
265
+
266
+ [[deps.MbedTLS_jll]]
267
+ deps = ["Artifacts", "Libdl"]
268
+ uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
269
+ version = "2.28.2+0"
270
+
271
+ [[deps.Missings]]
272
+ deps = ["DataAPI"]
273
+ git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d"
274
+ uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
275
+ version = "1.2.0"
276
+
277
+ [[deps.Mmap]]
278
+ uuid = "a63ad114-7e13-5084-954f-fe012c677804"
279
+
280
+ [[deps.MozillaCACerts_jll]]
281
+ uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
282
+ version = "2022.10.11"
283
+
284
+ [[deps.NetworkOptions]]
285
+ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
286
+ version = "1.2.0"
287
+
288
+ [[deps.OffsetArrays]]
289
+ git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151"
290
+ uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
291
+ version = "1.17.0"
292
+ weakdeps = ["Adapt"]
293
+
294
+ [deps.OffsetArrays.extensions]
295
+ OffsetArraysAdaptExt = "Adapt"
296
+
297
+ [[deps.OpenBLAS_jll]]
298
+ deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
299
+ uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
300
+ version = "0.3.21+4"
301
+
302
+ [[deps.OpenSSL]]
303
+ deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "NetworkOptions", "OpenSSL_jll", "Sockets"]
304
+ git-tree-sha1 = "1d1aaa7d449b58415f97d2839c318b70ffb525a0"
305
+ uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c"
306
+ version = "1.6.1"
307
+
308
+ [[deps.OpenSSL_jll]]
309
+ deps = ["Artifacts", "JLLWrappers", "Libdl"]
310
+ git-tree-sha1 = "f19301ae653233bc88b1810ae908194f07f8db9d"
311
+ uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
312
+ version = "3.5.4+0"
313
+
314
+ [[deps.OrderedCollections]]
315
+ git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee"
316
+ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
317
+ version = "1.8.1"
318
+
319
+ [[deps.Oxygen]]
320
+ deps = ["DataStructures", "Dates", "HTTP", "JSON3", "MIMEs", "Reexport", "RelocatableFolders", "Requires", "Sockets", "Statistics", "StructTypes"]
321
+ git-tree-sha1 = "2ad010b0de6172faf1d09ed5e0837eb0b7355bd8"
322
+ uuid = "df9a0d86-3283-4920-82dc-4555fc0d1d8b"
323
+ version = "1.5.16"
324
+
325
+ [[deps.Parsers]]
326
+ deps = ["Dates", "PrecompileTools", "UUIDs"]
327
+ git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810"
328
+ uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
329
+ version = "2.8.3"
330
+
331
+ [[deps.Pkg]]
332
+ deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
333
+ uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
334
+ version = "1.9.2"
335
+
336
+ [[deps.PooledArrays]]
337
+ deps = ["DataAPI", "Future"]
338
+ git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3"
339
+ uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
340
+ version = "1.4.3"
341
+
342
+ [[deps.PrecompileTools]]
343
+ deps = ["Preferences"]
344
+ git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f"
345
+ uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
346
+ version = "1.2.1"
347
+
348
+ [[deps.Preferences]]
349
+ deps = ["TOML"]
350
+ git-tree-sha1 = "522f093a29b31a93e34eaea17ba055d850edea28"
351
+ uuid = "21216c6a-2e73-6563-6e65-726566657250"
352
+ version = "1.5.1"
353
+
354
+ [[deps.PrettyTables]]
355
+ deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"]
356
+ git-tree-sha1 = "66b20dd35966a748321d3b2537c4584cf40387c7"
357
+ uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
358
+ version = "2.3.2"
359
+
360
+ [[deps.Printf]]
361
+ deps = ["Unicode"]
362
+ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
363
+
364
+ [[deps.REPL]]
365
+ deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
366
+ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
367
+
368
+ [[deps.Random]]
369
+ deps = ["SHA", "Serialization"]
370
+ uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
371
+
372
+ [[deps.Ratios]]
373
+ deps = ["Requires"]
374
+ git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b"
375
+ uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
376
+ version = "0.4.5"
377
+
378
+ [deps.Ratios.extensions]
379
+ RatiosFixedPointNumbersExt = "FixedPointNumbers"
380
+
381
+ [deps.Ratios.weakdeps]
382
+ FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
383
+
384
+ [[deps.Reexport]]
385
+ git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
386
+ uuid = "189a3867-3050-52da-a836-e630ba90ab69"
387
+ version = "1.2.2"
388
+
389
+ [[deps.RelocatableFolders]]
390
+ deps = ["SHA", "Scratch"]
391
+ git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864"
392
+ uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
393
+ version = "1.0.1"
394
+
395
+ [[deps.Requires]]
396
+ deps = ["UUIDs"]
397
+ git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64"
398
+ uuid = "ae029012-a4dd-5104-9daa-d747884805df"
399
+ version = "1.3.1"
400
+
401
+ [[deps.SHA]]
402
+ uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
403
+ version = "0.7.0"
404
+
405
+ [[deps.Scratch]]
406
+ deps = ["Dates"]
407
+ git-tree-sha1 = "9b81b8393e50b7d4e6d0a9f14e192294d3b7c109"
408
+ uuid = "6c6a2e73-6563-6170-7368-637461726353"
409
+ version = "1.3.0"
410
+
411
+ [[deps.SentinelArrays]]
412
+ deps = ["Dates", "Random"]
413
+ git-tree-sha1 = "ebe7e59b37c400f694f52b58c93d26201387da70"
414
+ uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
415
+ version = "1.4.9"
416
+
417
+ [[deps.Serialization]]
418
+ uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
419
+
420
+ [[deps.SharedArrays]]
421
+ deps = ["Distributed", "Mmap", "Random", "Serialization"]
422
+ uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"
423
+
424
+ [[deps.SimpleBufferStream]]
425
+ git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1"
426
+ uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7"
427
+ version = "1.2.0"
428
+
429
+ [[deps.Sockets]]
430
+ uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
431
+
432
+ [[deps.SortingAlgorithms]]
433
+ deps = ["DataStructures"]
434
+ git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9"
435
+ uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
436
+ version = "1.2.2"
437
+
438
+ [[deps.SparseArrays]]
439
+ deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
440
+ uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
441
+
442
+ [[deps.StaticArrays]]
443
+ deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"]
444
+ git-tree-sha1 = "b8693004b385c842357406e3af647701fe783f98"
445
+ uuid = "90137ffa-7385-5640-81b9-e52037218182"
446
+ version = "1.9.15"
447
+ weakdeps = ["ChainRulesCore", "Statistics"]
448
+
449
+ [deps.StaticArrays.extensions]
450
+ StaticArraysChainRulesCoreExt = "ChainRulesCore"
451
+ StaticArraysStatisticsExt = "Statistics"
452
+
453
+ [[deps.StaticArraysCore]]
454
+ git-tree-sha1 = "6ab403037779dae8c514bad259f32a447262455a"
455
+ uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
456
+ version = "1.4.4"
457
+
458
+ [[deps.Statistics]]
459
+ deps = ["LinearAlgebra", "SparseArrays"]
460
+ uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
461
+ version = "1.9.0"
462
+
463
+ [[deps.StringManipulation]]
464
+ deps = ["PrecompileTools"]
465
+ git-tree-sha1 = "a04cabe79c5f01f4d723cc6704070ada0b9d46d5"
466
+ uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e"
467
+ version = "0.3.4"
468
+
469
+ [[deps.StructTypes]]
470
+ deps = ["Dates", "UUIDs"]
471
+ git-tree-sha1 = "159331b30e94d7b11379037feeb9b690950cace8"
472
+ uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
473
+ version = "1.11.0"
474
+
475
+ [[deps.SuiteSparse_jll]]
476
+ deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"]
477
+ uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
478
+ version = "5.10.1+6"
479
+
480
+ [[deps.TOML]]
481
+ deps = ["Dates"]
482
+ uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
483
+ version = "1.0.3"
484
+
485
+ [[deps.TableTraits]]
486
+ deps = ["IteratorInterfaceExtensions"]
487
+ git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
488
+ uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
489
+ version = "1.0.1"
490
+
491
+ [[deps.Tables]]
492
+ deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"]
493
+ git-tree-sha1 = "f2c1efbc8f3a609aadf318094f8fc5204bdaf344"
494
+ uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
495
+ version = "1.12.1"
496
+
497
+ [[deps.Tar]]
498
+ deps = ["ArgTools", "SHA"]
499
+ uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
500
+ version = "1.10.0"
501
+
502
+ [[deps.Test]]
503
+ deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
504
+ uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
505
+
506
+ [[deps.TranscodingStreams]]
507
+ git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742"
508
+ uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
509
+ version = "0.11.3"
510
+
511
+ [[deps.URIs]]
512
+ git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a"
513
+ uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
514
+ version = "1.6.1"
515
+
516
+ [[deps.UUIDs]]
517
+ deps = ["Random", "SHA"]
518
+ uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
519
+
520
+ [[deps.Unicode]]
521
+ uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
522
+
523
+ [[deps.WeakRefStrings]]
524
+ deps = ["DataAPI", "InlineStrings", "Parsers"]
525
+ git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23"
526
+ uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5"
527
+ version = "1.4.2"
528
+
529
+ [[deps.WoodburyMatrices]]
530
+ deps = ["LinearAlgebra", "SparseArrays"]
531
+ git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511"
532
+ uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
533
+ version = "1.0.0"
534
+
535
+ [[deps.WorkerUtilities]]
536
+ git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7"
537
+ uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60"
538
+ version = "1.6.1"
539
+
540
+ [[deps.Zlib_jll]]
541
+ deps = ["Libdl"]
542
+ uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
543
+ version = "1.2.13+0"
544
+
545
+ [[deps.libblastrampoline_jll]]
546
+ deps = ["Artifacts", "Libdl"]
547
+ uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
548
+ version = "5.8.0+0"
549
+
550
+ [[deps.nghttp2_jll]]
551
+ deps = ["Artifacts", "Libdl"]
552
+ uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
553
+ version = "1.48.0+0"
554
+
555
+ [[deps.p7zip_jll]]
556
+ deps = ["Artifacts", "Libdl"]
557
+ uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
558
+ version = "17.4.0+0"
Project.toml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ [deps]
2
+ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
3
+ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
4
+ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
5
+ HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
6
+ Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
7
+ JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
8
+ Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b"
9
+ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
10
+ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
index.html ADDED
@@ -0,0 +1,498 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>3D Mosquito Trajectory Visualizer</title>
6
+ <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
7
+
8
+ <style>
9
+ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; overflow: hidden; }
10
+ #controls.top-banner {
11
+ position: fixed;
12
+ top: 0;
13
+ left: 0;
14
+ width: 100%;
15
+ height: 60px; /* Fixed height for a slim look */
16
+ background: rgba(255, 255, 255, 0.95);
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-around; /* Distributes items evenly */
20
+ padding: 0 20px;
21
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
22
+ z-index: 1000;
23
+ box-sizing: border-box;
24
+ font-family: sans-serif;
25
+ font-size: 13px;
26
+ }
27
+
28
+ .control-group {
29
+ display: flex;
30
+ flex-direction: column; /* Stack label over slider */
31
+ justify-content: center;
32
+ min-width: 150px;
33
+ }
34
+
35
+ .slider-header {
36
+ display: flex;
37
+ justify-content: space-between;
38
+ margin-bottom: 4px;
39
+ font-weight: bold;
40
+ }
41
+
42
+ .checkbox-label {
43
+ display: flex;
44
+ align-items: center; /* Centers the box with the text vertically */
45
+ gap: 8px; /* Adds consistent space between box and text */
46
+ font-weight: bold;
47
+ cursor: pointer;
48
+ white-space: nowrap;
49
+ height: 100%; /* Ensures it takes up full banner height if needed */
50
+ }
51
+
52
+ #reset-view {
53
+ padding: 6px 12px;
54
+ background: #f0f0f0;
55
+ border: 1px solid #ccc;
56
+ border-radius: 4px;
57
+ cursor: pointer;
58
+ transition: background 0.2s;
59
+ }
60
+
61
+ #reset-view:hover {
62
+ background: #e0e0e0;
63
+ }
64
+
65
+ .info-text {
66
+ font-size: 11px;
67
+ color: #888;
68
+ max-width: 240px;
69
+ line-height: 1.5;
70
+ text-align: center;
71
+ }
72
+
73
+ /* Adjust your Plotly container to make room for the banner */
74
+ #plot-container {
75
+ display: none; /* Hidden until data is loaded */
76
+ margin-top: 60px;
77
+ height: calc(100vh - 60px);
78
+ }
79
+ .slider-label { display: flex; justify-content: space-between; margin-bottom: 8px; font-weight: bold; }
80
+ input[type=range] { width: 100%; }
81
+ </style>
82
+ </head>
83
+ <body>
84
+
85
+ <div id="controls" class="top-banner">
86
+ <div class="control-group" style="max-width: 300px; flex-direction: row; align-items: stretch;">
87
+ <input type="file" id="file-selector" style="display: none;" onchange="updateFilename(this)">
88
+
89
+ <label for="file-selector" id="drop-zone"
90
+ style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 8px; border: 1px solid #ccc; border-radius: 4px 4px 4px 4px; background: white; cursor: pointer; color: #666; display: flex; align-items: center; overflow: hidden;">
91
+ <span id="file-name-display">Click to select or Drop CSV...</span>
92
+ </label>
93
+
94
+ <button class="btn" id="process-btn"
95
+ style="background: #007bff; color: white; border: 1px solid #007bff; border-radius: 4px 4px 4px 4px; cursor: pointer; white-space: nowrap; margin-left:6px;"
96
+ onclick="uploadAndProcess()">
97
+ Process File
98
+ </button>
99
+ </div>
100
+
101
+ <div class="control-group">
102
+ <label class="checkbox-label">
103
+ <input type="checkbox" id="toggle-heatmap"> Density Heatmaps
104
+ </label>
105
+ </div>
106
+
107
+ <div class="control-group">
108
+ <div class="slider-header">
109
+ <span>Trajectories:</span>
110
+ <span id="percent-val">2%</span>
111
+ </div>
112
+ <input type="range" id="percent" min="1" max="100" value="2">
113
+ </div>
114
+
115
+ <div class="control-group">
116
+ <div class="slider-header">
117
+ <span>Opacity:</span>
118
+ <span id="opacity-val">0.99</span>
119
+ </div>
120
+ <input type="range" id="opacity" min="0" max="0.99" step="0.01" value="0.99">
121
+ </div>
122
+
123
+ <div class="control-group">
124
+ <button id="reset-view">Reset View</button>
125
+ </div>
126
+
127
+ <div class="info-text">
128
+ L: Rotate | Scroll: Zoom | R: Pan <br>
129
+ <i>Trajectories colored by starting times</i>
130
+ </div>
131
+ </div>
132
+
133
+
134
+ <div id="plot-container"></div>
135
+
136
+ <script>
137
+
138
+ let allData = [];
139
+ let xMin, yMax, zMin;
140
+ let floorData, wallData, sideData;
141
+
142
+ function handleDrop(event) {
143
+ event.preventDefault();
144
+ const file = event.dataTransfer.files[0];
145
+ if (file) {
146
+ // Note: In local Chrome/Firefox, this usually grabs the filename.
147
+ // If the user drops from a local folder, it provides the name.
148
+ document.getElementById('path-input').value = file.name;
149
+ }
150
+
151
+ }
152
+
153
+ function updateFilename(input) {
154
+ const nameDisplay = document.getElementById('file-name-display');
155
+ if (input.files.length > 0) {
156
+ nameDisplay.innerText = input.files[0].name;
157
+ nameDisplay.style.color = "#333";
158
+ }
159
+ }
160
+
161
+ async function uploadAndProcess() {
162
+ // 1. Get the file from a standard file input
163
+ // <input type="file" id="file-selector">
164
+ const fileElement = document.getElementById('file-selector');
165
+ const file = fileElement.files[0];
166
+
167
+ if (!file) { alert("Please select a file first"); return; }
168
+
169
+ const btn = document.getElementById('process-btn');
170
+ btn.innerText = "Processing...";
171
+ btn.style.background = "#6c757d"; // Change to grey
172
+ btn.style.pointerEvents = "none"; // Prevent double-clicking
173
+
174
+ try {
175
+ // 2. Send the raw file to the backend
176
+ const response = await fetch('/process-file', {
177
+ method: 'POST',
178
+ body: file // Sending the blob directly
179
+ });
180
+
181
+ const data = await response.json();
182
+
183
+ if (data.error) {
184
+ alert("Error: " + data.error);
185
+ } else {
186
+ allData = data.trajectories;
187
+
188
+ // Re-flatten coordinate arrays for grid calculations
189
+ const allX = allData.flatMap(t => t.x);
190
+ const allY = allData.flatMap(t => t.y);
191
+ const allZ = allData.flatMap(t => t.z);
192
+
193
+ // Define the boundaries of your "box"
194
+ xMin = allX.reduce((a, b) => Math.min(a, b), Infinity);
195
+ yMax = allY.reduce((a, b) => Math.max(a, b), -Infinity);
196
+ zMin = allZ.reduce((a, b) => Math.min(a, b), Infinity);
197
+
198
+ floorData = computeDensityGrid(allX, allY);
199
+ wallData = computeDensityGrid(allX, allZ);
200
+ sideData = computeDensityGrid(allY, allZ);
201
+
202
+ // 6. Trigger UI
203
+ document.getElementById('plot-container').style.display = 'block';
204
+ // updatePlot(document.getElementById('percent').value);
205
+ //update slider to 2%
206
+ document.getElementById('percent').value = 2;
207
+ percentVal.innerText = "2%";
208
+ updatePlot(2);
209
+ console.log("Processed tracks:", allData.length);
210
+ }
211
+ } catch (err) {
212
+ console.error(err);
213
+ alert("Upload failed. Check file size.");
214
+ } finally {
215
+ btn.innerText = "Process File";
216
+ btn.style.background = "#3498db";
217
+ btn.style.pointerEvents = "auto"; // Re-enable button
218
+ }
219
+ }
220
+
221
+ // async function sendPathToJulia() {
222
+ // const path = document.getElementById('path-input').value;
223
+ // const btn = document.getElementById('process-btn');
224
+
225
+ // if (!path) {
226
+ // alert("Please provide a file path.");
227
+ // return;
228
+ // }
229
+
230
+ // btn.innerText = "Processing...";
231
+ // btn.style.background = "#6c757d"; // Change to grey
232
+ // btn.style.pointerEvents = "none"; // Prevent double-clicking
233
+
234
+ // try {
235
+ // const response = await fetch('http://localhost:8080/process-path', {
236
+ // method: 'POST',
237
+ // headers: { 'Content-Type': 'application/json' },
238
+ // body: JSON.stringify({ path: path })
239
+ // });
240
+
241
+ // const data = await response.json();
242
+
243
+ // if (data.error) {
244
+ // alert("Julia Error: " + data.error);
245
+ // } else {
246
+ // console.log("Data received:", data);
247
+ // allData = data.trajectories;
248
+
249
+ // // Re-flatten coordinate arrays for grid calculations
250
+ // const allX = allData.flatMap(t => t.x);
251
+ // const allY = allData.flatMap(t => t.y);
252
+ // const allZ = allData.flatMap(t => t.z);
253
+
254
+ // // Define the boundaries of your "box"
255
+ // xMin = allX.reduce((a, b) => Math.min(a, b), Infinity);
256
+ // yMax = allY.reduce((a, b) => Math.max(a, b), -Infinity);
257
+ // zMin = allZ.reduce((a, b) => Math.min(a, b), Infinity);
258
+
259
+ // floorData = computeDensityGrid(allX, allY);
260
+ // wallData = computeDensityGrid(allX, allZ);
261
+ // sideData = computeDensityGrid(allY, allZ);
262
+
263
+ // // 6. Trigger UI
264
+ // document.getElementById('plot-container').style.display = 'block';
265
+ // // updatePlot(document.getElementById('percent').value);
266
+ // //update slider to 2%
267
+ // document.getElementById('percent').value = 2;
268
+ // percentVal.innerText = "2%";
269
+ // updatePlot(2);
270
+ // console.log("Processed tracks:", allData.length);
271
+
272
+ // }
273
+ // } catch (err) {
274
+ // alert("Could not connect to Julia server. Is server.jl running?");
275
+ // console.error(err);
276
+ // } finally {
277
+ // btn.innerText = "Process File";
278
+ // btn.style.background = "#3498db";
279
+ // btn.style.pointerEvents = "auto"; // Re-enable button
280
+ // }
281
+ // }
282
+
283
+ // Use the variable name you defined in your Julia export
284
+
285
+ const plotDiv = document.getElementById('plot-container');
286
+ const slider = document.getElementById('percent');
287
+ const percentVal = document.getElementById('percent-val');
288
+ const opacitySlider = document.getElementById('opacity');
289
+ const opacityVal = document.getElementById('opacity-val');
290
+
291
+ function computeDensityGrid(allX, allY, dX = 0.2) {
292
+ // 1. Define the grid boundaries
293
+ const xMin = allX.reduce((a, b) => Math.min(a, b), Infinity);
294
+ const xMax = allX.reduce((a, b) => Math.max(a, b), -Infinity);
295
+ const yMin = allY.reduce((a, b) => Math.min(a, b), Infinity);
296
+ const yMax = allY.reduce((a, b) => Math.max(a, b), -Infinity);
297
+
298
+ // 2. Calculate number of bins based on fixed dX
299
+ // We use Math.ceil to ensure we cover the entire range
300
+ const xBins = Math.ceil((xMax - xMin) / dX) + 1;
301
+ const yBins = Math.ceil((yMax - yMin) / dX) + 1;
302
+
303
+ // 3. Create 1D axis arrays for Plotly
304
+ // These represent the "ticks" on your floor/wall
305
+ const xRange = Array.from({length: xBins}, (_, i) => xMin + (i * dX));
306
+ const yRange = Array.from({length: yBins}, (_, i) => yMin + (i * dX));
307
+
308
+ // 4. Initialize 2D density grid with zeros [rows][columns]
309
+ // Plotly Surface expects z[yIndex][xIndex]
310
+ let density = Array.from({ length: yBins }, () => Array(xBins).fill(0));
311
+
312
+ // 5. Populate the grid (Binning)
313
+ for (let i = 0; i < allX.length; i++) {
314
+ // Calculate which bin the point falls into
315
+ const xIdx = Math.floor((allX[i] - xMin) / dX);
316
+ const yIdx = Math.floor((allY[i] - yMin) / dX);
317
+
318
+ // Safety check to ensure indices stay within bounds
319
+ if (xIdx >= 0 && xIdx < xBins && yIdx >= 0 && yIdx < yBins) {
320
+ density[yIdx][xIdx]++;
321
+ }
322
+ }
323
+
324
+ return { x: xRange, y: yRange, z: density };
325
+ }
326
+
327
+
328
+
329
+ let currentOpacity = 0.99;
330
+ let heatmapOpacity = 0.0;
331
+
332
+ function updatePlot(percent) {
333
+
334
+ if (!allData || allData.length === 0) return;
335
+
336
+ const plotDiv = document.getElementById('plot-container');
337
+
338
+ // 1. Capture the CURRENT camera state
339
+ let currentCamera = null;
340
+ if (plotDiv && plotDiv.layout && plotDiv.layout.scene) {
341
+ currentCamera = plotDiv.layout.scene.camera;
342
+ }
343
+
344
+ // 1. Calculate how many trajectories to show
345
+ const totalToDisplay = Math.floor(allData.length * (percent / 100));
346
+ const subset = allData.slice(0, totalToDisplay);
347
+
348
+ // console.log("X range:", floorData.x[0], "to", floorData.x[floorData.x.length-1]);
349
+ // console.log("Y range:", floorData.y[0], "to", floorData.y[floorData.y.length-1]);
350
+
351
+
352
+ // 2. Map data to Plotly traces
353
+ const traces = subset.map(t => ({
354
+ type: 'scatter3d',
355
+ mode: 'lines',
356
+ x: t.x,
357
+ y: t.y,
358
+ z: t.z,
359
+ line: {
360
+ width: 2,
361
+ // color: viridis(t.start_time / 3600) // Color by start time (assuming in seconds, converting to hours)
362
+ // color:'#2c3e50'
363
+ color: Array(t.x.length).fill(t.start_time),
364
+ colorscale: 'YlGnBu',
365
+ cmin: 0,
366
+ cmax: 3600, // Assuming max start time is 60 minutes (3600 seconds)
367
+ },
368
+ opacity: currentOpacity, // Low opacity helps see the "void" density
369
+ hoverinfo: 'none' // Improves performance for 10k lines
370
+ }));
371
+
372
+ const floorSurface = {
373
+ type: 'surface',
374
+ x: floorData.x,
375
+ y: floorData.y,
376
+ z: floorData.y.map(() => floorData.x.map(() => zMin - 0.1)), // Constant Z
377
+ surfacecolor: floorData.z,
378
+ colorscale: 'Portland',
379
+ opacity: heatmapOpacity,
380
+ showscale: false,
381
+ hoverinfo: 'skip',
382
+ contours: {
383
+ x: { show: false },
384
+ y: { show: false },
385
+ z: { show: false }
386
+ }
387
+
388
+ };
389
+
390
+ const wallSurface = {
391
+ type: 'surface',
392
+ // X-matrix: Create a row for every Z-bin
393
+ x: wallData.y.map(() => wallData.x),
394
+
395
+ // Y-matrix: Every single point in the grid is at the same 'yMax' (the wall)
396
+ y: wallData.z.map(row => row.map(() => yMax + 0.2)),
397
+
398
+ // Z-matrix: Create a column for every X-bin
399
+ z: wallData.y.map(zVal => Array(wallData.x.length).fill(zVal)),
400
+
401
+ surfacecolor: wallData.z,
402
+ colorscale: 'Portland',
403
+ opacity: heatmapOpacity,
404
+ showscale: false,
405
+ hoverinfo: 'skip',
406
+ contours: { x: {show: false}, y: {show: false}, z: {show: false} }
407
+ };
408
+
409
+ const sideSurface = {
410
+ type: 'surface',
411
+ // X-matrix: Every single point in the grid is at the same 'xMin' (the side wall)
412
+ x: sideData.z.map(row => row.map(() => xMin - 0.1)),
413
+
414
+ // Y-matrix: Create a row for every Z-bin
415
+ y: sideData.y.map(() => sideData.x),
416
+
417
+ // Z-matrix: Create a column for every Y-bin
418
+ z: sideData.y.map(zVal => Array(sideData.x.length).fill(zVal)),
419
+
420
+ surfacecolor: sideData.z,
421
+ colorscale: 'Portland',
422
+ opacity: heatmapOpacity,
423
+ showscale: false,
424
+ hoverinfo: 'skip',
425
+ contours: { x: {show: false}, y: {show: false}, z: {show: false} }
426
+ };
427
+
428
+ // 3. Define Layout (Crucial for seeing the exclusion zone)
429
+ const layout = {
430
+ scene: {
431
+ camera: currentCamera || {
432
+ eye: {x: 1.25, y: 1.25, z: 1.25}
433
+ },
434
+ xaxis: { title: 'X (m)', backgroundcolor: "#f8f9fa", showbackground: true, showspikes: false, showgrid: true, zeroline: false, gridcolor: '#ffffff', gridwidth: 2 },
435
+ yaxis: { title: 'Y (m)', backgroundcolor: "#f8f9fa", showbackground: true, showspikes: false, showgrid: true, zeroline: false, gridcolor: '#ffffff', gridwidth: 2 },
436
+ zaxis: { title: 'Z (m)', backgroundcolor: "#f8f9fa", showbackground: true, showspikes: false, showgrid: true, zeroline: false, gridcolor: '#ffffff', gridwidth: 2 },
437
+ aspectmode: 'data' // Ensures 1:1:1 spatial scale
438
+
439
+ },
440
+ margin: { l: 0, r: 0, b: 0, t: 0 },
441
+ showlegend: false,
442
+ uirevision: 'constant-state-key' // Preserve camera view on updates
443
+ };
444
+
445
+ const config = {
446
+ responsive: true,
447
+ displaylogo: false
448
+ };
449
+
450
+ const dataToPlot = [ floorSurface, wallSurface, sideSurface, ...traces ];
451
+
452
+ Plotly.react(plotDiv, dataToPlot, layout, config);
453
+ }
454
+
455
+
456
+ // Event Listeners
457
+ slider.oninput = function() {
458
+ percentVal.innerText = this.value + "%";
459
+ };
460
+
461
+ slider.onchange = function() {
462
+ updatePlot(this.value);
463
+ };
464
+
465
+ opacitySlider.oninput = function() {
466
+ currentOpacity = parseFloat(this.value);
467
+ opacityVal.innerText = currentOpacity;
468
+ // Trigger a re-render with the new opacity
469
+ updatePlot(document.getElementById('percent').value);
470
+ };
471
+
472
+ // 3. Reset View Listener
473
+ document.getElementById('reset-view').onclick = function() {
474
+ Plotly.relayout('plot-container', {
475
+ 'scene.camera': {
476
+ eye: {x: 1.25, y: 1.25, z: 1.25}, // Default Plotly camera position
477
+ center: {x: 0, y: 0, z: 0},
478
+ up: {x: 0, y: 0, z: 1}
479
+ }
480
+ });
481
+ };
482
+
483
+ document.getElementById('toggle-heatmap').onchange = function() {
484
+ showHeatmaps = this.checked;
485
+ // if checked set heatmapOpacity to 0.6 else 0.0
486
+ heatmapOpacity = showHeatmaps ? 0.6 : 0.0;
487
+ // Get the current trajectory percentage to maintain state
488
+ const currentPercent = document.getElementById('percent').value;
489
+ updatePlot(currentPercent);
490
+ };
491
+
492
+
493
+ // Initial render
494
+ window.onload = () => updatePlot(2);
495
+
496
+ </script>
497
+ </body>
498
+ </html>
server.jl ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Oxygen, HTTP, JSON3, CSV, DataFrames, Dates, Random, Statistics, Interpolations
2
+
3
+ parse_date(d::AbstractString) = DateTime(d, dateformat"yyyy-mm-dd HH:MM:SS.ssss")
4
+
5
+ function export_clean_traces(file;
6
+ min_track_length = 1.0, min_start_time = 300.0, max_start_time=Inf,
7
+ wall_buffer_x = 0.0 , wall_buffer_y = 0.0, wall_buffer_z = 0.0
8
+ )
9
+
10
+ data = CSV.read(file, DataFrame)
11
+ df = convert(DataFrame,data)
12
+ groups = groupby(df, 1)
13
+
14
+ starting_times, clean_traces = save_data(groups, file;
15
+ min_track_length=min_track_length, min_start_time=min_start_time, max_start_time=max_start_time,
16
+ wall_buffer_x=wall_buffer_x, wall_buffer_y=wall_buffer_y, wall_buffer_z=wall_buffer_z
17
+ )
18
+
19
+ return starting_times, clean_traces
20
+
21
+ end
22
+
23
+
24
+ function save_data(groups, file;
25
+ min_track_length = 1.0, min_start_time = 300.0, max_start_time = Inf,
26
+ wall_buffer_x = 0.0 , wall_buffer_y = 0.0, wall_buffer_z = 0.0
27
+ )
28
+ # first, compute positions of wall
29
+ min_x = Vector{Float64}()
30
+ max_x = Vector{Float64}()
31
+ min_y = Vector{Float64}()
32
+ max_y = Vector{Float64}()
33
+ min_z = Vector{Float64}()
34
+ max_z = Vector{Float64}()
35
+ for g in groups
36
+ push!(min_x,minimum(g[:,3]))
37
+ push!(max_x,maximum(g[:,3]))
38
+ push!(min_y,minimum(g[:,4]))
39
+ push!(max_y,maximum(g[:,4]))
40
+ push!(min_z,minimum(g[:,5]))
41
+ push!(max_z,maximum(g[:,5]))
42
+ end
43
+
44
+ wall_robust = [(quantile(min_x,0.01),quantile(max_x,0.99)),(quantile(min_y,0.01),quantile(max_y,0.99)),(quantile(min_z,0.01),quantile(max_z,0.99))]
45
+ println("Wall x position: ", wall_robust[1])
46
+ println("Wall y position: ", wall_robust[2])
47
+ println("Wall z position: ", wall_robust[3])
48
+
49
+ # Filter tracks based on time requirements
50
+ experiment_start_time = parse_date(groups[1].datetime[1][1:end-3])
51
+ long_traces = []
52
+ for g in groups
53
+ track_end_time = parse_date(g.datetime[end][1:end-3])
54
+ track_start_time = parse_date(g.datetime[1][1:end-3])
55
+ if Dates.value(track_end_time - track_start_time)/1000 > min_track_length && Dates.value(track_start_time-experiment_start_time)/1000 > min_start_time && Dates.value(track_start_time-experiment_start_time)/1000 < max_start_time
56
+ push!(long_traces,g)
57
+ end
58
+ end
59
+
60
+ # Filter tracks based on position from wall
61
+ final_traces = []
62
+ times = []
63
+ starting_times = []
64
+ for g in long_traces
65
+ if all(g[:,3] .> wall_robust[1][1]+wall_buffer_x) && all(g[:,3] .< wall_robust[1][2]-wall_buffer_x) && all(g[:,4] .> wall_robust[2][1]+wall_buffer_y) && all(g[:,4] .< wall_robust[2][2]-wall_buffer_y) && all(g[:,5] .> wall_robust[3][1]+wall_buffer_z) && all(g[:,5] .< wall_robust[3][2]-wall_buffer_z)
66
+ push!(final_traces,g)
67
+ tmp = []
68
+ for i in 1:length(g.datetime)
69
+ push!(tmp,Dates.value(parse_date(g.datetime[i][1:end-3])-parse_date(g.datetime[1][1:end-3]))/1000)
70
+ end
71
+ push!(starting_times,Dates.value(parse_date(g.datetime[1][1:end-3])-experiment_start_time)/1000)
72
+ push!(times,tmp)
73
+ end
74
+ end
75
+
76
+
77
+ clean_traces = Vector{Matrix{Float64}}()
78
+ for g in 1:length(final_traces)
79
+ if sum(diff(times[g]) .<= 0.0) == 0
80
+ # ts = LinRange(0.0,times[g][end],Int(round(times[g][end]*100)+1))
81
+ ts = collect(0.0:0.01:times[g][end]) # fix dt to 0.01 seconds
82
+ interp_linear_xs = linear_interpolation(times[g], final_traces[g][:,3])
83
+ interp_linear_ys = linear_interpolation(times[g], final_traces[g][:,4])
84
+ interp_linear_zs = linear_interpolation(times[g], final_traces[g][:,5])
85
+
86
+ temp = zeros(length(ts),5)
87
+ temp[:,1] = interp_linear_xs.(ts) / 100 # convert cm to m
88
+ temp[:,2] = interp_linear_ys.(ts) / 100
89
+ temp[:,3] = interp_linear_zs.(ts) / 100
90
+ temp[:,4] = ts
91
+
92
+ for j in 1:length(ts)
93
+ if round(ts[j],digits=2) in times[g]
94
+ temp[j,5] = 1.0
95
+ else
96
+ temp[j,5] = 0.0
97
+ end
98
+ end
99
+ push!(clean_traces,temp)
100
+ else
101
+ println("Skipping track ",g)
102
+ deleteat!(starting_times, g)
103
+ end
104
+ end
105
+
106
+ return starting_times, clean_traces
107
+
108
+ end
109
+
110
+ function unzip(collection)
111
+ firsts = [x[1] for x in collection]
112
+ seconds = [x[2] for x in collection]
113
+ return firsts, seconds
114
+ end
115
+
116
+ # Re-use your existing processing logic here
117
+ function process_big_csv(filepath)
118
+ start_times, traces = export_clean_traces(filepath;
119
+ min_track_length = 1.0, min_start_time = 0.0, max_start_time=Inf,
120
+ )
121
+ combined = collect(zip(start_times, traces))
122
+ shuffle!(combined)
123
+ # Separate the shuffled arrays
124
+ start_times, traces = unzip(combined);
125
+ payload = Dict("trajectories"=> [Dict("start_time" => start_times[i],
126
+ "x" => Float32.(traces[i][:,1]),
127
+ "y" => Float32.(traces[i][:,3]),
128
+ "z" => Float32.(traces[i][:,2]),
129
+ ) for i in 1:length(traces)]
130
+ )
131
+ return payload # A dictionary/struct
132
+ end
133
+
134
+ @get "/" function()
135
+ return file("index.html")
136
+ end
137
+
138
+ @post "/process-path" function(req)
139
+ # Julia receives the file path or raw bytes
140
+ # Processes it at 100% precision
141
+ data = JSON3.read(String(req.body))
142
+ filepath = data.path
143
+ data = process_big_csv(filepath)
144
+ return data # Automatically converted to JSON
145
+ end
146
+
147
+ @post "/process-file" function(req)
148
+ try
149
+ # req.body contains the raw bytes of the uploaded 600MB file
150
+ # We wrap it in an IOBuffer so CSV.read can process it in RAM
151
+ data = process_big_csv(IOBuffer(req.body))
152
+
153
+ # Return results (Oxygen handles JSON conversion)
154
+ return data
155
+ catch e
156
+ return HTTP.Response(500, JSON3.write(Dict("error" => string(e))))
157
+ end
158
+ end
159
+
160
+ staticfiles(".")
161
+ serve(host="0.0.0.0", port=7860)