cnhkmcp 2.1.2__py3-none-any.whl → 2.1.3__py3-none-any.whl
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.
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
- cnhkmcp-2.1.3.dist-info/RECORD +6 -0
- cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
- cnhkmcp/__init__.py +0 -125
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/README.md +0 -38
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/ace.log +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/config.json +0 -6
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/ace_lib.py +0 -1510
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_datasets.py +0 -157
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_documentation.py +0 -132
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_operators.py +0 -99
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/helpful_functions.py +0 -180
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.ico +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.png +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/test.txt +0 -1
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +0 -576
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/process_knowledge_base.py +0 -281
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/rag_engine.py +0 -408
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/requirements.txt +0 -7
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/run.bat +0 -3
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -265
- cnhkmcp/untracked/APP/.gitignore +0 -32
- cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
- cnhkmcp/untracked/APP/README.md +0 -309
- cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
- cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
- cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_/321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/277/321/207/320/253/342/224/244/321/206/320/236/320/265/321/210/342/225/234/342/225/234/321/205/320/225/320/265Machine_lib.json +0 -22
- cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
- cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
- cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
- cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
- cnhkmcp/untracked/APP/ace.log +0 -69
- cnhkmcp/untracked/APP/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
- cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
- cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
- cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
- cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
- cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
- cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
- cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
- cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
- cnhkmcp/untracked/APP/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
- cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
- cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/mirror_config.txt +0 -20
- cnhkmcp/untracked/APP/operaters.csv +0 -129
- cnhkmcp/untracked/APP/requirements.txt +0 -53
- cnhkmcp/untracked/APP/run_app.bat +0 -28
- cnhkmcp/untracked/APP/run_app.sh +0 -34
- cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
- cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
- cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
- cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
- cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
- cnhkmcp/untracked/APP/static/brain.js +0 -589
- cnhkmcp/untracked/APP/static/decoder.js +0 -1540
- cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
- cnhkmcp/untracked/APP/static/idea_house.js +0 -937
- cnhkmcp/untracked/APP/static/inspiration.js +0 -465
- cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
- cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
- cnhkmcp/untracked/APP/static/script.js +0 -3082
- cnhkmcp/untracked/APP/static/simulator.js +0 -597
- cnhkmcp/untracked/APP/static/styles.css +0 -3127
- cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
- cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
- cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
- cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
- cnhkmcp/untracked/APP/templates/index.html +0 -932
- cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
- cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
- cnhkmcp/untracked/APP/templates/simulator.html +0 -343
- cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
- cnhkmcp/untracked/APP/usage.md +0 -351
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/brain_alpha_inspector.py +0 -712
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -2456
- cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
- cnhkmcp/untracked/arxiv_api.py +0 -229
- cnhkmcp/untracked/forum_functions.py +0 -998
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +0 -407
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/platform_functions.py +0 -2415
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/user_config.json +0 -31
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/210/320/276/320/271AI/321/210/320/277/342/225/227/321/210/342/224/220/320/251/321/204/342/225/225/320/272/321/206/320/246/320/227/321/206/320/261/320/263/321/206/320/255/320/265/321/205/320/275/320/266/321/204/342/225/235/320/252/321/204/342/225/225/320/233/321/210/342/225/234/342/225/234/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270.md +0 -101
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
- cnhkmcp/untracked/platform_functions.py +0 -2886
- cnhkmcp/untracked/sample_mcp_config.json +0 -11
- cnhkmcp/untracked/user_config.json +0 -31
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/222/321/210/320/220/320/223/321/206/320/246/320/227/321/206/320/261/320/263_BRAIN_Alpha_Test_Requirements_and_Tips.md +0 -202
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Alpha_explaination_workflow.md +0 -56
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_6_Tips_Datafield_Exploration_Guide.md +0 -194
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_Alpha_Improvement_Workflow.md +0 -101
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Dataset_Exploration_Expert_Manual.md +0 -436
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_daily_report_workflow.md +0 -128
- cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
- cnhkmcp-2.1.2.dist-info/RECORD +0 -111
- cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,597 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BRAIN Alpha Simulator - Frontend JavaScript
|
|
3
|
-
* Handles the user interface for the simulator with parameter input and log monitoring
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
let currentLogFile = null;
|
|
7
|
-
let logPollingInterval = null;
|
|
8
|
-
let isSimulationRunning = false;
|
|
9
|
-
let simulationAbortController = null;
|
|
10
|
-
let userSelectedLogFile = false; // Track if user manually selected a log file
|
|
11
|
-
|
|
12
|
-
// Initialize page when DOM is loaded
|
|
13
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
14
|
-
refreshLogFiles();
|
|
15
|
-
setupFormValidation();
|
|
16
|
-
loadSimulatorDefaults();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Setup form validation and change handlers
|
|
21
|
-
*/
|
|
22
|
-
function setupFormValidation() {
|
|
23
|
-
const startPosition = document.getElementById('startPosition');
|
|
24
|
-
const randomShuffle = document.getElementById('randomShuffle');
|
|
25
|
-
const jsonFile = document.getElementById('jsonFile');
|
|
26
|
-
|
|
27
|
-
// Show warning when file might be overwritten
|
|
28
|
-
function checkOverwriteWarning() {
|
|
29
|
-
const warning = document.getElementById('overwriteWarning');
|
|
30
|
-
const showWarning = parseInt(startPosition.value) > 0 || randomShuffle.checked;
|
|
31
|
-
warning.style.display = showWarning ? 'block' : 'none';
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
startPosition.addEventListener('input', checkOverwriteWarning);
|
|
35
|
-
randomShuffle.addEventListener('change', checkOverwriteWarning);
|
|
36
|
-
|
|
37
|
-
// Handle JSON file selection
|
|
38
|
-
jsonFile.addEventListener('change', function(e) {
|
|
39
|
-
const file = e.target.files[0];
|
|
40
|
-
const info = document.getElementById('jsonFileInfo');
|
|
41
|
-
|
|
42
|
-
if (file) {
|
|
43
|
-
info.innerHTML = `
|
|
44
|
-
<strong>Selected:</strong> ${file.name}<br>
|
|
45
|
-
<strong>Size:</strong> ${(file.size / 1024).toFixed(1)} KB<br>
|
|
46
|
-
<strong>Modified:</strong> ${new Date(file.lastModified).toLocaleString()}
|
|
47
|
-
`;
|
|
48
|
-
info.style.display = 'block';
|
|
49
|
-
|
|
50
|
-
// Try to read and validate JSON
|
|
51
|
-
const reader = new FileReader();
|
|
52
|
-
reader.onload = function(e) {
|
|
53
|
-
try {
|
|
54
|
-
const data = JSON.parse(e.target.result);
|
|
55
|
-
if (Array.isArray(data)) {
|
|
56
|
-
const maxStart = Math.max(0, data.length - 1);
|
|
57
|
-
startPosition.max = maxStart;
|
|
58
|
-
info.innerHTML += `<br><strong>Expressions:</strong> ${data.length} found`;
|
|
59
|
-
} else {
|
|
60
|
-
info.innerHTML += '<br><span style="color: #721c24;">⚠️ Warning: Not an array format</span>';
|
|
61
|
-
}
|
|
62
|
-
} catch (err) {
|
|
63
|
-
info.innerHTML += '<br><span style="color: #721c24;">❌ Invalid JSON format</span>';
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
reader.readAsText(file);
|
|
67
|
-
} else {
|
|
68
|
-
info.style.display = 'none';
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Load default values from localStorage if available
|
|
75
|
-
*/
|
|
76
|
-
function loadSimulatorDefaults() {
|
|
77
|
-
const username = localStorage.getItem('simulator_username');
|
|
78
|
-
if (username) {
|
|
79
|
-
document.getElementById('username').value = username;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const concurrentCount = localStorage.getItem('simulator_concurrent');
|
|
83
|
-
if (concurrentCount) {
|
|
84
|
-
document.getElementById('concurrentCount').value = concurrentCount;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Save current form values to localStorage
|
|
90
|
-
*/
|
|
91
|
-
function saveSimulatorDefaults() {
|
|
92
|
-
localStorage.setItem('simulator_username', document.getElementById('username').value);
|
|
93
|
-
localStorage.setItem('simulator_concurrent', document.getElementById('concurrentCount').value);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Toggle password visibility
|
|
98
|
-
*/
|
|
99
|
-
function togglePassword() {
|
|
100
|
-
const passwordInput = document.getElementById('password');
|
|
101
|
-
const isPassword = passwordInput.type === 'password';
|
|
102
|
-
passwordInput.type = isPassword ? 'text' : 'password';
|
|
103
|
-
|
|
104
|
-
const toggleBtn = document.querySelector('.password-toggle');
|
|
105
|
-
toggleBtn.textContent = isPassword ? '🙈' : '👁️';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Toggle multi-simulation options
|
|
110
|
-
*/
|
|
111
|
-
function toggleMultiSimOptions() {
|
|
112
|
-
const checkbox = document.getElementById('useMultiSim');
|
|
113
|
-
const options = document.getElementById('multiSimOptions');
|
|
114
|
-
options.style.display = checkbox.checked ? 'block' : 'none';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Refresh available log files
|
|
119
|
-
*/
|
|
120
|
-
async function refreshLogFiles() {
|
|
121
|
-
try {
|
|
122
|
-
const response = await fetch('/api/simulator/logs');
|
|
123
|
-
const data = await response.json();
|
|
124
|
-
|
|
125
|
-
const selector = document.getElementById('logSelector');
|
|
126
|
-
selector.innerHTML = '<option value="">Select a log file...</option>';
|
|
127
|
-
|
|
128
|
-
if (data.logs && data.logs.length > 0) {
|
|
129
|
-
data.logs.forEach(log => {
|
|
130
|
-
const option = document.createElement('option');
|
|
131
|
-
option.value = log.filename;
|
|
132
|
-
option.textContent = `${log.filename} (${log.size}, ${log.modified})`;
|
|
133
|
-
selector.appendChild(option);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Auto-select the latest log file only if user hasn't manually selected one
|
|
137
|
-
if (data.latest && !userSelectedLogFile) {
|
|
138
|
-
selector.value = data.latest;
|
|
139
|
-
currentLogFile = data.latest;
|
|
140
|
-
// Update UI to show auto-monitoring
|
|
141
|
-
document.getElementById('currentLogFile').innerHTML = `
|
|
142
|
-
<strong>🔄 Auto-monitoring:</strong> ${data.latest}<br>
|
|
143
|
-
<small>Latest log file will be automatically selected when new ones appear.</small>
|
|
144
|
-
`;
|
|
145
|
-
loadSelectedLog();
|
|
146
|
-
// Ensure polling is active for auto-selected files too
|
|
147
|
-
ensureLogPollingActive();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} catch (error) {
|
|
151
|
-
console.error('Error refreshing log files:', error);
|
|
152
|
-
updateStatus('Error loading log files', 'error');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Ensure polling continues after refresh
|
|
156
|
-
ensureLogPollingActive();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Load selected log file content
|
|
161
|
-
*/
|
|
162
|
-
async function loadSelectedLog() {
|
|
163
|
-
const selector = document.getElementById('logSelector');
|
|
164
|
-
const selectedLog = selector.value;
|
|
165
|
-
|
|
166
|
-
if (!selectedLog) {
|
|
167
|
-
// Reset if user deselects
|
|
168
|
-
userSelectedLogFile = false;
|
|
169
|
-
currentLogFile = null;
|
|
170
|
-
document.getElementById('currentLogFile').innerHTML = `
|
|
171
|
-
<strong>🔄 Auto-mode enabled:</strong> Will monitor latest log when available<br>
|
|
172
|
-
<small>System will automatically select and monitor the newest log file.</small>
|
|
173
|
-
`;
|
|
174
|
-
// Try to auto-select latest again
|
|
175
|
-
refreshLogFiles();
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Mark that user has manually selected a log file
|
|
180
|
-
userSelectedLogFile = true;
|
|
181
|
-
currentLogFile = selectedLog;
|
|
182
|
-
|
|
183
|
-
// Start polling if not already running to monitor the selected file
|
|
184
|
-
ensureLogPollingActive();
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const response = await fetch(`/api/simulator/logs/${encodeURIComponent(selectedLog)}`);
|
|
188
|
-
const data = await response.json();
|
|
189
|
-
|
|
190
|
-
if (data.content !== undefined) {
|
|
191
|
-
const logViewer = document.getElementById('logViewer');
|
|
192
|
-
// Use innerHTML to properly handle character encoding for Chinese text
|
|
193
|
-
const content = data.content || 'Log file is empty.';
|
|
194
|
-
logViewer.textContent = content;
|
|
195
|
-
logViewer.scrollTop = logViewer.scrollHeight;
|
|
196
|
-
|
|
197
|
-
// Only update status if user manually selected (not auto-selected)
|
|
198
|
-
if (userSelectedLogFile) {
|
|
199
|
-
document.getElementById('currentLogFile').innerHTML = `
|
|
200
|
-
<strong>📌 Manually selected:</strong> ${selectedLog}<br>
|
|
201
|
-
<small>Auto-switching to latest log disabled. Select "Select a log file..." to re-enable.</small>
|
|
202
|
-
`;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.error('Error loading log file:', error);
|
|
207
|
-
updateStatus('Error loading log content', 'error');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Test connection to BRAIN API
|
|
213
|
-
*/
|
|
214
|
-
async function testConnection() {
|
|
215
|
-
const username = document.getElementById('username').value;
|
|
216
|
-
const password = document.getElementById('password').value;
|
|
217
|
-
|
|
218
|
-
if (!username || !password) {
|
|
219
|
-
updateStatus('Please enter username and password first', 'error');
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const testBtn = document.getElementById('testBtn');
|
|
224
|
-
testBtn.disabled = true;
|
|
225
|
-
testBtn.textContent = '🔄 Testing...';
|
|
226
|
-
|
|
227
|
-
updateStatus('Testing BRAIN API connection...', 'running');
|
|
228
|
-
|
|
229
|
-
try {
|
|
230
|
-
const response = await fetch('/api/simulator/test-connection', {
|
|
231
|
-
method: 'POST',
|
|
232
|
-
headers: {
|
|
233
|
-
'Content-Type': 'application/json'
|
|
234
|
-
},
|
|
235
|
-
body: JSON.stringify({
|
|
236
|
-
username: username,
|
|
237
|
-
password: password
|
|
238
|
-
})
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const data = await response.json();
|
|
242
|
-
|
|
243
|
-
if (data.success) {
|
|
244
|
-
updateStatus('✅ Connection successful! Ready to run simulation.', 'success');
|
|
245
|
-
saveSimulatorDefaults();
|
|
246
|
-
} else {
|
|
247
|
-
updateStatus(`❌ Connection failed: ${data.error}`, 'error');
|
|
248
|
-
}
|
|
249
|
-
} catch (error) {
|
|
250
|
-
updateStatus(`❌ Connection error: ${error.message}`, 'error');
|
|
251
|
-
} finally {
|
|
252
|
-
testBtn.disabled = false;
|
|
253
|
-
testBtn.textContent = '🔗 Test Connection';
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Run the simulator with user parameters
|
|
259
|
-
*/
|
|
260
|
-
async function runSimulator() {
|
|
261
|
-
if (isSimulationRunning) {
|
|
262
|
-
updateStatus('Simulation is already running', 'error');
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Validate form
|
|
267
|
-
const form = document.getElementById('simulatorForm');
|
|
268
|
-
if (!form.checkValidity()) {
|
|
269
|
-
form.reportValidity();
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const jsonFile = document.getElementById('jsonFile').files[0];
|
|
274
|
-
if (!jsonFile) {
|
|
275
|
-
updateStatus('Please select a JSON file', 'error');
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Prepare form data
|
|
280
|
-
const formData = new FormData();
|
|
281
|
-
formData.append('jsonFile', jsonFile);
|
|
282
|
-
formData.append('username', document.getElementById('username').value);
|
|
283
|
-
formData.append('password', document.getElementById('password').value);
|
|
284
|
-
formData.append('startPosition', document.getElementById('startPosition').value);
|
|
285
|
-
formData.append('concurrentCount', document.getElementById('concurrentCount').value);
|
|
286
|
-
formData.append('randomShuffle', document.getElementById('randomShuffle').checked);
|
|
287
|
-
formData.append('useMultiSim', document.getElementById('useMultiSim').checked);
|
|
288
|
-
formData.append('alphaCountPerSlot', document.getElementById('alphaCountPerSlot').value);
|
|
289
|
-
|
|
290
|
-
// UI updates
|
|
291
|
-
isSimulationRunning = true;
|
|
292
|
-
const runBtn = document.getElementById('runSimulator');
|
|
293
|
-
const stopBtn = document.getElementById('stopBtn');
|
|
294
|
-
|
|
295
|
-
runBtn.disabled = true;
|
|
296
|
-
runBtn.textContent = '🔄 Running...';
|
|
297
|
-
stopBtn.style.display = 'inline-block';
|
|
298
|
-
|
|
299
|
-
updateStatus('Starting simulation...', 'running');
|
|
300
|
-
showProgress(true);
|
|
301
|
-
|
|
302
|
-
// Create abort controller for stopping simulation
|
|
303
|
-
simulationAbortController = new AbortController();
|
|
304
|
-
|
|
305
|
-
try {
|
|
306
|
-
saveSimulatorDefaults();
|
|
307
|
-
|
|
308
|
-
const response = await fetch('/api/simulator/run', {
|
|
309
|
-
method: 'POST',
|
|
310
|
-
body: formData,
|
|
311
|
-
signal: simulationAbortController.signal
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
const data = await response.json();
|
|
315
|
-
|
|
316
|
-
if (data.success) {
|
|
317
|
-
updateStatus('✅ Simulator launched in new terminal回测器启动成功! Check the terminal window for progress.请检查新唤起的python程序', 'success');
|
|
318
|
-
|
|
319
|
-
// Show launch information
|
|
320
|
-
if (data.parameters) {
|
|
321
|
-
showLaunchInfo(data.parameters);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Start monitoring log files more frequently since simulation is running
|
|
325
|
-
startLogPolling();
|
|
326
|
-
|
|
327
|
-
// Refresh log files to get the latest simulation log
|
|
328
|
-
setTimeout(() => {
|
|
329
|
-
refreshLogFiles();
|
|
330
|
-
}, 3000);
|
|
331
|
-
} else {
|
|
332
|
-
updateStatus(`❌ Failed to launch simulator: ${data.error}`, 'error');
|
|
333
|
-
}
|
|
334
|
-
} catch (error) {
|
|
335
|
-
if (error.name === 'AbortError') {
|
|
336
|
-
updateStatus('⏹️ Simulation stopped by user', 'idle');
|
|
337
|
-
} else {
|
|
338
|
-
updateStatus(`❌ Simulation error: ${error.message}`, 'error');
|
|
339
|
-
}
|
|
340
|
-
} finally {
|
|
341
|
-
isSimulationRunning = false;
|
|
342
|
-
runBtn.disabled = false;
|
|
343
|
-
runBtn.textContent = '🚀 Start Simulation';
|
|
344
|
-
stopBtn.style.display = 'none';
|
|
345
|
-
simulationAbortController = null;
|
|
346
|
-
showProgress(false);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Stop running simulation
|
|
352
|
-
*/
|
|
353
|
-
async function stopSimulation() {
|
|
354
|
-
if (simulationAbortController) {
|
|
355
|
-
simulationAbortController.abort();
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
try {
|
|
359
|
-
await fetch('/api/simulator/stop', { method: 'POST' });
|
|
360
|
-
} catch (error) {
|
|
361
|
-
console.error('Error stopping simulation:', error);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
updateStatus('Stopping simulation...', 'idle');
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Ensure log polling is active if we have a log file to monitor
|
|
369
|
-
*/
|
|
370
|
-
function ensureLogPollingActive() {
|
|
371
|
-
if (currentLogFile && !logPollingInterval) {
|
|
372
|
-
console.log('Starting log polling for file:', currentLogFile);
|
|
373
|
-
startLogPolling();
|
|
374
|
-
|
|
375
|
-
// Add visual indicator that polling is active
|
|
376
|
-
const currentLogFileDiv = document.getElementById('currentLogFile');
|
|
377
|
-
if (userSelectedLogFile) {
|
|
378
|
-
currentLogFileDiv.innerHTML = `
|
|
379
|
-
<strong>📌 Manually selected:</strong> ${currentLogFile} <span style="color: #28a745;">●</span><br>
|
|
380
|
-
<small>Auto-switching to latest log disabled. Select "Select a log file..." to re-enable.</small>
|
|
381
|
-
`;
|
|
382
|
-
} else {
|
|
383
|
-
currentLogFileDiv.innerHTML = `
|
|
384
|
-
<strong>🔄 Auto-monitoring:</strong> ${currentLogFile} <span style="color: #28a745;">●</span><br>
|
|
385
|
-
<small>Latest log file will be automatically selected when new ones appear.</small>
|
|
386
|
-
`;
|
|
387
|
-
}
|
|
388
|
-
} else if (currentLogFile && logPollingInterval) {
|
|
389
|
-
console.log('Log polling already active for:', currentLogFile);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Start polling for log updates
|
|
395
|
-
*/
|
|
396
|
-
function startLogPolling() {
|
|
397
|
-
if (logPollingInterval) {
|
|
398
|
-
clearInterval(logPollingInterval);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Start more frequent polling when simulation is running in terminal
|
|
402
|
-
logPollingInterval = setInterval(async () => {
|
|
403
|
-
try {
|
|
404
|
-
// Only refresh log file list if user hasn't manually selected a file
|
|
405
|
-
// This allows the system to detect new log files but won't interfere with user's choice
|
|
406
|
-
if (!userSelectedLogFile) {
|
|
407
|
-
await refreshLogFiles();
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Always refresh the content of the currently monitored log file
|
|
411
|
-
if (currentLogFile) {
|
|
412
|
-
console.log('Polling log file:', currentLogFile, 'User selected:', userSelectedLogFile);
|
|
413
|
-
const response = await fetch(`/api/simulator/logs/${encodeURIComponent(currentLogFile)}`);
|
|
414
|
-
const data = await response.json();
|
|
415
|
-
|
|
416
|
-
if (data.content !== undefined) {
|
|
417
|
-
const logViewer = document.getElementById('logViewer');
|
|
418
|
-
logViewer.textContent = data.content;
|
|
419
|
-
logViewer.scrollTop = logViewer.scrollHeight;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
} catch (error) {
|
|
423
|
-
console.error('Error polling log:', error);
|
|
424
|
-
}
|
|
425
|
-
}, 3000); // Poll every 3 seconds when running in terminal
|
|
426
|
-
|
|
427
|
-
// Auto-stop polling after 15 minutes to prevent excessive server load
|
|
428
|
-
setTimeout(() => {
|
|
429
|
-
if (logPollingInterval) {
|
|
430
|
-
clearInterval(logPollingInterval);
|
|
431
|
-
logPollingInterval = null;
|
|
432
|
-
console.log('Auto-stopped log polling after 15 minutes');
|
|
433
|
-
}
|
|
434
|
-
}, 900000); // 15 minutes
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Stop log polling
|
|
439
|
-
*/
|
|
440
|
-
function stopLogPolling() {
|
|
441
|
-
if (logPollingInterval) {
|
|
442
|
-
clearInterval(logPollingInterval);
|
|
443
|
-
logPollingInterval = null;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Update status indicator
|
|
449
|
-
*/
|
|
450
|
-
function updateStatus(message, type = 'idle') {
|
|
451
|
-
const statusEl = document.getElementById('simulatorStatus');
|
|
452
|
-
statusEl.textContent = message;
|
|
453
|
-
statusEl.className = `status-indicator status-${type}`;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Show/hide progress bar
|
|
458
|
-
*/
|
|
459
|
-
function showProgress(show) {
|
|
460
|
-
const progressDiv = document.getElementById('simulationProgress');
|
|
461
|
-
progressDiv.style.display = show ? 'block' : 'none';
|
|
462
|
-
|
|
463
|
-
if (!show) {
|
|
464
|
-
updateProgress(0, 0);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Update progress bar
|
|
470
|
-
*/
|
|
471
|
-
function updateProgress(current, total) {
|
|
472
|
-
const progressText = document.getElementById('progressText');
|
|
473
|
-
const progressBar = document.getElementById('progressBar');
|
|
474
|
-
|
|
475
|
-
progressText.textContent = `${current}/${total}`;
|
|
476
|
-
|
|
477
|
-
if (total > 0) {
|
|
478
|
-
const percentage = (current / total) * 100;
|
|
479
|
-
progressBar.style.width = `${percentage}%`;
|
|
480
|
-
} else {
|
|
481
|
-
progressBar.style.width = '0%';
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* Show launch information when simulator starts in terminal
|
|
487
|
-
*/
|
|
488
|
-
function showLaunchInfo(parameters) {
|
|
489
|
-
const resultsPanel = document.getElementById('resultsPanel');
|
|
490
|
-
const resultsDiv = document.getElementById('simulationResults');
|
|
491
|
-
|
|
492
|
-
let html = '<div class="launch-info">';
|
|
493
|
-
html += '<h4>🚀 Simulator Launched Successfully</h4>';
|
|
494
|
-
html += '<p>The simulator is running in a separate terminal window. You can monitor the progress there.</p>';
|
|
495
|
-
|
|
496
|
-
html += '<div class="parameters-summary">';
|
|
497
|
-
html += '<h5>📋 Configuration Summary:</h5>';
|
|
498
|
-
html += `<p><strong>Total Expressions:</strong> ${parameters.expressions_count}</p>`;
|
|
499
|
-
html += `<p><strong>Concurrent Simulations:</strong> ${parameters.concurrent_count}</p>`;
|
|
500
|
-
|
|
501
|
-
if (parameters.use_multi_sim) {
|
|
502
|
-
html += `<p><strong>Multi-Simulation Mode:</strong> Yes (${parameters.alpha_count_per_slot} alphas per slot)</p>`;
|
|
503
|
-
} else {
|
|
504
|
-
html += `<p><strong>Multi-Simulation Mode:</strong> No</p>`;
|
|
505
|
-
}
|
|
506
|
-
html += '</div>';
|
|
507
|
-
|
|
508
|
-
html += '<div class="monitoring-info" style="margin-top: 15px; padding: 10px; background: #e7f3ff; border-radius: 4px;">';
|
|
509
|
-
html += '<p><strong>💡 Monitoring Tips:</strong></p>';
|
|
510
|
-
html += '<ul style="margin: 5px 0; padding-left: 20px;">';
|
|
511
|
-
html += '<li>Watch the terminal window for real-time progress</li>';
|
|
512
|
-
html += '<li>Log files will be updated automatically below</li>';
|
|
513
|
-
html += '<li>Simulation results will appear in the terminal when complete</li>';
|
|
514
|
-
html += '<li>You can refresh log files manually using the refresh button</li>';
|
|
515
|
-
html += '</ul>';
|
|
516
|
-
html += '</div>';
|
|
517
|
-
|
|
518
|
-
html += '</div>';
|
|
519
|
-
|
|
520
|
-
resultsDiv.innerHTML = html;
|
|
521
|
-
resultsPanel.style.display = 'block';
|
|
522
|
-
|
|
523
|
-
// Scroll to results
|
|
524
|
-
resultsPanel.scrollIntoView({ behavior: 'smooth' });
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Show simulation results
|
|
529
|
-
*/
|
|
530
|
-
function showResults(results) {
|
|
531
|
-
const resultsPanel = document.getElementById('resultsPanel');
|
|
532
|
-
const resultsDiv = document.getElementById('simulationResults');
|
|
533
|
-
|
|
534
|
-
let html = '<div class="results-summary">';
|
|
535
|
-
html += `<p><strong>Total Simulations:</strong> ${results.total || 0}</p>`;
|
|
536
|
-
html += `<p><strong>Successful:</strong> ${results.successful || 0}</p>`;
|
|
537
|
-
html += `<p><strong>Failed:</strong> ${results.failed || 0}</p>`;
|
|
538
|
-
|
|
539
|
-
// Add multi-simulation information if applicable
|
|
540
|
-
if (results.use_multi_sim && results.alpha_count_per_slot) {
|
|
541
|
-
html += `<div class="info-box" style="margin: 10px 0;">`;
|
|
542
|
-
html += `<strong>📌 Multi-Simulation Mode:</strong><br>`;
|
|
543
|
-
html += `Each simulation slot contains ${results.alpha_count_per_slot} alphas.<br>`;
|
|
544
|
-
html += `Total individual alphas processed: <strong>${results.successful * results.alpha_count_per_slot}</strong>`;
|
|
545
|
-
html += `</div>`;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
html += '</div>';
|
|
549
|
-
|
|
550
|
-
if (results.alphaIds && results.alphaIds.length > 0) {
|
|
551
|
-
html += '<h4>Generated Alpha IDs:</h4>';
|
|
552
|
-
html += '<div class="alpha-ids" style="max-height: 200px; overflow-y: auto; background: #f8f9fa; padding: 10px; border-radius: 4px; font-family: monospace; font-size: 12px;">';
|
|
553
|
-
results.alphaIds.forEach((alphaId, index) => {
|
|
554
|
-
html += `<div>${index + 1}. ${alphaId}</div>`;
|
|
555
|
-
});
|
|
556
|
-
html += '</div>';
|
|
557
|
-
|
|
558
|
-
// Add copy button for alpha IDs
|
|
559
|
-
html += '<div style="margin-top: 10px;">';
|
|
560
|
-
html += '<button class="btn btn-outline btn-small" onclick="copyAlphaIds()">📋 Copy All Alpha IDs</button>';
|
|
561
|
-
html += '</div>';
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
resultsDiv.innerHTML = html;
|
|
565
|
-
resultsPanel.style.display = 'block';
|
|
566
|
-
|
|
567
|
-
// Store results for copying
|
|
568
|
-
window.lastSimulationResults = results;
|
|
569
|
-
|
|
570
|
-
// Scroll to results
|
|
571
|
-
resultsPanel.scrollIntoView({ behavior: 'smooth' });
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* Copy all alpha IDs to clipboard
|
|
576
|
-
*/
|
|
577
|
-
function copyAlphaIds() {
|
|
578
|
-
if (window.lastSimulationResults && window.lastSimulationResults.alphaIds) {
|
|
579
|
-
const alphaIds = window.lastSimulationResults.alphaIds.join('\n');
|
|
580
|
-
navigator.clipboard.writeText(alphaIds).then(() => {
|
|
581
|
-
updateStatus('✅ Alpha IDs copied to clipboard!', 'success');
|
|
582
|
-
}).catch(err => {
|
|
583
|
-
console.error('Failed to copy: ', err);
|
|
584
|
-
updateStatus('❌ Failed to copy Alpha IDs', 'error');
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* Handle page unload - cleanup polling
|
|
591
|
-
*/
|
|
592
|
-
window.addEventListener('beforeunload', function() {
|
|
593
|
-
stopLogPolling();
|
|
594
|
-
if (simulationAbortController) {
|
|
595
|
-
simulationAbortController.abort();
|
|
596
|
-
}
|
|
597
|
-
});
|