linny-r 1.5.8 → 1.6.1
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/package.json +1 -1
- package/static/index.html +7 -3
- package/static/linny-r.css +19 -0
- package/static/scripts/linny-r-gui-actor-manager.js +3 -3
- package/static/scripts/linny-r-gui-chart-manager.js +10 -9
- package/static/scripts/linny-r-gui-controller.js +49 -36
- package/static/scripts/linny-r-gui-dataset-manager.js +17 -49
- package/static/scripts/linny-r-gui-documentation-manager.js +71 -47
- package/static/scripts/linny-r-gui-equation-manager.js +26 -10
- package/static/scripts/linny-r-gui-experiment-manager.js +41 -23
- package/static/scripts/linny-r-gui-expression-editor.js +26 -21
- package/static/scripts/linny-r-gui-finder.js +1 -0
- package/static/scripts/linny-r-gui-monitor.js +4 -4
- package/static/scripts/linny-r-milp.js +18 -15
- package/static/scripts/linny-r-model.js +354 -137
- package/static/scripts/linny-r-utils.js +68 -18
- package/static/scripts/linny-r-vm.js +593 -300
@@ -307,6 +307,26 @@ function indexOfMatchingBracket(str, offset) {
|
|
307
307
|
return -1;
|
308
308
|
}
|
309
309
|
|
310
|
+
function monoSpaced(vbl) {
|
311
|
+
// Removes all non-essential spaces from variable reference `vbl`.
|
312
|
+
// First reduce all whitespace to a single space.
|
313
|
+
return vbl.replace(/\s+/g, ' ')
|
314
|
+
// Then remove spaces after the opening bracket.
|
315
|
+
.replace(/\[\s+/g, '[')
|
316
|
+
// Also remove spaces after a leading colon (if any).
|
317
|
+
.replace(/\[:\s+/g, '[:')
|
318
|
+
// Also remove spaces before closing bracket.
|
319
|
+
.replace(/\s+\]/, ']');
|
320
|
+
}
|
321
|
+
|
322
|
+
function monoSpacedVariables(xt) {
|
323
|
+
// Return expression text `xt` with all non-functional whitespace
|
324
|
+
// *inside* its variable references (i.e., substrings like
|
325
|
+
// "[entity name|attribute]") removed.
|
326
|
+
// NOTE: All spacing *outside* variable references is preserved.
|
327
|
+
return xt.replace(/\[[^\]]*\]/g, monoSpaced);
|
328
|
+
}
|
329
|
+
|
310
330
|
function patternList(str) {
|
311
331
|
// Returns the &|^-pattern defined by `str`
|
312
332
|
// Pattern operators: & (and), ^ (not) and | (or) in sequence, e.g.,
|
@@ -510,13 +530,19 @@ function compareWithTailNumbers(s1, s2) {
|
|
510
530
|
|
511
531
|
function compareSelectors(s1, s2) {
|
512
532
|
// Dataset selectors comparison is case-insensitive, and puts wildcards
|
513
|
-
// last, where * comes later than
|
514
|
-
//
|
515
|
-
//
|
516
|
-
//
|
533
|
+
// last, where * comes later than ?, and leading colons come AFTER
|
534
|
+
// regular selector names.
|
535
|
+
// NOTE: Without wildcards, strings that are identical except for the
|
536
|
+
// digits they *end* on are sorted on this "end number" (so abc12 > abc2).
|
537
|
+
// NOTE: This also applies to percentages ("end number"+ %).
|
517
538
|
if(s1 === s2) return 0;
|
518
539
|
if(s1 === '*') return 1;
|
519
540
|
if(s2 === '*') return -1;
|
541
|
+
// Replace leading colon by | because | has a higher ASCII value than
|
542
|
+
// all other characters. This will move selectors with leading colons
|
543
|
+
// to the end of the list.
|
544
|
+
if(s1.startsWith(':')) s1 = '|' + s1.substring(1);
|
545
|
+
if(s2.startsWith(':')) s2 = '|' + s2.substring(1);
|
520
546
|
const
|
521
547
|
star1 = s1.indexOf('*'),
|
522
548
|
star2 = s2.indexOf('*');
|
@@ -525,10 +551,10 @@ function compareSelectors(s1, s2) {
|
|
525
551
|
return ciCompare(s1, s2);
|
526
552
|
}
|
527
553
|
if(star2 >= 0) return -1;
|
528
|
-
//
|
554
|
+
// Now replace ? by | to make it sort further down than other characters.
|
529
555
|
let s_1 = s1.replace('?', '|').toLowerCase(),
|
530
556
|
s_2 = s2.replace('?', '|').toLowerCase(),
|
531
|
-
// NOTE:
|
557
|
+
// NOTE: Selectors ending on a number or percentage are special.
|
532
558
|
n_1 = endsWithDigits(s_1),
|
533
559
|
p_1 = (s1.endsWith('%') ? endsWithDigits(s1.slice(0, -1)) : '');
|
534
560
|
if(n_1) {
|
@@ -546,10 +572,11 @@ function compareSelectors(s1, s2) {
|
|
546
572
|
return parseInt(p_1) - parseInt(p_2);
|
547
573
|
}
|
548
574
|
}
|
549
|
-
// Also sort selectors ending on minuses lower than those ending on
|
550
|
-
// and
|
551
|
-
// ASCII(+) = 43, ASCII(-) = 45, so replace trailing minuses
|
552
|
-
// (ASCII 32) and add a '!' (ASCII 33)
|
575
|
+
// Also sort selectors ending on minuses lower than those ending on
|
576
|
+
// plusses, and so that X-- comes before X-, like X+ automatically comes
|
577
|
+
// before X++. ASCII(+) = 43, ASCII(-) = 45, so replace trailing minuses
|
578
|
+
// by as many spaces (ASCII 32) and add a '!' (ASCII 33). This will then
|
579
|
+
// "sorts things out".
|
553
580
|
let n = s_1.length,
|
554
581
|
i = n - 1;
|
555
582
|
while(i >= 0 && s_1[i] === '-') i--;
|
@@ -716,17 +743,28 @@ function xmlDecoded(str) {
|
|
716
743
|
}
|
717
744
|
|
718
745
|
function customizeXML(str) {
|
719
|
-
// NOTE:
|
746
|
+
// NOTE: This function can be customized to pre-process a model file,
|
720
747
|
// for example to rename entities in one go -- USE WITH CARE!
|
721
|
-
//
|
722
|
-
|
748
|
+
// To prevent unintended customization, check whether the model name
|
749
|
+
// ends with "!!CUSTOMIZE". This check ensures that the modeler must
|
750
|
+
// first save the model with this text as the (end of the) model name
|
751
|
+
// and then load it again for the customization to be performed.
|
752
|
+
if(str.indexOf('!!CUSTOMIZE</name><author>') >= 0) {
|
753
|
+
// Modify `str` -- by default, do nothing, but typical modifications
|
754
|
+
// will replace RexEx patterns by other strings.
|
755
|
+
|
723
756
|
/*
|
724
|
-
|
725
|
-
|
726
|
-
|
757
|
+
const
|
758
|
+
re = /xyz/gi,
|
759
|
+
r = 'abc';
|
727
760
|
*/
|
728
761
|
|
729
|
-
|
762
|
+
// Trace the changes to the console.
|
763
|
+
console.log('Customizing:', re, r);
|
764
|
+
console.log('Matches:', str.match(re));
|
765
|
+
str = str.replace(re, r);
|
766
|
+
}
|
767
|
+
// Finally, return the modified string.
|
730
768
|
return str;
|
731
769
|
}
|
732
770
|
|
@@ -830,10 +868,22 @@ function randomID() {
|
|
830
868
|
}
|
831
869
|
|
832
870
|
function escapedSingleQuotes(s) {
|
833
|
-
//
|
871
|
+
// Return string `s` with "escaped" single quotes.
|
834
872
|
return s.replace('\'', '\\\'');
|
835
873
|
}
|
836
874
|
|
875
|
+
function safeDoubleQuotes(s) {
|
876
|
+
// Return string `s` with ASCII quotes " replaced by curly quotes to
|
877
|
+
// ensure that it does not break HTML attribute strings.
|
878
|
+
const q = ['\u201C', '\u201D'];
|
879
|
+
let index = 0;
|
880
|
+
while(s.indexOf('"') >= 0) {
|
881
|
+
s = s.replace('"', q[index]);
|
882
|
+
index = 1 - index;
|
883
|
+
}
|
884
|
+
return s;
|
885
|
+
}
|
886
|
+
|
837
887
|
function nameToLines(name, actor_name = '') {
|
838
888
|
// Return the name of a Linny-R entity as a string-with-line-breaks
|
839
889
|
// that fits nicely in an oblong box. For efficiency reasons, a fixed
|