linny-r 1.9.3 → 2.0.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/LICENSE +1 -1
- package/README.md +172 -126
- package/console.js +2 -1
- package/package.json +1 -1
- package/post-install.js +93 -37
- package/server.js +73 -29
- package/static/images/eq-negated.png +0 -0
- package/static/images/power.png +0 -0
- package/static/images/tex.png +0 -0
- package/static/index.html +226 -11
- package/static/linny-r.css +458 -8
- package/static/scripts/linny-r-ctrl.js +6 -4
- package/static/scripts/linny-r-gui-actor-manager.js +1 -1
- package/static/scripts/linny-r-gui-chart-manager.js +20 -13
- package/static/scripts/linny-r-gui-constraint-editor.js +410 -50
- package/static/scripts/linny-r-gui-controller.js +138 -21
- package/static/scripts/linny-r-gui-dataset-manager.js +28 -20
- package/static/scripts/linny-r-gui-documentation-manager.js +11 -3
- package/static/scripts/linny-r-gui-equation-manager.js +1 -1
- package/static/scripts/linny-r-gui-experiment-manager.js +1 -1
- package/static/scripts/linny-r-gui-expression-editor.js +7 -1
- package/static/scripts/linny-r-gui-file-manager.js +63 -19
- package/static/scripts/linny-r-gui-finder.js +1 -1
- package/static/scripts/linny-r-gui-model-autosaver.js +1 -1
- package/static/scripts/linny-r-gui-monitor.js +1 -1
- package/static/scripts/linny-r-gui-paper.js +108 -25
- package/static/scripts/linny-r-gui-power-grid-manager.js +529 -0
- package/static/scripts/linny-r-gui-receiver.js +1 -1
- package/static/scripts/linny-r-gui-repository-browser.js +1 -1
- package/static/scripts/linny-r-gui-scale-unit-manager.js +1 -1
- package/static/scripts/linny-r-gui-sensitivity-analysis.js +1 -1
- package/static/scripts/linny-r-gui-tex-manager.js +110 -0
- package/static/scripts/linny-r-gui-undo-redo.js +1 -1
- package/static/scripts/linny-r-milp.js +1 -1
- package/static/scripts/linny-r-model.js +982 -123
- package/static/scripts/linny-r-utils.js +3 -3
- package/static/scripts/linny-r-vm.js +731 -252
- package/static/show-diff.html +1 -1
- package/static/show-png.html +1 -1
package/post-install.js
CHANGED
@@ -5,28 +5,30 @@ The Linny-R language and tool have been developed by Pieter Bots at Delft
|
|
5
5
|
University of Technology, starting in 2009. The project to develop a browser-
|
6
6
|
based version started in 2017. See https://linny-r.org for more information.
|
7
7
|
|
8
|
-
This NodeJS script (post-install.js)
|
9
|
-
|
10
|
-
|
8
|
+
This NodeJS script (post-install.js) checks whether the Linny-R directory
|
9
|
+
contains a launch script for Linny-R. For macOS, the script file is
|
10
|
+
`linny-r.command`, for Windows `linny-r.bat`.
|
11
|
+
If such a file already exists, this script will try to rename it, adding
|
12
|
+
the prefix `OLD-` to the name. Doing this will make that the the Linny-R
|
13
|
+
server script will create the newest version of the launch script the
|
14
|
+
first time it is run.
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
The launch script has two intended functions:
|
17
|
+
(1) to facilitate start-up: the user can type `linny-r` at the command
|
18
|
+
line prompt,and (more importantly) create a clickable icon as desktop
|
19
|
+
shortcut.
|
20
|
+
(2) to facilitate automatic software updates: when (after lauch in a browser)
|
21
|
+
Linny-R detects a newer version, it will prompt the user whether this
|
22
|
+
update should be installed. When the user confirms, the server script
|
23
|
+
is terminated, and then launch script executes the commands to update
|
24
|
+
and then restart the Linny-R server.
|
14
25
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
since Windows also supports the slash as path separator. The "launch"
|
19
|
-
command tells the script `server.js` to start Linny-R in the default
|
20
|
-
web browser.
|
21
|
-
|
22
|
-
Comments are added to the script file to facilitate customization of the
|
23
|
-
scripts by the user. The README.md file explains how the script file can be
|
24
|
-
used for single-click launch of Linny-R, and how the "workspace" parameter
|
25
|
-
can be used in a multi-user network environment to provide individual
|
26
|
-
workspaces for users.
|
26
|
+
The README.md file explains how the script file can be used for single-click
|
27
|
+
launch of Linny-R, and how the "workspace" parameter can be used in a
|
28
|
+
multi-user network environment to provide individual workspaces for users.
|
27
29
|
*/
|
28
30
|
/*
|
29
|
-
Copyright (c) 2020-
|
31
|
+
Copyright (c) 2020-2024 Delft University of Technology
|
30
32
|
|
31
33
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
32
34
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -56,32 +58,86 @@ const
|
|
56
58
|
// NOTE: working directory for this script is the *module* directory,
|
57
59
|
// which is two levels deeper than the actual working directory
|
58
60
|
WORKING_DIRECTORY = process.cwd().replace(path.sep + mod_dir, ''),
|
59
|
-
|
61
|
+
ext = (PLATFORM.startsWith('win') ? 'bat' : 'command'),
|
62
|
+
sp = path.join(WORKING_DIRECTORY, 'linny-r.' + ext);
|
63
|
+
|
64
|
+
// NOTE: Function `createLaunchScript` is a copy of this function as
|
65
|
+
// defined in script file `server.js`.
|
66
|
+
|
67
|
+
function createLaunchScript() {
|
68
|
+
// Creates platform-specific script with Linny-R start-up command
|
69
|
+
const
|
70
|
+
lines = [
|
60
71
|
'# The first line (without the comment symbol #) should be like this:',
|
61
|
-
'# cd ',
|
62
72
|
'',
|
73
|
+
'cd ' + WORKING_DIRECTORY,
|
63
74
|
'# Then this command to launch the Linny-R server should work:',
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
'',
|
76
|
+
'# After shut-down, check whether new version should be installed:'
|
77
|
+
],
|
78
|
+
windows = PLATFORM.startsWith('win'),
|
79
|
+
sp = path.join(WORKING_DIRECTORY, 'linny-r.' + (windows ? 'bat' : 'command'));
|
80
|
+
if(windows) {
|
81
|
+
lines.push(
|
82
|
+
':loop',
|
83
|
+
'if exist newer_version (',
|
84
|
+
' del newer_version',
|
85
|
+
' npm update linny-r',
|
86
|
+
' node node_modules\\linny-r\\server',
|
87
|
+
' goto loop',
|
88
|
+
')');
|
89
|
+
lines[1] = '# cd C:\\path\\to\\main\\Linny-R\\directory';
|
90
|
+
lines[4] = 'node node_modules\\linny-r\\server launch';
|
91
|
+
} else {
|
92
|
+
lines.push(
|
93
|
+
'while test -f newer_version; do',
|
94
|
+
' unlink newer_version',
|
95
|
+
' npm update linny-r',
|
96
|
+
' node node_modules/linny-r/server',
|
97
|
+
'done');
|
98
|
+
lines[1] = '# cd /path/to/main/Linny-R/directory';
|
99
|
+
lines[4] = 'node node_modules/linny-r/server launch';
|
100
|
+
}
|
101
|
+
try {
|
102
|
+
let code = lines.join(os.EOL);
|
103
|
+
if(windows) code = code.replaceAll('#', '::');
|
104
|
+
try {
|
105
|
+
fs.accessSync(sp);
|
106
|
+
// Do not overwrite existing script, as it may have been customized
|
107
|
+
// by the user. When istalling/updating Linny-R, the post-install
|
108
|
+
// script should have renamed it, so typically it is created the
|
109
|
+
// first time Linny-R is run after install/update.
|
110
|
+
} catch(err) {
|
111
|
+
console.log('Creating launch script:', sp);
|
112
|
+
fs.writeFileSync(sp, code, 'utf8');
|
113
|
+
// On macOS machines, try to make the script executable.
|
114
|
+
if(!windows) try {
|
115
|
+
fs.chmodSync(sp, '+x');
|
116
|
+
} catch(err) {
|
117
|
+
console.log('WARNING: Failed to make script executable -- please check');
|
118
|
+
}
|
119
|
+
}
|
120
|
+
} catch(err) {
|
121
|
+
console.log('WARNING: Failed to create launch script');
|
122
|
+
}
|
73
123
|
}
|
74
|
-
|
124
|
+
|
125
|
+
// First rename the existing script (if any) as this may have been changed
|
126
|
+
// by the user, and the idea of the changes would be lost by overwriting it.
|
75
127
|
try {
|
128
|
+
fs.accessSync(sp);
|
76
129
|
try {
|
77
|
-
|
130
|
+
// Only rename the script content if the file it does not yet exist
|
131
|
+
console.log('Renaming existing launch script:', sp);
|
132
|
+
fs.renameSync(sp, path.join(WORKING_DIRECTORY, 'OLD-linny-r.' + ext));
|
78
133
|
} catch(err) {
|
79
|
-
|
80
|
-
console.log('Creating launch script:', sp);
|
81
|
-
let code = lines.join(os.EOL);
|
82
|
-
if(PLATFORM.startsWith('win')) code = code.replaceAll('#', '::');
|
83
|
-
fs.writeFileSync(sp, code, 'utf8');
|
134
|
+
console.log('WARNING: Failed to rename existing launch script');
|
84
135
|
}
|
85
136
|
} catch(err) {
|
86
|
-
|
137
|
+
// No existing script => action needed.
|
87
138
|
}
|
139
|
+
|
140
|
+
// Then create new launch script. This way, after update or clean install,
|
141
|
+
// the user can
|
142
|
+
createLaunchScript();
|
143
|
+
|
package/server.js
CHANGED
@@ -12,7 +12,7 @@ that pass the MILP equation model to the solver, and then return the solution
|
|
12
12
|
to the Linny-R "virtual machine" that is running in the browser.
|
13
13
|
*/
|
14
14
|
/*
|
15
|
-
Copyright (c) 2020-
|
15
|
+
Copyright (c) 2020-2024 Delft University of Technology
|
16
16
|
|
17
17
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
18
18
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -416,9 +416,21 @@ function autoSaveLoad(res, sp) {
|
|
416
416
|
function autoSaveStore(res, sp) {
|
417
417
|
// Stores XML data under specified file name in the auto-save directory
|
418
418
|
let data = 'OK';
|
419
|
-
const
|
419
|
+
const
|
420
|
+
fn = sp.get('file'),
|
421
|
+
wsd = sp.get('wsd'),
|
422
|
+
ws = (wsd ? WORKSPACE.models : WORKSPACE.autosave),
|
423
|
+
msg = (wsd === 'models' ? 'save to user workspace' : 'auto-save'),
|
424
|
+
exists = (path) => {
|
425
|
+
try {
|
426
|
+
fs.accessSync(path);
|
427
|
+
return true;
|
428
|
+
} catch(err) {
|
429
|
+
return false;
|
430
|
+
}
|
431
|
+
};
|
420
432
|
if(!fn) {
|
421
|
-
data = 'WARNING: No name for file to
|
433
|
+
data = 'WARNING: No name for file to ' + msg;
|
422
434
|
} else {
|
423
435
|
const xml = sp.get('xml');
|
424
436
|
// Validate XML as a Linny-R model
|
@@ -429,10 +441,41 @@ function autoSaveStore(res, sp) {
|
|
429
441
|
root = doc.documentElement;
|
430
442
|
// Linny-R models have a model element as root
|
431
443
|
if(root.nodeName !== 'model') throw 'XML document has no model element';
|
432
|
-
|
444
|
+
let fp = path.join(ws, fn + '.lnr');
|
445
|
+
if(wsd) {
|
446
|
+
// Append a version number to the file name if named file exists.
|
447
|
+
const re = /\(\d+\).lnr$/;
|
448
|
+
if(exists(fp)) {
|
449
|
+
const m = fp.match(re);
|
450
|
+
let n = 1;
|
451
|
+
if(m) {
|
452
|
+
// Replace version number (n) by (n+1).
|
453
|
+
n = parseInt(m[0].substring(1, m[0].length - 1)) + 1;
|
454
|
+
fp = fp.replace(re, `(${n}).lnr`);
|
455
|
+
} else {
|
456
|
+
// Add (1) as version number.
|
457
|
+
fp = fp.substring(0, fp.length - 4) + ' (1).lnr';
|
458
|
+
}
|
459
|
+
while(exists(fp)) {
|
460
|
+
// Iterate to find the first available version number.
|
461
|
+
n++;
|
462
|
+
fp = fp.replace(re, `(${n}).lnr`);
|
463
|
+
}
|
464
|
+
}
|
465
|
+
}
|
466
|
+
try {
|
467
|
+
fs.writeFileSync(fp, xml);
|
468
|
+
const d = `Model ${ws ? '' : 'auto-'}saved as ${fp}`;
|
469
|
+
console.log(d);
|
470
|
+
// No message (other than OK) when auto-saving.
|
471
|
+
if(ws) data = d;
|
472
|
+
} catch(err) {
|
473
|
+
console.log(err);
|
474
|
+
data = `ERROR: Failed to ${msg} to ${fp}`;
|
475
|
+
}
|
433
476
|
} catch(err) {
|
434
477
|
console.log(err);
|
435
|
-
data = 'ERROR: Not a Linny-R model to
|
478
|
+
data = 'ERROR: Not a Linny-R model to ' + msg;
|
436
479
|
}
|
437
480
|
}
|
438
481
|
servePlainText(res, data);
|
@@ -1687,6 +1730,7 @@ function createWorkspace() {
|
|
1687
1730
|
callback: path.join(SETTINGS.user_dir, 'callback'),
|
1688
1731
|
data: path.join(SETTINGS.user_dir, 'data'),
|
1689
1732
|
diagrams: path.join(SETTINGS.user_dir, 'diagrams'),
|
1733
|
+
models: path.join(SETTINGS.user_dir, 'models'),
|
1690
1734
|
modules: path.join(SETTINGS.user_dir, 'modules'),
|
1691
1735
|
reports: path.join(SETTINGS.user_dir, 'reports'),
|
1692
1736
|
solver_output: path.join(SETTINGS.user_dir, 'solver')
|
@@ -1715,18 +1759,18 @@ function createWorkspace() {
|
|
1715
1759
|
|
1716
1760
|
function createLaunchScript() {
|
1717
1761
|
// Creates platform-specific script with Linny-R start-up command
|
1718
|
-
const
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1762
|
+
const
|
1763
|
+
lines = [
|
1764
|
+
'# The first line (without the comment symbol #) should be like this:',
|
1765
|
+
'',
|
1766
|
+
'cd ' + WORKING_DIRECTORY,
|
1767
|
+
'# Then this command to launch the Linny-R server should work:',
|
1768
|
+
'',
|
1769
|
+
'# After shut-down, check whether new version should be installed:'
|
1770
|
+
],
|
1771
|
+
windows = PLATFORM.startsWith('win'),
|
1772
|
+
sp = path.join(WORKING_DIRECTORY, 'linny-r.' + (windows ? 'bat' : 'command'));
|
1773
|
+
if(windows) {
|
1730
1774
|
lines.push(
|
1731
1775
|
':loop',
|
1732
1776
|
'if exist newer_version (',
|
@@ -1738,7 +1782,6 @@ function createLaunchScript() {
|
|
1738
1782
|
lines[1] = '# cd C:\\path\\to\\main\\Linny-R\\directory';
|
1739
1783
|
lines[4] = 'node node_modules\\linny-r\\server launch';
|
1740
1784
|
} else {
|
1741
|
-
sp = path.join(WORKING_DIRECTORY, 'linny-r.command');
|
1742
1785
|
lines.push(
|
1743
1786
|
'while test -f newer_version; do',
|
1744
1787
|
' unlink newer_version',
|
@@ -1749,22 +1792,23 @@ function createLaunchScript() {
|
|
1749
1792
|
lines[4] = 'node node_modules/linny-r/server launch';
|
1750
1793
|
}
|
1751
1794
|
try {
|
1752
|
-
let
|
1753
|
-
|
1754
|
-
if(PLATFORM.startsWith('win')) code = code.replaceAll('#', '::');
|
1795
|
+
let code = lines.join(os.EOL);
|
1796
|
+
if(windows) code = code.replaceAll('#', '::');
|
1755
1797
|
try {
|
1756
1798
|
fs.accessSync(sp);
|
1757
|
-
//
|
1758
|
-
// by the user
|
1759
|
-
|
1760
|
-
|
1799
|
+
// Do not overwrite existing script, as it may have been customized
|
1800
|
+
// by the user. When istalling/updating Linny-R, the post-install
|
1801
|
+
// script should have renamed it, so typically it is created the
|
1802
|
+
// first time Linny-R is run after install/update.
|
1761
1803
|
} catch(err) {
|
1762
|
-
// ... or if it does not exist yet.
|
1763
|
-
make_script = true;
|
1764
|
-
}
|
1765
|
-
if(make_script) {
|
1766
1804
|
console.log('Creating launch script:', sp);
|
1767
1805
|
fs.writeFileSync(sp, code, 'utf8');
|
1806
|
+
// On macOS machines, try to make the script executable.
|
1807
|
+
if(!windows) try {
|
1808
|
+
fs.chmodSync(sp, '+x');
|
1809
|
+
} catch(err) {
|
1810
|
+
console.log('WARNING: Failed to make script executable -- please check');
|
1811
|
+
}
|
1768
1812
|
}
|
1769
1813
|
} catch(err) {
|
1770
1814
|
console.log('WARNING: Failed to create launch script');
|
Binary file
|
Binary file
|
Binary file
|