linny-r 2.0.4 → 2.0.6

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 CHANGED
@@ -1,32 +1,32 @@
1
- {
2
- "name": "linny-r",
3
- "version": "2.0.4",
4
- "description": "Executable graphical language with WYSIWYG editor for MILP models",
5
- "main": "server.js",
6
- "scripts": {
7
- "postinstall": "node post-install.js",
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "dependencies": {
11
- "@xmldom/xmldom": ">=0.8.2"
12
- },
13
- "repository": {
14
- "type": "git",
15
- "url": "git+https://github.com/pwgbots/linny-r.git"
16
- },
17
- "keywords": [
18
- "executable",
19
- "graphical modeling language",
20
- "mixed integer linear programming",
21
- "optimization",
22
- "simulation",
23
- "unit commitment",
24
- "generation expansion"
25
- ],
26
- "author": "Pieter W.G. Bots",
27
- "license": "MIT",
28
- "bugs": {
29
- "url": "https://github.com/pwgbots/linny-r/issues"
30
- },
31
- "homepage": "https://github.com/pwgbots/linny-r#readme"
32
- }
1
+ {
2
+ "name": "linny-r",
3
+ "version": "2.0.6",
4
+ "description": "Executable graphical language with WYSIWYG editor for MILP models",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "postinstall": "node post-install.js",
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "dependencies": {
11
+ "@xmldom/xmldom": ">=0.8.2"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/pwgbots/linny-r.git"
16
+ },
17
+ "keywords": [
18
+ "executable",
19
+ "graphical modeling language",
20
+ "mixed integer linear programming",
21
+ "optimization",
22
+ "simulation",
23
+ "unit commitment",
24
+ "generation expansion"
25
+ ],
26
+ "author": "Pieter W.G. Bots",
27
+ "license": "MIT",
28
+ "bugs": {
29
+ "url": "https://github.com/pwgbots/linny-r/issues"
30
+ },
31
+ "homepage": "https://github.com/pwgbots/linny-r#readme"
32
+ }
package/server.js CHANGED
@@ -330,28 +330,34 @@ function asFileName(s) {
330
330
  }
331
331
 
332
332
  function autoSave(res, sp) {
333
- // Processes all auto-save & restore commands
334
- const action = sp.get('action').trim();
335
- logAction('Auto-save action: ' + action);
333
+ // Process all auto-save & restore commands.
334
+ // NOTE: To prevent duplicate code, this routine is also called when
335
+ // the modeler SHIFT-clicks on the "Save model" button. This option
336
+ // has been added to permit saving files larger than the 25 MB that
337
+ // some browsers impose as limit for saving a string to disk.
338
+ const
339
+ action = sp.get('action').trim(),
340
+ saving = (sp.get('wsd') === 'true' ? 'Save' : 'Auto-save');
341
+ logAction(saving + ' action: ' + action);
336
342
  if(['purge', 'load', 'store'].indexOf(action) < 0) {
337
- // Invalid action => report error
343
+ // Invalid action => report error.
338
344
  return servePlainText(res, `ERROR: Invalid auto-save action: "${action}"`);
339
345
  }
340
346
  // Always purge the auto-save files before further action; this returns
341
- // the list with model data objects
347
+ // the list with model data objects.
342
348
  const data = autoSavePurge(res, sp);
343
- // NOTE: if string instead of array, this string is an error message
349
+ // NOTE: If string instead of array, this string is an error message.
344
350
  if(typeof data === 'string') return servePlainText(res, data);
345
- // Perform load or store actions if requested
351
+ // Perform load or store actions if requested.
346
352
  if(action === 'load') return autoSaveLoad(res, sp);
347
353
  if(action === 'store') return autoSaveStore(res, sp);
348
- // Otherwise, action was 'purge' => return the auto-saved model list
354
+ // Otherwise, action was 'purge' => return the auto-saved model list.
349
355
  serveJSON(res, data);
350
356
  }
351
357
 
352
358
  function autoSavePurge(res, sp) {
353
- // Deletes specified file(s) (if any) as well as all expired files,
354
- // and returns list with data on remaining files as JSON string
359
+ // Delete specified file(s) (if any) as well as all expired files,
360
+ // and return list with data on remaining files as JSON string.
355
361
  const
356
362
  now = new Date(),
357
363
  p = sp.get('period'),
@@ -359,7 +365,7 @@ function autoSavePurge(res, sp) {
359
365
  df = sp.get('to_delete'),
360
366
  all = df === '/*ALL*/';
361
367
 
362
- // Get list of data on Linny-R models in `autosave` directory
368
+ // Get list of data on Linny-R models in `autosave` directory.
363
369
  data = [];
364
370
  try {
365
371
  const flist = fs.readdirSync(WORKSPACE.autosave);
@@ -368,7 +374,7 @@ function autoSavePurge(res, sp) {
368
374
  pp = path.parse(flist[i]),
369
375
  md = {name: pp.name},
370
376
  fp = path.join(WORKSPACE.autosave, flist[i]);
371
- // NOTE: only consider Linny-R model files (extension .lnr)
377
+ // NOTE: Only consider Linny-R model files (extension .lnr).
372
378
  if(pp.ext === '.lnr') {
373
379
  let dodel = all || pp.name === df;
374
380
  if(!dodel) {
@@ -376,11 +382,11 @@ function autoSavePurge(res, sp) {
376
382
  const fstat = fs.statSync(fp);
377
383
  md.size = fstat.size;
378
384
  md.date = fstat.mtime;
379
- // Also delete if file has expired
385
+ // Also delete if file has expired.
380
386
  dodel = now - fstat.mtimeMs > period;
381
387
  }
382
388
  if(dodel) {
383
- // Delete model file
389
+ // Delete model file.
384
390
  try {
385
391
  fs.unlinkSync(fp);
386
392
  } catch(err) {
@@ -388,7 +394,7 @@ function autoSavePurge(res, sp) {
388
394
  console.log(err);
389
395
  }
390
396
  } else {
391
- // Add model data to the list
397
+ // Add model data to the list.
392
398
  data.push(md);
393
399
  }
394
400
  }
@@ -401,7 +407,7 @@ function autoSavePurge(res, sp) {
401
407
  }
402
408
 
403
409
  function autoSaveLoad(res, sp) {
404
- // Return XML content of specified file
410
+ // Return XML content of specified file".
405
411
  const fn = sp.get('file');
406
412
  if(fn) {
407
413
  const fp = path.join(WORKSPACE.autosave, fn + '.lnr');
@@ -418,13 +424,15 @@ function autoSaveLoad(res, sp) {
418
424
  }
419
425
 
420
426
  function autoSaveStore(res, sp) {
421
- // Stores XML data under specified file name in the auto-save directory
427
+ // Store XML data under specified file name in the auto-save directory,
428
+ // or in the models directory if the "Save model button was SHIFT-clicked.
422
429
  let data = 'OK';
423
430
  const
424
431
  fn = sp.get('file'),
425
- wsd = sp.get('wsd'),
432
+ // NOTE: Booleans are passed as strings.
433
+ wsd = sp.get('wsd') === 'true',
426
434
  ws = (wsd ? WORKSPACE.models : WORKSPACE.autosave),
427
- msg = (wsd === 'models' ? 'save to user workspace' : 'auto-save'),
435
+ msg = (wsd ? 'save to user workspace' : 'auto-save'),
428
436
  exists = (path) => {
429
437
  try {
430
438
  fs.accessSync(path);
@@ -1,23 +1,23 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <svg width="32px" height="32px" xmlns="http://www.w3.org/2000/svg"
3
- viewBox="24 32 232 231" preserveAspectRatio="xMidYMid">
4
- <style>
5
- path.roic {
6
- stroke: #8264a0;
7
- stroke-width: 1px;
8
- stroke-linejoin: round;
9
- stroke-opacity: 1;
10
- opacity: 0.45;
11
- }
12
- </style>
13
- <g id="fr00">
14
- <path id="ABC0" class="roic" style="fill:#960041" d="M40 96L167 78L122 32z"></path>
15
- <path id="ADE0" class="roic" style="fill:#ebebe1" d="M40 96L61 189L120 208z"></path>
16
- <path id="AEB0" class="roic" style="fill:#fab8ea" d="M40 96L120 208L167 78z"></path>
17
- <path id="ACD0" class="roic" style="fill:#3236c8" d="M40 96L122 32L61 189z"></path>
18
- <path id="FBC0" class="roic" style="fill:#ebebe1" d="M215 160L167 78L122 32z"></path>
19
- <path id="FDE0" class="roic" style="fill:#960041" d="M215 160L61 189L120 208z"></path>
20
- <path id="FEB0" class="roic" style="fill:#3236c8" d="M215 160L120 208L167 78z"></path>
21
- <path id="FCD0" class="roic" style="fill:#fab8ea" d="M215 160L122 32L61 189z"></path>
22
- </g>
23
- </svg>
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="32px" height="32px" xmlns="http://www.w3.org/2000/svg"
3
+ viewBox="24 32 232 231" preserveAspectRatio="xMidYMid">
4
+ <style>
5
+ path.roic {
6
+ stroke: #8264a0;
7
+ stroke-width: 1px;
8
+ stroke-linejoin: round;
9
+ stroke-opacity: 1;
10
+ opacity: 0.45;
11
+ }
12
+ </style>
13
+ <g id="fr00">
14
+ <path id="ABC0" class="roic" style="fill:#960041" d="M40 96L167 78L122 32z"></path>
15
+ <path id="ADE0" class="roic" style="fill:#ebebe1" d="M40 96L61 189L120 208z"></path>
16
+ <path id="AEB0" class="roic" style="fill:#fab8ea" d="M40 96L120 208L167 78z"></path>
17
+ <path id="ACD0" class="roic" style="fill:#3236c8" d="M40 96L122 32L61 189z"></path>
18
+ <path id="FBC0" class="roic" style="fill:#ebebe1" d="M215 160L167 78L122 32z"></path>
19
+ <path id="FDE0" class="roic" style="fill:#960041" d="M215 160L61 189L120 208z"></path>
20
+ <path id="FEB0" class="roic" style="fill:#3236c8" d="M215 160L120 208L167 78z"></path>
21
+ <path id="FCD0" class="roic" style="fill:#fab8ea" d="M215 160L122 32L61 189z"></path>
22
+ </g>
23
+ </svg>
package/static/index.html CHANGED
@@ -378,7 +378,9 @@ and move the cursor over the status bar">
378
378
  title="Add cluster">
379
379
  <img id="note-btn" class="btn toggle enab sep" src="images/note.png"
380
380
  title="Add note">
381
- <img id="clone-btn" class="btn disab sep" src="images/clone.png"
381
+ <img id="replace-btn" class="btn disab" src="images/replace-product.png"
382
+ title="Replace selected product by some other product (Alt-P)">
383
+ <img id="clone-btn" class="btn disab" src="images/clone.png"
382
384
  title="Copy selection (Ctrl-C) &ndash; Alt-click to clone (Alt-C)">
383
385
  <img id="paste-btn" class="btn disab sep" src="images/paste.png"
384
386
  title="Paste selection (Ctrl-V)">
@@ -667,6 +669,12 @@ and move the cursor over the status bar">
667
669
  </td>
668
670
  <td style="padding-bottom:4px">Infer and display cost prices</td>
669
671
  </tr>
672
+ <tr>
673
+ <td style="padding:0px">
674
+ <div id="settings-negative-flows" class="box clear"></div>
675
+ </td>
676
+ <td style="padding-bottom:4px">Do not warn when process levels are < 0</td>
677
+ </tr>
670
678
  <tr>
671
679
  <td style="padding:0px">
672
680
  <div id="settings-decimal-comma" class="box clear"></div>
@@ -1375,6 +1383,9 @@ NOTE: Products directly linked to such processes should have a proportional unit
1375
1383
  <option id="link-shutdown" value="10">
1376
1384
  &#x25BC; (shut-down: 1 if X[t-1] > 0 &and; X[t] = 0, otherwise 0)
1377
1385
  </option>
1386
+ <option id="link-slack" value="12">
1387
+ &#x21A5; (available capacity: UB - X[t])
1388
+ </option>
1378
1389
  <option id="link-spinning" value="8">
1379
1390
  &#x2934; (spinning reserve: UB - X[t] if X[t] > 0, otherwise 0)
1380
1391
  </option>
@@ -1,7 +1,7 @@
1
- /*!
2
- * iro.js v5.5.2
3
- * 2016-2021 James Daniel
4
- * Licensed under MPL 2.0
5
- * github.com/jaames/iro.js
6
- */
7
- !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).iro=n()}(this,function(){"use strict";var m,s,n,i,o,x={},j=[],r=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|^--/i;function M(t,n){for(var i in n)t[i]=n[i];return t}function y(t){var n=t.parentNode;n&&n.removeChild(t)}function h(t,n,i){var r,e,u,o,l=arguments;if(n=M({},n),3<arguments.length)for(i=[i],r=3;r<arguments.length;r++)i.push(l[r]);if(null!=i&&(n.children=i),null!=t&&null!=t.defaultProps)for(e in t.defaultProps)void 0===n[e]&&(n[e]=t.defaultProps[e]);return o=n.key,null!=(u=n.ref)&&delete n.ref,null!=o&&delete n.key,c(t,n,o,u)}function c(t,n,i,r){var e={type:t,props:n,key:i,ref:r,n:null,i:null,e:0,o:null,l:null,c:null,constructor:void 0};return m.vnode&&m.vnode(e),e}function O(t){return t.children}function I(t,n){this.props=t,this.context=n}function w(t,n){if(null==n)return t.i?w(t.i,t.i.n.indexOf(t)+1):null;for(var i;n<t.n.length;n++)if(null!=(i=t.n[n])&&null!=i.o)return i.o;return"function"==typeof t.type?w(t):null}function a(t){var n,i;if(null!=(t=t.i)&&null!=t.c){for(t.o=t.c.base=null,n=0;n<t.n.length;n++)if(null!=(i=t.n[n])&&null!=i.o){t.o=t.c.base=i.o;break}return a(t)}}function e(t){(!t.f&&(t.f=!0)&&1===s.push(t)||i!==m.debounceRendering)&&(i=m.debounceRendering,(m.debounceRendering||n)(u))}function u(){var t,n,i,r,e,u,o,l;for(s.sort(function(t,n){return n.d.e-t.d.e});t=s.pop();)t.f&&(r=i=void 0,u=(e=(n=t).d).o,o=n.p,l=n.u,n.u=!1,o&&(i=[],r=k(o,e,M({},e),n.w,void 0!==o.ownerSVGElement,null,i,l,null==u?w(e):u),d(i,e),r!=u&&a(e)))}function S(n,i,t,r,e,u,o,l,s){var c,a,f,h,v,d,g,b=t&&t.n||j,p=b.length;if(l==x&&(l=null!=u?u[0]:p?w(t,0):null),c=0,i.n=A(i.n,function(t){if(null!=t){if(t.i=i,t.e=i.e+1,null===(f=b[c])||f&&t.key==f.key&&t.type===f.type)b[c]=void 0;else for(a=0;a<p;a++){if((f=b[a])&&t.key==f.key&&t.type===f.type){b[a]=void 0;break}f=null}if(h=k(n,t,f=f||x,r,e,u,o,null,l,s),(a=t.ref)&&f.ref!=a&&(g=g||[]).push(a,t.c||h,t),null!=h){if(null==d&&(d=h),null!=t.l)h=t.l,t.l=null;else if(u==f||h!=l||null==h.parentNode){t:if(null==l||l.parentNode!==n)n.appendChild(h);else{for(v=l,a=0;(v=v.nextSibling)&&a<p;a+=2)if(v==h)break t;n.insertBefore(h,l)}"option"==i.type&&(n.value="")}l=h.nextSibling,"function"==typeof i.type&&(i.l=h)}}return c++,t}),i.o=d,null!=u&&"function"!=typeof i.type)for(c=u.length;c--;)null!=u[c]&&y(u[c]);for(c=p;c--;)null!=b[c]&&N(b[c],b[c]);if(g)for(c=0;c<g.length;c++)E(g[c],g[++c],g[++c])}function A(t,n,i){if(null==i&&(i=[]),null==t||"boolean"==typeof t)n&&i.push(n(null));else if(Array.isArray(t))for(var r=0;r<t.length;r++)A(t[r],n,i);else i.push(n?n(function(t){if(null==t||"boolean"==typeof t)return null;if("string"==typeof t||"number"==typeof t)return c(null,t,null,null);if(null==t.o&&null==t.c)return t;var n=c(t.type,t.props,t.key,null);return n.o=t.o,n}(t)):t);return i}function f(t,n,i){"-"===n[0]?t.setProperty(n,i):t[n]="number"==typeof i&&!1===r.test(n)?i+"px":null==i?"":i}function R(t,n,i,r,e){var u,o,l,s,c;if("key"===(n=e?"className"===n?"class":n:"class"===n?"className":n)||"children"===n);else if("style"===n)if(u=t.style,"string"==typeof i)u.cssText=i;else{if("string"==typeof r&&(u.cssText="",r=null),r)for(o in r)i&&o in i||f(u,o,"");if(i)for(l in i)r&&i[l]===r[l]||f(u,l,i[l])}else"o"===n[0]&&"n"===n[1]?(s=n!==(n=n.replace(/Capture$/,"")),n=((c=n.toLowerCase())in t?c:n).slice(2),i?(r||t.addEventListener(n,v,s),(t.t||(t.t={}))[n]=i):t.removeEventListener(n,v,s)):"list"!==n&&"tagName"!==n&&"form"!==n&&!e&&n in t?t[n]=null==i?"":i:"function"!=typeof i&&"dangerouslySetInnerHTML"!==n&&(n!==(n=n.replace(/^xlink:?/,""))?null==i||!1===i?t.removeAttributeNS("http://www.w3.org/1999/xlink",n.toLowerCase()):t.setAttributeNS("http://www.w3.org/1999/xlink",n.toLowerCase(),i):null==i||!1===i?t.removeAttribute(n):t.setAttribute(n,i))}function v(t){return this.t[t.type](m.event?m.event(t):t)}function k(t,n,i,r,e,u,o,l,s,c){var a,f,h,v,d,g,b,p,y,w,k=n.type;if(void 0!==n.constructor)return null;(a=m.e)&&a(n);try{t:if("function"==typeof k){if(p=n.props,y=(a=k.contextType)&&r[a.c],w=a?y?y.props.value:a.i:r,i.c?b=(f=n.c=i.c).i=f.k:("prototype"in k&&k.prototype.render?n.c=f=new k(p,w):(n.c=f=new I(p,w),f.constructor=k,f.render=z),y&&y.sub(f),f.props=p,f.state||(f.state={}),f.context=w,f.w=r,h=f.f=!0,f.m=[]),null==f.j&&(f.j=f.state),null!=k.getDerivedStateFromProps&&M(f.j==f.state?f.j=M({},f.j):f.j,k.getDerivedStateFromProps(p,f.j)),h)null==k.getDerivedStateFromProps&&null!=f.componentWillMount&&f.componentWillMount(),null!=f.componentDidMount&&o.push(f);else{if(null==k.getDerivedStateFromProps&&null==l&&null!=f.componentWillReceiveProps&&f.componentWillReceiveProps(p,w),!l&&null!=f.shouldComponentUpdate&&!1===f.shouldComponentUpdate(p,f.j,w)){for(f.props=p,f.state=f.j,f.f=!1,(f.d=n).o=null!=s?s!==i.o?s:i.o:null,n.n=i.n,a=0;a<n.n.length;a++)n.n[a]&&(n.n[a].i=n);break t}null!=f.componentWillUpdate&&f.componentWillUpdate(p,f.j,w)}for(v=f.props,d=f.state,f.context=w,f.props=p,f.state=f.j,(a=m.M)&&a(n),f.f=!1,f.d=n,f.p=t,a=f.render(f.props,f.state,f.context),n.n=A(null!=a&&a.type==O&&null==a.key?a.props.children:a),null!=f.getChildContext&&(r=M(M({},r),f.getChildContext())),h||null==f.getSnapshotBeforeUpdate||(g=f.getSnapshotBeforeUpdate(v,d)),S(t,n,i,r,e,u,o,s,c),f.base=n.o;a=f.m.pop();)f.j&&(f.state=f.j),a.call(f);h||null==v||null==f.componentDidUpdate||f.componentDidUpdate(v,d,g),b&&(f.k=f.i=null)}else n.o=function(t,n,i,r,e,u,o,l){var s,c,a,f,h=i.props,v=n.props;if(e="svg"===n.type||e,null==t&&null!=u)for(s=0;s<u.length;s++)if(null!=(c=u[s])&&(null===n.type?3===c.nodeType:c.localName===n.type)){t=c,u[s]=null;break}if(null==t){if(null===n.type)return document.createTextNode(v);t=e?document.createElementNS("http://www.w3.org/2000/svg",n.type):document.createElement(n.type),u=null}return null===n.type?h!==v&&(null!=u&&(u[u.indexOf(t)]=null),t.data=v):n!==i&&(null!=u&&(u=j.slice.call(t.childNodes)),a=(h=i.props||x).dangerouslySetInnerHTML,f=v.dangerouslySetInnerHTML,l||(f||a)&&(f&&a&&f.O==a.O||(t.innerHTML=f&&f.O||"")),function(t,n,i,r,e){var u;for(u in i)u in n||R(t,u,null,i[u],r);for(u in n)e&&"function"!=typeof n[u]||"value"===u||"checked"===u||i[u]===n[u]||R(t,u,n[u],i[u],r)}(t,v,h,e,l),n.n=n.props.children,f||S(t,n,i,r,"foreignObject"!==n.type&&e,u,o,x,l),l||("value"in v&&void 0!==v.value&&v.value!==t.value&&(t.value=null==v.value?"":v.value),"checked"in v&&void 0!==v.checked&&v.checked!==t.checked&&(t.checked=v.checked))),t}(i.o,n,i,r,e,u,o,c);(a=m.diffed)&&a(n)}catch(t){m.o(t,n,i)}return n.o}function d(t,n){for(var i;i=t.pop();)try{i.componentDidMount()}catch(t){m.o(t,i.d)}m.c&&m.c(n)}function E(t,n,i){try{"function"==typeof t?t(n):t.current=n}catch(t){m.o(t,i)}}function N(t,n,i){var r,e,u;if(m.unmount&&m.unmount(t),(r=t.ref)&&E(r,null,n),i||"function"==typeof t.type||(i=null!=(e=t.o)),t.o=t.l=null,null!=(r=t.c)){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(t){m.o(t,n)}r.base=r.p=null}if(r=t.n)for(u=0;u<r.length;u++)r[u]&&N(r[u],n,i);null!=e&&y(e)}function z(t,n,i){return this.constructor(t,i)}function g(t,n){for(var i=0;i<n.length;i++){var r=n[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function b(){return(b=Object.assign||function(t){for(var n=arguments,i=1;i<arguments.length;i++){var r=n[i];for(var e in r)Object.prototype.hasOwnProperty.call(r,e)&&(t[e]=r[e])}return t}).apply(this,arguments)}m={},I.prototype.setState=function(t,n){var i=this.j!==this.state&&this.j||(this.j=M({},this.state));"function"==typeof t&&!(t=t(i,this.props))||M(i,t),null!=t&&this.d&&(this.u=!1,n&&this.m.push(n),e(this))},I.prototype.forceUpdate=function(t){this.d&&(t&&this.m.push(t),this.u=!0,e(this))},I.prototype.render=O,s=[],n="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,i=m.debounceRendering,m.o=function(t,n,i){for(var r;n=n.i;)if((r=n.c)&&!r.i)try{if(r.constructor&&null!=r.constructor.getDerivedStateFromError)r.setState(r.constructor.getDerivedStateFromError(t));else{if(null==r.componentDidCatch)continue;r.componentDidCatch(t)}return e(r.k=r)}catch(n){t=n}throw t},o=x;var t="(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)",l="[\\s|\\(]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")\\s*\\)?",p="[\\s|\\(]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")\\s*\\)?",_=new RegExp("rgb"+l),H=new RegExp("rgba"+p),P=new RegExp("hsl"+l),$=new RegExp("hsla"+p),T="^(?:#?|0x?)",W="([0-9a-fA-F]{1})",C="([0-9a-fA-F]{2})",D=new RegExp(T+W+W+W+"$"),F=new RegExp(T+W+W+W+W+"$"),L=new RegExp(T+C+C+C+"$"),B=new RegExp(T+C+C+C+C+"$"),q=Math.log,G=Math.round,Z=Math.floor;function J(t,n,i){return Math.min(Math.max(t,n),i)}function K(t,n){var i=-1<t.indexOf("%"),r=parseFloat(t);return i?n/100*r:r}function Q(t){return parseInt(t,16)}function U(t){return t.toString(16).padStart(2,"0")}var V=function(){function l(t,n){this.$={h:0,s:0,v:0,a:1},t&&this.set(t),this.onChange=n,this.initialValue=b({},this.$)}var t=l.prototype;return t.set=function(t){if("string"==typeof t)/^(?:#?|0x?)[0-9a-fA-F]{3,8}$/.test(t)?this.hexString=t:/^rgba?/.test(t)?this.rgbString=t:/^hsla?/.test(t)&&(this.hslString=t);else{if("object"!=typeof t)throw new Error("Invalid color value");t instanceof l?this.hsva=t.hsva:"r"in t&&"g"in t&&"b"in t?this.rgb=t:"h"in t&&"s"in t&&"v"in t?this.hsv=t:"h"in t&&"s"in t&&"l"in t?this.hsl=t:"kelvin"in t&&(this.kelvin=t.kelvin)}},t.setChannel=function(t,n,i){var r;this[t]=b({},this[t],((r={})[n]=i,r))},t.reset=function(){this.hsva=this.initialValue},t.clone=function(){return new l(this)},t.unbind=function(){this.onChange=void 0},l.hsvToRgb=function(t){var n=t.h/60,i=t.s/100,r=t.v/100,e=Z(n),u=n-e,o=r*(1-i),l=r*(1-u*i),s=r*(1-(1-u)*i),c=e%6,a=[s,r,r,l,o,o][c],f=[o,o,s,r,r,l][c];return{r:J(255*[r,l,o,o,s,r][c],0,255),g:J(255*a,0,255),b:J(255*f,0,255)}},l.rgbToHsv=function(t){var n=t.r/255,i=t.g/255,r=t.b/255,e=Math.max(n,i,r),u=Math.min(n,i,r),o=e-u,l=0,s=e,c=0===e?0:o/e;switch(e){case u:l=0;break;case n:l=(i-r)/o+(i<r?6:0);break;case i:l=(r-n)/o+2;break;case r:l=(n-i)/o+4}return{h:60*l%360,s:J(100*c,0,100),v:J(100*s,0,100)}},l.hsvToHsl=function(t){var n=t.s/100,i=t.v/100,r=(2-n)*i,e=r<=1?r:2-r,u=e<1e-9?0:n*i/e;return{h:t.h,s:J(100*u,0,100),l:J(50*r,0,100)}},l.hslToHsv=function(t){var n=2*t.l,i=t.s*(n<=100?n:200-n)/100,r=n+i<1e-9?0:2*i/(n+i);return{h:t.h,s:J(100*r,0,100),v:J((n+i)/2,0,100)}},l.kelvinToRgb=function(t){var n,i,r,e=t/100;return r=e<66?(n=255,i=-155.25485562709179-.44596950469579133*(i=e-2)+104.49216199393888*q(i),e<20?0:.8274096064007395*(r=e-10)-254.76935184120902+115.67994401066147*q(r)):(n=351.97690566805693+.114206453784165*(n=e-55)-40.25366309332127*q(n),i=325.4494125711974+.07943456536662342*(i=e-50)-28.0852963507957*q(i),255),{r:J(Z(n),0,255),g:J(Z(i),0,255),b:J(Z(r),0,255)}},l.rgbToKelvin=function(t){for(var n,i=t.r,r=t.b,e=2e3,u=4e4;.4<u-e;){var o=l.kelvinToRgb(n=.5*(u+e));o.b/o.r>=r/i?u=n:e=n}return n},function(t,n,i){n&&g(t.prototype,n),i&&g(t,i)}(l,[{key:"hsv",get:function(){var t=this.$;return{h:t.h,s:t.s,v:t.v}},set:function(t){var n=this.$;if(t=b({},n,t),this.onChange){var i={h:!1,v:!1,s:!1,a:!1};for(var r in n)i[r]=t[r]!=n[r];this.$=t,(i.h||i.s||i.v||i.a)&&this.onChange(this,i)}else this.$=t}},{key:"hsva",get:function(){return b({},this.$)},set:function(t){this.hsv=t}},{key:"hue",get:function(){return this.$.h},set:function(t){this.hsv={h:t}}},{key:"saturation",get:function(){return this.$.s},set:function(t){this.hsv={s:t}}},{key:"value",get:function(){return this.$.v},set:function(t){this.hsv={v:t}}},{key:"alpha",get:function(){return this.$.a},set:function(t){this.hsv=b({},this.hsv,{a:t})}},{key:"kelvin",get:function(){return l.rgbToKelvin(this.rgb)},set:function(t){this.rgb=l.kelvinToRgb(t)}},{key:"red",get:function(){return this.rgb.r},set:function(t){this.rgb=b({},this.rgb,{r:t})}},{key:"green",get:function(){return this.rgb.g},set:function(t){this.rgb=b({},this.rgb,{g:t})}},{key:"blue",get:function(){return this.rgb.b},set:function(t){this.rgb=b({},this.rgb,{b:t})}},{key:"rgb",get:function(){var t=l.hsvToRgb(this.$),n=t.r,i=t.g,r=t.b;return{r:G(n),g:G(i),b:G(r)}},set:function(t){this.hsv=b({},l.rgbToHsv(t),{a:void 0===t.a?1:t.a})}},{key:"rgba",get:function(){return b({},this.rgb,{a:this.alpha})},set:function(t){this.rgb=t}},{key:"hsl",get:function(){var t=l.hsvToHsl(this.$),n=t.h,i=t.s,r=t.l;return{h:G(n),s:G(i),l:G(r)}},set:function(t){this.hsv=b({},l.hslToHsv(t),{a:void 0===t.a?1:t.a})}},{key:"hsla",get:function(){return b({},this.hsl,{a:this.alpha})},set:function(t){this.hsl=t}},{key:"rgbString",get:function(){var t=this.rgb;return"rgb("+t.r+", "+t.g+", "+t.b+")"},set:function(t){var n,i,r,e,u=1;if((n=_.exec(t))?(i=K(n[1],255),r=K(n[2],255),e=K(n[3],255)):(n=H.exec(t))&&(i=K(n[1],255),r=K(n[2],255),e=K(n[3],255),u=K(n[4],1)),!n)throw new Error("Invalid rgb string");this.rgb={r:i,g:r,b:e,a:u}}},{key:"rgbaString",get:function(){var t=this.rgba;return"rgba("+t.r+", "+t.g+", "+t.b+", "+t.a+")"},set:function(t){this.rgbString=t}},{key:"hexString",get:function(){var t=this.rgb;return"#"+U(t.r)+U(t.g)+U(t.b)},set:function(t){var n,i,r,e,u=255;if((n=D.exec(t))?(i=17*Q(n[1]),r=17*Q(n[2]),e=17*Q(n[3])):(n=F.exec(t))?(i=17*Q(n[1]),r=17*Q(n[2]),e=17*Q(n[3]),u=17*Q(n[4])):(n=L.exec(t))?(i=Q(n[1]),r=Q(n[2]),e=Q(n[3])):(n=B.exec(t))&&(i=Q(n[1]),r=Q(n[2]),e=Q(n[3]),u=Q(n[4])),!n)throw new Error("Invalid hex string");this.rgb={r:i,g:r,b:e,a:u/255}}},{key:"hex8String",get:function(){var t=this.rgba;return"#"+U(t.r)+U(t.g)+U(t.b)+U(Z(255*t.a))},set:function(t){this.hexString=t}},{key:"hslString",get:function(){var t=this.hsl;return"hsl("+t.h+", "+t.s+"%, "+t.l+"%)"},set:function(t){var n,i,r,e,u=1;if((n=P.exec(t))?(i=K(n[1],360),r=K(n[2],100),e=K(n[3],100)):(n=$.exec(t))&&(i=K(n[1],360),r=K(n[2],100),e=K(n[3],100),u=K(n[4],1)),!n)throw new Error("Invalid hsl string");this.hsl={h:i,s:r,l:e,a:u}}},{key:"hslaString",get:function(){var t=this.hsla;return"hsla("+t.h+", "+t.s+"%, "+t.l+"%, "+t.a+")"},set:function(t){this.hslString=t}}]),l}();function X(t){var n,i=t.width,r=t.sliderSize,e=t.borderWidth,u=t.handleRadius,o=t.padding,l=t.sliderShape,s="horizontal"===t.layoutDirection;return r=null!=(n=r)?n:2*o+2*u,"circle"===l?{handleStart:t.padding+t.handleRadius,handleRange:i-2*o-2*u,width:i,height:i,cx:i/2,cy:i/2,radius:i/2-e/2}:{handleStart:r/2,handleRange:i-r,radius:r/2,x:0,y:0,width:s?r:i,height:s?i:r}}function Y(t,n){var i=X(t),r=i.width,e=i.height,u=i.handleRange,o=i.handleStart,l="horizontal"===t.layoutDirection,s=l?r/2:e/2,c=o+function(t,n){var i=n.hsva,r=n.rgb;switch(t.sliderType){case"red":return r.r/2.55;case"green":return r.g/2.55;case"blue":return r.b/2.55;case"alpha":return 100*i.a;case"kelvin":var e=t.minTemperature,u=t.maxTemperature-e,o=(n.kelvin-e)/u*100;return Math.max(0,Math.min(o,100));case"hue":return i.h/=3.6;case"saturation":return i.s;case"value":default:return i.v}}(t,n)/100*u;return l&&(c=-1*c+u+2*o),{x:l?s:c,y:l?c:s}}var tt,nt=2*Math.PI,it=function(t,n){return(t%n+n)%n},rt=function(t,n){return Math.sqrt(t*t+n*n)};function et(t){return t.width/2-t.padding-t.handleRadius-t.borderWidth}function ut(t){var n=t.width/2;return{width:t.width,radius:n-t.borderWidth,cx:n,cy:n}}function ot(t,n,i){var r=t.wheelAngle,e=t.wheelDirection;return i&&"clockwise"===e?n=r+n:"clockwise"===e?n=360-r+n:i&&"anticlockwise"===e?n=r+180-n:"anticlockwise"===e&&(n=r-n),it(n,360)}function lt(t,n,i){var r=ut(t),e=r.cx,u=r.cy,o=et(t);n=e-n,i=u-i;var l=ot(t,Math.atan2(-i,-n)*(360/nt)),s=Math.min(rt(n,i),o);return{h:Math.round(l),s:Math.round(100/o*s)}}function st(t){var n=t.width,i=t.boxHeight;return{width:n,height:null!=i?i:n,radius:t.padding+t.handleRadius}}function ct(t,n,i){var r=st(t),e=r.width,u=r.height,o=r.radius,l=(n-o)/(e-2*o)*100,s=(i-o)/(u-2*o)*100;return{s:Math.max(0,Math.min(l,100)),v:Math.max(0,Math.min(100-s,100))}}function at(t,n,i,r){for(var e=0;e<r.length;e++){var u=r[e].x-n,o=r[e].y-i;if(Math.sqrt(u*u+o*o)<t.handleRadius)return e}return null}function ft(t){return{boxSizing:"border-box",border:t.borderWidth+"px solid "+t.borderColor}}function ht(t,n,i){return t+"-gradient("+n+", "+i.map(function(t){var n=t[0];return t[1]+" "+n+"%"}).join(",")+")"}function vt(t){return"string"==typeof t?t:t+"px"}var dt=["mousemove","touchmove","mouseup","touchend"],gt=function(n){function t(t){n.call(this,t),this.uid=(Math.random()+1).toString(36).substring(5)}return n&&(t.__proto__=n),((t.prototype=Object.create(n&&n.prototype)).constructor=t).prototype.render=function(t){var n=this.handleEvent.bind(this),i={onMouseDown:n,ontouchstart:n},r="horizontal"===t.layoutDirection,e=null===t.margin?t.sliderMargin:t.margin,u={overflow:"visible",display:r?"inline-block":"block"};return 0<t.index&&(u[r?"marginLeft":"marginTop"]=e),h(O,null,t.children(this.uid,i,u))},t.prototype.handleEvent=function(t){var n=this,i=this.props.onInput,r=this.base.getBoundingClientRect();t.preventDefault();var e=t.touches?t.changedTouches[0]:t,u=e.clientX-r.left,o=e.clientY-r.top;switch(t.type){case"mousedown":case"touchstart":!1!==i(u,o,0)&&dt.forEach(function(t){document.addEventListener(t,n,{passive:!1})});break;case"mousemove":case"touchmove":i(u,o,1);break;case"mouseup":case"touchend":i(u,o,2),dt.forEach(function(t){document.removeEventListener(t,n,{passive:!1})})}},t}(I);function bt(t){var n=t.r,i=t.url,r=n,e=n;return h("svg",{className:"IroHandle IroHandle--"+t.index+" "+(t.isActive?"IroHandle--isActive":""),style:{"-webkit-tap-highlight-color":"rgba(0, 0, 0, 0);",transform:"translate("+vt(t.x)+", "+vt(t.y)+")",willChange:"transform",top:vt(-n),left:vt(-n),width:vt(2*n),height:vt(2*n),position:"absolute",overflow:"visible"}},i&&h("use",Object.assign({xlinkHref:function(t){tt=tt||document.getElementsByTagName("base");var n=window.navigator.userAgent,i=/^((?!chrome|android).)*safari/i.test(n),r=/iPhone|iPod|iPad/i.test(n),e=window.location;return(i||r)&&0<tt.length?e.protocol+"//"+e.host+e.pathname+e.search+t:t}(i)},t.props)),!i&&h("circle",{cx:r,cy:e,r:n,fill:"none","stroke-width":2,stroke:"#000"}),!i&&h("circle",{cx:r,cy:e,r:n-2,fill:t.fill,"stroke-width":2,stroke:"#fff"}))}function pt(e){var t=e.activeIndex,u=void 0!==t&&t<e.colors.length?e.colors[t]:e.color,n=X(e),r=n.width,o=n.height,l=n.radius,s=Y(e,u),c=function(t,n){var i=n.hsv,r=n.rgb;switch(t.sliderType){case"red":return[[0,"rgb(0,"+r.g+","+r.b+")"],[100,"rgb(255,"+r.g+","+r.b+")"]];case"green":return[[0,"rgb("+r.r+",0,"+r.b+")"],[100,"rgb("+r.r+",255,"+r.b+")"]];case"blue":return[[0,"rgb("+r.r+","+r.g+",0)"],[100,"rgb("+r.r+","+r.g+",255)"]];case"alpha":return[[0,"rgba("+r.r+","+r.g+","+r.b+",0)"],[100,"rgb("+r.r+","+r.g+","+r.b+")"]];case"kelvin":for(var e=[],u=t.minTemperature,o=t.maxTemperature,l=o-u,s=u,c=0;s<o;s+=l/8,c+=1){var a=V.kelvinToRgb(s),f=a.r,h=a.g,v=a.b;e.push([12.5*c,"rgb("+f+","+h+","+v+")"])}return e;case"hue":return[[0,"#f00"],[16.666,"#ff0"],[33.333,"#0f0"],[50,"#0ff"],[66.666,"#00f"],[83.333,"#f0f"],[100,"#f00"]];case"saturation":var d=V.hsvToHsl({h:i.h,s:0,v:i.v}),g=V.hsvToHsl({h:i.h,s:100,v:i.v});return[[0,"hsl("+d.h+","+d.s+"%,"+d.l+"%)"],[100,"hsl("+g.h+","+g.s+"%,"+g.l+"%)"]];case"value":default:var b=V.hsvToHsl({h:i.h,s:i.s,v:100});return[[0,"#000"],[100,"hsl("+b.h+","+b.s+"%,"+b.l+"%)"]]}}(e,u);return h(gt,Object.assign({},e,{onInput:function(t,n,i){var r=function(t,n,i){var r,e=X(t),u=e.handleRange,o=e.handleStart;r="horizontal"===t.layoutDirection?-1*i+u+o:n-o,r=Math.max(Math.min(r,u),0);var l=Math.round(100/u*r);switch(t.sliderType){case"kelvin":var s=t.minTemperature;return s+l/100*(t.maxTemperature-s);case"alpha":return l/100;case"hue":return 3.6*l;case"red":case"blue":case"green":return 2.55*l;default:return l}}(e,t,n);e.parent.inputActive=!0,u[e.sliderType]=r,e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroSlider",style:Object.assign({},{position:"relative",width:vt(r),height:vt(o),borderRadius:vt(l),background:"conic-gradient(#ccc 25%, #fff 0 50%, #ccc 0 75%, #fff 0)",backgroundSize:"8px 8px"},i)}),h("div",{className:"IroSliderGradient",style:Object.assign({},{position:"absolute",top:0,left:0,width:"100%",height:"100%",borderRadius:vt(l),background:ht("linear","horizontal"===e.layoutDirection?"to top":"to right",c)},ft(e))}),h(bt,{isActive:!0,index:u.index,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:s.x,y:s.y}))})}function yt(e){var t=st(e),r=t.width,u=t.height,o=t.radius,l=e.colors,s=e.parent,n=e.activeIndex,c=void 0!==n&&n<e.colors.length?e.colors[n]:e.color,a=function(t,n){return[[[0,"#fff"],[100,"hsl("+n.hue+",100%,50%)"]],[[0,"rgba(0,0,0,0)"],[100,"#000"]]]}(0,c),f=l.map(function(t){return function(t,n){var i=st(t),r=i.width,e=i.height,u=i.radius,o=n.hsv,l=u,s=r-2*u,c=e-2*u;return{x:l+o.s/100*s,y:l+(c-o.v/100*c)}}(e,t)});return h(gt,Object.assign({},e,{onInput:function(t,n,i){if(0===i){var r=at(e,t,n,f);null!==r?s.setActiveColor(r):(s.inputActive=!0,c.hsv=ct(e,t,n),e.onInput(i,e.id))}else 1===i&&(s.inputActive=!0,c.hsv=ct(e,t,n));e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroBox",style:Object.assign({},{width:vt(r),height:vt(u),position:"relative"},i)}),h("div",{className:"IroBox",style:Object.assign({},{width:"100%",height:"100%",borderRadius:vt(o)},ft(e),{background:ht("linear","to bottom",a[1])+","+ht("linear","to right",a[0])})}),l.filter(function(t){return t!==c}).map(function(t){return h(bt,{isActive:!1,index:t.index,fill:t.hslString,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:f[t.index].x,y:f[t.index].y})}),h(bt,{isActive:!0,index:c.index,fill:c.hslString,r:e.activeHandleRadius||e.handleRadius,url:e.handleSvg,props:e.handleProps,x:f[c.index].x,y:f[c.index].y}))})}bt.defaultProps={fill:"none",x:0,y:0,r:8,url:null,props:{x:0,y:0}},pt.defaultProps=Object.assign({},{sliderShape:"bar",sliderType:"value",minTemperature:2200,maxTemperature:11e3});function wt(e){var r=ut(e).width,u=e.colors,o=(e.borderWidth,e.parent),l=e.color,s=l.hsv,c=u.map(function(t){return function(t,n){var i=n.hsv,r=ut(t),e=r.cx,u=r.cy,o=et(t),l=(180+ot(t,i.h,!0))*(nt/360),s=i.s/100*o,c="clockwise"===t.wheelDirection?-1:1;return{x:e+s*Math.cos(l)*c,y:u+s*Math.sin(l)*c}}(e,t)}),a={position:"absolute",top:0,left:0,width:"100%",height:"100%",borderRadius:"50%",boxSizing:"border-box"};return h(gt,Object.assign({},e,{onInput:function(t,n,i){if(0===i){if(!function(t,n,i){var r=ut(t),e=r.cx,u=r.cy,o=t.width/2;return rt(e-n,u-i)<o}(e,t,n))return!1;var r=at(e,t,n,c);null!==r?o.setActiveColor(r):(o.inputActive=!0,l.hsv=lt(e,t,n),e.onInput(i,e.id))}else 1===i&&(o.inputActive=!0,l.hsv=lt(e,t,n));e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroWheel",style:Object.assign({},{width:vt(r),height:vt(r),position:"relative"},i)}),h("div",{className:"IroWheelHue",style:Object.assign({},a,{transform:"rotateZ("+(e.wheelAngle+90)+"deg)",background:"clockwise"===e.wheelDirection?"conic-gradient(red, yellow, lime, aqua, blue, magenta, red)":"conic-gradient(red, magenta, blue, aqua, lime, yellow, red)"})}),h("div",{className:"IroWheelSaturation",style:Object.assign({},a,{background:"radial-gradient(circle closest-side, #fff, transparent)"})}),e.wheelLightness&&h("div",{className:"IroWheelLightness",style:Object.assign({},a,{background:"#000",opacity:1-s.v/100})}),h("div",{className:"IroWheelBorder",style:Object.assign({},a,ft(e))}),u.filter(function(t){return t!==l}).map(function(t){return h(bt,{isActive:!1,index:t.index,fill:t.hslString,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:c[t.index].x,y:c[t.index].y})}),h(bt,{isActive:!0,index:l.index,fill:l.hslString,r:e.activeHandleRadius||e.handleRadius,url:e.handleSvg,props:e.handleProps,x:c[l.index].x,y:c[l.index].y}))})}var kt=function(i){function t(t){var n=this;i.call(this,t),this.colors=[],this.inputActive=!1,this.events={},this.activeEvents={},this.deferredEvents={},this.id=t.id,(0<t.colors.length?t.colors:[t.color]).forEach(function(t){return n.addColor(t)}),this.setActiveColor(0),this.state=Object.assign({},t,{color:this.color,colors:this.colors,layout:t.layout})}return i&&(t.__proto__=i),((t.prototype=Object.create(i&&i.prototype)).constructor=t).prototype.addColor=function(t,n){void 0===n&&(n=this.colors.length);var i=new V(t,this.onColorChange.bind(this));this.colors.splice(n,0,i),this.colors.forEach(function(t,n){return t.index=n}),this.state&&this.setState({colors:this.colors}),this.deferredEmit("color:init",i)},t.prototype.removeColor=function(t){var n=this.colors.splice(t,1)[0];n.unbind(),this.colors.forEach(function(t,n){return t.index=n}),this.state&&this.setState({colors:this.colors}),n.index===this.color.index&&this.setActiveColor(0),this.emit("color:remove",n)},t.prototype.setActiveColor=function(t){this.color=this.colors[t],this.state&&this.setState({color:this.color}),this.emit("color:setActive",this.color)},t.prototype.setColors=function(t,n){var i=this;void 0===n&&(n=0),this.colors.forEach(function(t){return t.unbind()}),this.colors=[],t.forEach(function(t){return i.addColor(t)}),this.setActiveColor(n),this.emit("color:setAll",this.colors)},t.prototype.on=function(t,n){var i=this,r=this.events;(Array.isArray(t)?t:[t]).forEach(function(t){(r[t]||(r[t]=[])).push(n),i.deferredEvents[t]&&(i.deferredEvents[t].forEach(function(t){n.apply(null,t)}),i.deferredEvents[t]=[])})},t.prototype.off=function(t,i){var r=this;(Array.isArray(t)?t:[t]).forEach(function(t){var n=r.events[t];n&&n.splice(n.indexOf(i),1)})},t.prototype.emit=function(t){for(var n=this,i=[],r=arguments.length-1;0<r--;)i[r]=arguments[r+1];var e=this.activeEvents;!!e.hasOwnProperty(t)&&e[t]||(e[t]=!0,(this.events[t]||[]).forEach(function(t){return t.apply(n,i)}),e[t]=!1)},t.prototype.deferredEmit=function(t){for(var n,i=[],r=arguments.length-1;0<r--;)i[r]=arguments[r+1];var e=this.deferredEvents;(n=this).emit.apply(n,[t].concat(i)),(e[t]||(e[t]=[])).push(i)},t.prototype.setOptions=function(t){this.setState(t)},t.prototype.resize=function(t){this.setOptions({width:t})},t.prototype.reset=function(){this.colors.forEach(function(t){return t.reset()}),this.setState({colors:this.colors})},t.prototype.onMount=function(t){this.el=t,this.deferredEmit("mount",this)},t.prototype.onColorChange=function(t,n){this.setState({color:this.color}),this.inputActive&&(this.inputActive=!1,this.emit("input:change",t,n)),this.emit("color:change",t,n)},t.prototype.emitInputEvent=function(t,n){0===t?this.emit("input:start",this.color,n):1===t?this.emit("input:move",this.color,n):2===t&&this.emit("input:end",this.color,n)},t.prototype.render=function(t,e){var u=this,n=e.layout;return Array.isArray(n)||(n=[{component:wt},{component:pt}],e.transparency&&n.push({component:pt,options:{sliderType:"alpha"}})),h("div",{class:"IroColorPicker",id:e.id,style:{display:e.display}},n.map(function(t,n){var i=t.component,r=t.options;return h(i,Object.assign({},e,r,{ref:void 0,onInput:u.emitInputEvent.bind(u),parent:u,index:n}))}))},t}(I);kt.defaultProps=Object.assign({},{width:300,height:300,color:"#fff",colors:[],padding:6,layoutDirection:"vertical",borderColor:"#fff",borderWidth:0,handleRadius:8,activeHandleRadius:null,handleSvg:null,handleProps:{x:0,y:0},wheelLightness:!0,wheelAngle:0,wheelDirection:"anticlockwise",sliderSize:null,sliderMargin:12,boxHeight:null},{colors:[],display:"block",id:null,layout:"default",margin:null});var mt,xt,jt,Mt,Ot=(It.prototype=(mt=kt).prototype,Object.assign(It,mt),It.I=mt,It);function It(n,t){var i,r=document.createElement("div");function e(){var t=n instanceof Element?n:document.querySelector(n);t.appendChild(i.base),i.onMount(t)}return function(t,n,i){var r,e,u;m.i&&m.i(t,n),e=(r=i===o)?null:i&&i.n||n.n,t=h(O,null,[t]),u=[],k(n,r?n.n=t:(i||n).n=t,e||x,x,void 0!==n.ownerSVGElement,i&&!r?[i]:e?null:j.slice.call(n.childNodes),u,!1,i||x,r),d(u,t)}(h(mt,Object.assign({},{ref:function(t){return i=t}},t)),r),"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e),i}return(jt=xt=xt||{}).version="5.5.2",jt.Color=V,jt.ColorPicker=Ot,(Mt=jt.ui||(jt.ui={})).h=h,Mt.ComponentBase=gt,Mt.Handle=bt,Mt.Slider=pt,Mt.Wheel=wt,Mt.Box=yt,xt});
1
+ /*!
2
+ * iro.js v5.5.2
3
+ * 2016-2021 James Daniel
4
+ * Licensed under MPL 2.0
5
+ * github.com/jaames/iro.js
6
+ */
7
+ !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).iro=n()}(this,function(){"use strict";var m,s,n,i,o,x={},j=[],r=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|^--/i;function M(t,n){for(var i in n)t[i]=n[i];return t}function y(t){var n=t.parentNode;n&&n.removeChild(t)}function h(t,n,i){var r,e,u,o,l=arguments;if(n=M({},n),3<arguments.length)for(i=[i],r=3;r<arguments.length;r++)i.push(l[r]);if(null!=i&&(n.children=i),null!=t&&null!=t.defaultProps)for(e in t.defaultProps)void 0===n[e]&&(n[e]=t.defaultProps[e]);return o=n.key,null!=(u=n.ref)&&delete n.ref,null!=o&&delete n.key,c(t,n,o,u)}function c(t,n,i,r){var e={type:t,props:n,key:i,ref:r,n:null,i:null,e:0,o:null,l:null,c:null,constructor:void 0};return m.vnode&&m.vnode(e),e}function O(t){return t.children}function I(t,n){this.props=t,this.context=n}function w(t,n){if(null==n)return t.i?w(t.i,t.i.n.indexOf(t)+1):null;for(var i;n<t.n.length;n++)if(null!=(i=t.n[n])&&null!=i.o)return i.o;return"function"==typeof t.type?w(t):null}function a(t){var n,i;if(null!=(t=t.i)&&null!=t.c){for(t.o=t.c.base=null,n=0;n<t.n.length;n++)if(null!=(i=t.n[n])&&null!=i.o){t.o=t.c.base=i.o;break}return a(t)}}function e(t){(!t.f&&(t.f=!0)&&1===s.push(t)||i!==m.debounceRendering)&&(i=m.debounceRendering,(m.debounceRendering||n)(u))}function u(){var t,n,i,r,e,u,o,l;for(s.sort(function(t,n){return n.d.e-t.d.e});t=s.pop();)t.f&&(r=i=void 0,u=(e=(n=t).d).o,o=n.p,l=n.u,n.u=!1,o&&(i=[],r=k(o,e,M({},e),n.w,void 0!==o.ownerSVGElement,null,i,l,null==u?w(e):u),d(i,e),r!=u&&a(e)))}function S(n,i,t,r,e,u,o,l,s){var c,a,f,h,v,d,g,b=t&&t.n||j,p=b.length;if(l==x&&(l=null!=u?u[0]:p?w(t,0):null),c=0,i.n=A(i.n,function(t){if(null!=t){if(t.i=i,t.e=i.e+1,null===(f=b[c])||f&&t.key==f.key&&t.type===f.type)b[c]=void 0;else for(a=0;a<p;a++){if((f=b[a])&&t.key==f.key&&t.type===f.type){b[a]=void 0;break}f=null}if(h=k(n,t,f=f||x,r,e,u,o,null,l,s),(a=t.ref)&&f.ref!=a&&(g=g||[]).push(a,t.c||h,t),null!=h){if(null==d&&(d=h),null!=t.l)h=t.l,t.l=null;else if(u==f||h!=l||null==h.parentNode){t:if(null==l||l.parentNode!==n)n.appendChild(h);else{for(v=l,a=0;(v=v.nextSibling)&&a<p;a+=2)if(v==h)break t;n.insertBefore(h,l)}"option"==i.type&&(n.value="")}l=h.nextSibling,"function"==typeof i.type&&(i.l=h)}}return c++,t}),i.o=d,null!=u&&"function"!=typeof i.type)for(c=u.length;c--;)null!=u[c]&&y(u[c]);for(c=p;c--;)null!=b[c]&&N(b[c],b[c]);if(g)for(c=0;c<g.length;c++)E(g[c],g[++c],g[++c])}function A(t,n,i){if(null==i&&(i=[]),null==t||"boolean"==typeof t)n&&i.push(n(null));else if(Array.isArray(t))for(var r=0;r<t.length;r++)A(t[r],n,i);else i.push(n?n(function(t){if(null==t||"boolean"==typeof t)return null;if("string"==typeof t||"number"==typeof t)return c(null,t,null,null);if(null==t.o&&null==t.c)return t;var n=c(t.type,t.props,t.key,null);return n.o=t.o,n}(t)):t);return i}function f(t,n,i){"-"===n[0]?t.setProperty(n,i):t[n]="number"==typeof i&&!1===r.test(n)?i+"px":null==i?"":i}function R(t,n,i,r,e){var u,o,l,s,c;if("key"===(n=e?"className"===n?"class":n:"class"===n?"className":n)||"children"===n);else if("style"===n)if(u=t.style,"string"==typeof i)u.cssText=i;else{if("string"==typeof r&&(u.cssText="",r=null),r)for(o in r)i&&o in i||f(u,o,"");if(i)for(l in i)r&&i[l]===r[l]||f(u,l,i[l])}else"o"===n[0]&&"n"===n[1]?(s=n!==(n=n.replace(/Capture$/,"")),n=((c=n.toLowerCase())in t?c:n).slice(2),i?(r||t.addEventListener(n,v,s),(t.t||(t.t={}))[n]=i):t.removeEventListener(n,v,s)):"list"!==n&&"tagName"!==n&&"form"!==n&&!e&&n in t?t[n]=null==i?"":i:"function"!=typeof i&&"dangerouslySetInnerHTML"!==n&&(n!==(n=n.replace(/^xlink:?/,""))?null==i||!1===i?t.removeAttributeNS("http://www.w3.org/1999/xlink",n.toLowerCase()):t.setAttributeNS("http://www.w3.org/1999/xlink",n.toLowerCase(),i):null==i||!1===i?t.removeAttribute(n):t.setAttribute(n,i))}function v(t){return this.t[t.type](m.event?m.event(t):t)}function k(t,n,i,r,e,u,o,l,s,c){var a,f,h,v,d,g,b,p,y,w,k=n.type;if(void 0!==n.constructor)return null;(a=m.e)&&a(n);try{t:if("function"==typeof k){if(p=n.props,y=(a=k.contextType)&&r[a.c],w=a?y?y.props.value:a.i:r,i.c?b=(f=n.c=i.c).i=f.k:("prototype"in k&&k.prototype.render?n.c=f=new k(p,w):(n.c=f=new I(p,w),f.constructor=k,f.render=z),y&&y.sub(f),f.props=p,f.state||(f.state={}),f.context=w,f.w=r,h=f.f=!0,f.m=[]),null==f.j&&(f.j=f.state),null!=k.getDerivedStateFromProps&&M(f.j==f.state?f.j=M({},f.j):f.j,k.getDerivedStateFromProps(p,f.j)),h)null==k.getDerivedStateFromProps&&null!=f.componentWillMount&&f.componentWillMount(),null!=f.componentDidMount&&o.push(f);else{if(null==k.getDerivedStateFromProps&&null==l&&null!=f.componentWillReceiveProps&&f.componentWillReceiveProps(p,w),!l&&null!=f.shouldComponentUpdate&&!1===f.shouldComponentUpdate(p,f.j,w)){for(f.props=p,f.state=f.j,f.f=!1,(f.d=n).o=null!=s?s!==i.o?s:i.o:null,n.n=i.n,a=0;a<n.n.length;a++)n.n[a]&&(n.n[a].i=n);break t}null!=f.componentWillUpdate&&f.componentWillUpdate(p,f.j,w)}for(v=f.props,d=f.state,f.context=w,f.props=p,f.state=f.j,(a=m.M)&&a(n),f.f=!1,f.d=n,f.p=t,a=f.render(f.props,f.state,f.context),n.n=A(null!=a&&a.type==O&&null==a.key?a.props.children:a),null!=f.getChildContext&&(r=M(M({},r),f.getChildContext())),h||null==f.getSnapshotBeforeUpdate||(g=f.getSnapshotBeforeUpdate(v,d)),S(t,n,i,r,e,u,o,s,c),f.base=n.o;a=f.m.pop();)f.j&&(f.state=f.j),a.call(f);h||null==v||null==f.componentDidUpdate||f.componentDidUpdate(v,d,g),b&&(f.k=f.i=null)}else n.o=function(t,n,i,r,e,u,o,l){var s,c,a,f,h=i.props,v=n.props;if(e="svg"===n.type||e,null==t&&null!=u)for(s=0;s<u.length;s++)if(null!=(c=u[s])&&(null===n.type?3===c.nodeType:c.localName===n.type)){t=c,u[s]=null;break}if(null==t){if(null===n.type)return document.createTextNode(v);t=e?document.createElementNS("http://www.w3.org/2000/svg",n.type):document.createElement(n.type),u=null}return null===n.type?h!==v&&(null!=u&&(u[u.indexOf(t)]=null),t.data=v):n!==i&&(null!=u&&(u=j.slice.call(t.childNodes)),a=(h=i.props||x).dangerouslySetInnerHTML,f=v.dangerouslySetInnerHTML,l||(f||a)&&(f&&a&&f.O==a.O||(t.innerHTML=f&&f.O||"")),function(t,n,i,r,e){var u;for(u in i)u in n||R(t,u,null,i[u],r);for(u in n)e&&"function"!=typeof n[u]||"value"===u||"checked"===u||i[u]===n[u]||R(t,u,n[u],i[u],r)}(t,v,h,e,l),n.n=n.props.children,f||S(t,n,i,r,"foreignObject"!==n.type&&e,u,o,x,l),l||("value"in v&&void 0!==v.value&&v.value!==t.value&&(t.value=null==v.value?"":v.value),"checked"in v&&void 0!==v.checked&&v.checked!==t.checked&&(t.checked=v.checked))),t}(i.o,n,i,r,e,u,o,c);(a=m.diffed)&&a(n)}catch(t){m.o(t,n,i)}return n.o}function d(t,n){for(var i;i=t.pop();)try{i.componentDidMount()}catch(t){m.o(t,i.d)}m.c&&m.c(n)}function E(t,n,i){try{"function"==typeof t?t(n):t.current=n}catch(t){m.o(t,i)}}function N(t,n,i){var r,e,u;if(m.unmount&&m.unmount(t),(r=t.ref)&&E(r,null,n),i||"function"==typeof t.type||(i=null!=(e=t.o)),t.o=t.l=null,null!=(r=t.c)){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(t){m.o(t,n)}r.base=r.p=null}if(r=t.n)for(u=0;u<r.length;u++)r[u]&&N(r[u],n,i);null!=e&&y(e)}function z(t,n,i){return this.constructor(t,i)}function g(t,n){for(var i=0;i<n.length;i++){var r=n[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function b(){return(b=Object.assign||function(t){for(var n=arguments,i=1;i<arguments.length;i++){var r=n[i];for(var e in r)Object.prototype.hasOwnProperty.call(r,e)&&(t[e]=r[e])}return t}).apply(this,arguments)}m={},I.prototype.setState=function(t,n){var i=this.j!==this.state&&this.j||(this.j=M({},this.state));"function"==typeof t&&!(t=t(i,this.props))||M(i,t),null!=t&&this.d&&(this.u=!1,n&&this.m.push(n),e(this))},I.prototype.forceUpdate=function(t){this.d&&(t&&this.m.push(t),this.u=!0,e(this))},I.prototype.render=O,s=[],n="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,i=m.debounceRendering,m.o=function(t,n,i){for(var r;n=n.i;)if((r=n.c)&&!r.i)try{if(r.constructor&&null!=r.constructor.getDerivedStateFromError)r.setState(r.constructor.getDerivedStateFromError(t));else{if(null==r.componentDidCatch)continue;r.componentDidCatch(t)}return e(r.k=r)}catch(n){t=n}throw t},o=x;var t="(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)",l="[\\s|\\(]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")\\s*\\)?",p="[\\s|\\(]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")[,|\\s]+("+t+")\\s*\\)?",_=new RegExp("rgb"+l),H=new RegExp("rgba"+p),P=new RegExp("hsl"+l),$=new RegExp("hsla"+p),T="^(?:#?|0x?)",W="([0-9a-fA-F]{1})",C="([0-9a-fA-F]{2})",D=new RegExp(T+W+W+W+"$"),F=new RegExp(T+W+W+W+W+"$"),L=new RegExp(T+C+C+C+"$"),B=new RegExp(T+C+C+C+C+"$"),q=Math.log,G=Math.round,Z=Math.floor;function J(t,n,i){return Math.min(Math.max(t,n),i)}function K(t,n){var i=-1<t.indexOf("%"),r=parseFloat(t);return i?n/100*r:r}function Q(t){return parseInt(t,16)}function U(t){return t.toString(16).padStart(2,"0")}var V=function(){function l(t,n){this.$={h:0,s:0,v:0,a:1},t&&this.set(t),this.onChange=n,this.initialValue=b({},this.$)}var t=l.prototype;return t.set=function(t){if("string"==typeof t)/^(?:#?|0x?)[0-9a-fA-F]{3,8}$/.test(t)?this.hexString=t:/^rgba?/.test(t)?this.rgbString=t:/^hsla?/.test(t)&&(this.hslString=t);else{if("object"!=typeof t)throw new Error("Invalid color value");t instanceof l?this.hsva=t.hsva:"r"in t&&"g"in t&&"b"in t?this.rgb=t:"h"in t&&"s"in t&&"v"in t?this.hsv=t:"h"in t&&"s"in t&&"l"in t?this.hsl=t:"kelvin"in t&&(this.kelvin=t.kelvin)}},t.setChannel=function(t,n,i){var r;this[t]=b({},this[t],((r={})[n]=i,r))},t.reset=function(){this.hsva=this.initialValue},t.clone=function(){return new l(this)},t.unbind=function(){this.onChange=void 0},l.hsvToRgb=function(t){var n=t.h/60,i=t.s/100,r=t.v/100,e=Z(n),u=n-e,o=r*(1-i),l=r*(1-u*i),s=r*(1-(1-u)*i),c=e%6,a=[s,r,r,l,o,o][c],f=[o,o,s,r,r,l][c];return{r:J(255*[r,l,o,o,s,r][c],0,255),g:J(255*a,0,255),b:J(255*f,0,255)}},l.rgbToHsv=function(t){var n=t.r/255,i=t.g/255,r=t.b/255,e=Math.max(n,i,r),u=Math.min(n,i,r),o=e-u,l=0,s=e,c=0===e?0:o/e;switch(e){case u:l=0;break;case n:l=(i-r)/o+(i<r?6:0);break;case i:l=(r-n)/o+2;break;case r:l=(n-i)/o+4}return{h:60*l%360,s:J(100*c,0,100),v:J(100*s,0,100)}},l.hsvToHsl=function(t){var n=t.s/100,i=t.v/100,r=(2-n)*i,e=r<=1?r:2-r,u=e<1e-9?0:n*i/e;return{h:t.h,s:J(100*u,0,100),l:J(50*r,0,100)}},l.hslToHsv=function(t){var n=2*t.l,i=t.s*(n<=100?n:200-n)/100,r=n+i<1e-9?0:2*i/(n+i);return{h:t.h,s:J(100*r,0,100),v:J((n+i)/2,0,100)}},l.kelvinToRgb=function(t){var n,i,r,e=t/100;return r=e<66?(n=255,i=-155.25485562709179-.44596950469579133*(i=e-2)+104.49216199393888*q(i),e<20?0:.8274096064007395*(r=e-10)-254.76935184120902+115.67994401066147*q(r)):(n=351.97690566805693+.114206453784165*(n=e-55)-40.25366309332127*q(n),i=325.4494125711974+.07943456536662342*(i=e-50)-28.0852963507957*q(i),255),{r:J(Z(n),0,255),g:J(Z(i),0,255),b:J(Z(r),0,255)}},l.rgbToKelvin=function(t){for(var n,i=t.r,r=t.b,e=2e3,u=4e4;.4<u-e;){var o=l.kelvinToRgb(n=.5*(u+e));o.b/o.r>=r/i?u=n:e=n}return n},function(t,n,i){n&&g(t.prototype,n),i&&g(t,i)}(l,[{key:"hsv",get:function(){var t=this.$;return{h:t.h,s:t.s,v:t.v}},set:function(t){var n=this.$;if(t=b({},n,t),this.onChange){var i={h:!1,v:!1,s:!1,a:!1};for(var r in n)i[r]=t[r]!=n[r];this.$=t,(i.h||i.s||i.v||i.a)&&this.onChange(this,i)}else this.$=t}},{key:"hsva",get:function(){return b({},this.$)},set:function(t){this.hsv=t}},{key:"hue",get:function(){return this.$.h},set:function(t){this.hsv={h:t}}},{key:"saturation",get:function(){return this.$.s},set:function(t){this.hsv={s:t}}},{key:"value",get:function(){return this.$.v},set:function(t){this.hsv={v:t}}},{key:"alpha",get:function(){return this.$.a},set:function(t){this.hsv=b({},this.hsv,{a:t})}},{key:"kelvin",get:function(){return l.rgbToKelvin(this.rgb)},set:function(t){this.rgb=l.kelvinToRgb(t)}},{key:"red",get:function(){return this.rgb.r},set:function(t){this.rgb=b({},this.rgb,{r:t})}},{key:"green",get:function(){return this.rgb.g},set:function(t){this.rgb=b({},this.rgb,{g:t})}},{key:"blue",get:function(){return this.rgb.b},set:function(t){this.rgb=b({},this.rgb,{b:t})}},{key:"rgb",get:function(){var t=l.hsvToRgb(this.$),n=t.r,i=t.g,r=t.b;return{r:G(n),g:G(i),b:G(r)}},set:function(t){this.hsv=b({},l.rgbToHsv(t),{a:void 0===t.a?1:t.a})}},{key:"rgba",get:function(){return b({},this.rgb,{a:this.alpha})},set:function(t){this.rgb=t}},{key:"hsl",get:function(){var t=l.hsvToHsl(this.$),n=t.h,i=t.s,r=t.l;return{h:G(n),s:G(i),l:G(r)}},set:function(t){this.hsv=b({},l.hslToHsv(t),{a:void 0===t.a?1:t.a})}},{key:"hsla",get:function(){return b({},this.hsl,{a:this.alpha})},set:function(t){this.hsl=t}},{key:"rgbString",get:function(){var t=this.rgb;return"rgb("+t.r+", "+t.g+", "+t.b+")"},set:function(t){var n,i,r,e,u=1;if((n=_.exec(t))?(i=K(n[1],255),r=K(n[2],255),e=K(n[3],255)):(n=H.exec(t))&&(i=K(n[1],255),r=K(n[2],255),e=K(n[3],255),u=K(n[4],1)),!n)throw new Error("Invalid rgb string");this.rgb={r:i,g:r,b:e,a:u}}},{key:"rgbaString",get:function(){var t=this.rgba;return"rgba("+t.r+", "+t.g+", "+t.b+", "+t.a+")"},set:function(t){this.rgbString=t}},{key:"hexString",get:function(){var t=this.rgb;return"#"+U(t.r)+U(t.g)+U(t.b)},set:function(t){var n,i,r,e,u=255;if((n=D.exec(t))?(i=17*Q(n[1]),r=17*Q(n[2]),e=17*Q(n[3])):(n=F.exec(t))?(i=17*Q(n[1]),r=17*Q(n[2]),e=17*Q(n[3]),u=17*Q(n[4])):(n=L.exec(t))?(i=Q(n[1]),r=Q(n[2]),e=Q(n[3])):(n=B.exec(t))&&(i=Q(n[1]),r=Q(n[2]),e=Q(n[3]),u=Q(n[4])),!n)throw new Error("Invalid hex string");this.rgb={r:i,g:r,b:e,a:u/255}}},{key:"hex8String",get:function(){var t=this.rgba;return"#"+U(t.r)+U(t.g)+U(t.b)+U(Z(255*t.a))},set:function(t){this.hexString=t}},{key:"hslString",get:function(){var t=this.hsl;return"hsl("+t.h+", "+t.s+"%, "+t.l+"%)"},set:function(t){var n,i,r,e,u=1;if((n=P.exec(t))?(i=K(n[1],360),r=K(n[2],100),e=K(n[3],100)):(n=$.exec(t))&&(i=K(n[1],360),r=K(n[2],100),e=K(n[3],100),u=K(n[4],1)),!n)throw new Error("Invalid hsl string");this.hsl={h:i,s:r,l:e,a:u}}},{key:"hslaString",get:function(){var t=this.hsla;return"hsla("+t.h+", "+t.s+"%, "+t.l+"%, "+t.a+")"},set:function(t){this.hslString=t}}]),l}();function X(t){var n,i=t.width,r=t.sliderSize,e=t.borderWidth,u=t.handleRadius,o=t.padding,l=t.sliderShape,s="horizontal"===t.layoutDirection;return r=null!=(n=r)?n:2*o+2*u,"circle"===l?{handleStart:t.padding+t.handleRadius,handleRange:i-2*o-2*u,width:i,height:i,cx:i/2,cy:i/2,radius:i/2-e/2}:{handleStart:r/2,handleRange:i-r,radius:r/2,x:0,y:0,width:s?r:i,height:s?i:r}}function Y(t,n){var i=X(t),r=i.width,e=i.height,u=i.handleRange,o=i.handleStart,l="horizontal"===t.layoutDirection,s=l?r/2:e/2,c=o+function(t,n){var i=n.hsva,r=n.rgb;switch(t.sliderType){case"red":return r.r/2.55;case"green":return r.g/2.55;case"blue":return r.b/2.55;case"alpha":return 100*i.a;case"kelvin":var e=t.minTemperature,u=t.maxTemperature-e,o=(n.kelvin-e)/u*100;return Math.max(0,Math.min(o,100));case"hue":return i.h/=3.6;case"saturation":return i.s;case"value":default:return i.v}}(t,n)/100*u;return l&&(c=-1*c+u+2*o),{x:l?s:c,y:l?c:s}}var tt,nt=2*Math.PI,it=function(t,n){return(t%n+n)%n},rt=function(t,n){return Math.sqrt(t*t+n*n)};function et(t){return t.width/2-t.padding-t.handleRadius-t.borderWidth}function ut(t){var n=t.width/2;return{width:t.width,radius:n-t.borderWidth,cx:n,cy:n}}function ot(t,n,i){var r=t.wheelAngle,e=t.wheelDirection;return i&&"clockwise"===e?n=r+n:"clockwise"===e?n=360-r+n:i&&"anticlockwise"===e?n=r+180-n:"anticlockwise"===e&&(n=r-n),it(n,360)}function lt(t,n,i){var r=ut(t),e=r.cx,u=r.cy,o=et(t);n=e-n,i=u-i;var l=ot(t,Math.atan2(-i,-n)*(360/nt)),s=Math.min(rt(n,i),o);return{h:Math.round(l),s:Math.round(100/o*s)}}function st(t){var n=t.width,i=t.boxHeight;return{width:n,height:null!=i?i:n,radius:t.padding+t.handleRadius}}function ct(t,n,i){var r=st(t),e=r.width,u=r.height,o=r.radius,l=(n-o)/(e-2*o)*100,s=(i-o)/(u-2*o)*100;return{s:Math.max(0,Math.min(l,100)),v:Math.max(0,Math.min(100-s,100))}}function at(t,n,i,r){for(var e=0;e<r.length;e++){var u=r[e].x-n,o=r[e].y-i;if(Math.sqrt(u*u+o*o)<t.handleRadius)return e}return null}function ft(t){return{boxSizing:"border-box",border:t.borderWidth+"px solid "+t.borderColor}}function ht(t,n,i){return t+"-gradient("+n+", "+i.map(function(t){var n=t[0];return t[1]+" "+n+"%"}).join(",")+")"}function vt(t){return"string"==typeof t?t:t+"px"}var dt=["mousemove","touchmove","mouseup","touchend"],gt=function(n){function t(t){n.call(this,t),this.uid=(Math.random()+1).toString(36).substring(5)}return n&&(t.__proto__=n),((t.prototype=Object.create(n&&n.prototype)).constructor=t).prototype.render=function(t){var n=this.handleEvent.bind(this),i={onMouseDown:n,ontouchstart:n},r="horizontal"===t.layoutDirection,e=null===t.margin?t.sliderMargin:t.margin,u={overflow:"visible",display:r?"inline-block":"block"};return 0<t.index&&(u[r?"marginLeft":"marginTop"]=e),h(O,null,t.children(this.uid,i,u))},t.prototype.handleEvent=function(t){var n=this,i=this.props.onInput,r=this.base.getBoundingClientRect();t.preventDefault();var e=t.touches?t.changedTouches[0]:t,u=e.clientX-r.left,o=e.clientY-r.top;switch(t.type){case"mousedown":case"touchstart":!1!==i(u,o,0)&&dt.forEach(function(t){document.addEventListener(t,n,{passive:!1})});break;case"mousemove":case"touchmove":i(u,o,1);break;case"mouseup":case"touchend":i(u,o,2),dt.forEach(function(t){document.removeEventListener(t,n,{passive:!1})})}},t}(I);function bt(t){var n=t.r,i=t.url,r=n,e=n;return h("svg",{className:"IroHandle IroHandle--"+t.index+" "+(t.isActive?"IroHandle--isActive":""),style:{"-webkit-tap-highlight-color":"rgba(0, 0, 0, 0);",transform:"translate("+vt(t.x)+", "+vt(t.y)+")",willChange:"transform",top:vt(-n),left:vt(-n),width:vt(2*n),height:vt(2*n),position:"absolute",overflow:"visible"}},i&&h("use",Object.assign({xlinkHref:function(t){tt=tt||document.getElementsByTagName("base");var n=window.navigator.userAgent,i=/^((?!chrome|android).)*safari/i.test(n),r=/iPhone|iPod|iPad/i.test(n),e=window.location;return(i||r)&&0<tt.length?e.protocol+"//"+e.host+e.pathname+e.search+t:t}(i)},t.props)),!i&&h("circle",{cx:r,cy:e,r:n,fill:"none","stroke-width":2,stroke:"#000"}),!i&&h("circle",{cx:r,cy:e,r:n-2,fill:t.fill,"stroke-width":2,stroke:"#fff"}))}function pt(e){var t=e.activeIndex,u=void 0!==t&&t<e.colors.length?e.colors[t]:e.color,n=X(e),r=n.width,o=n.height,l=n.radius,s=Y(e,u),c=function(t,n){var i=n.hsv,r=n.rgb;switch(t.sliderType){case"red":return[[0,"rgb(0,"+r.g+","+r.b+")"],[100,"rgb(255,"+r.g+","+r.b+")"]];case"green":return[[0,"rgb("+r.r+",0,"+r.b+")"],[100,"rgb("+r.r+",255,"+r.b+")"]];case"blue":return[[0,"rgb("+r.r+","+r.g+",0)"],[100,"rgb("+r.r+","+r.g+",255)"]];case"alpha":return[[0,"rgba("+r.r+","+r.g+","+r.b+",0)"],[100,"rgb("+r.r+","+r.g+","+r.b+")"]];case"kelvin":for(var e=[],u=t.minTemperature,o=t.maxTemperature,l=o-u,s=u,c=0;s<o;s+=l/8,c+=1){var a=V.kelvinToRgb(s),f=a.r,h=a.g,v=a.b;e.push([12.5*c,"rgb("+f+","+h+","+v+")"])}return e;case"hue":return[[0,"#f00"],[16.666,"#ff0"],[33.333,"#0f0"],[50,"#0ff"],[66.666,"#00f"],[83.333,"#f0f"],[100,"#f00"]];case"saturation":var d=V.hsvToHsl({h:i.h,s:0,v:i.v}),g=V.hsvToHsl({h:i.h,s:100,v:i.v});return[[0,"hsl("+d.h+","+d.s+"%,"+d.l+"%)"],[100,"hsl("+g.h+","+g.s+"%,"+g.l+"%)"]];case"value":default:var b=V.hsvToHsl({h:i.h,s:i.s,v:100});return[[0,"#000"],[100,"hsl("+b.h+","+b.s+"%,"+b.l+"%)"]]}}(e,u);return h(gt,Object.assign({},e,{onInput:function(t,n,i){var r=function(t,n,i){var r,e=X(t),u=e.handleRange,o=e.handleStart;r="horizontal"===t.layoutDirection?-1*i+u+o:n-o,r=Math.max(Math.min(r,u),0);var l=Math.round(100/u*r);switch(t.sliderType){case"kelvin":var s=t.minTemperature;return s+l/100*(t.maxTemperature-s);case"alpha":return l/100;case"hue":return 3.6*l;case"red":case"blue":case"green":return 2.55*l;default:return l}}(e,t,n);e.parent.inputActive=!0,u[e.sliderType]=r,e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroSlider",style:Object.assign({},{position:"relative",width:vt(r),height:vt(o),borderRadius:vt(l),background:"conic-gradient(#ccc 25%, #fff 0 50%, #ccc 0 75%, #fff 0)",backgroundSize:"8px 8px"},i)}),h("div",{className:"IroSliderGradient",style:Object.assign({},{position:"absolute",top:0,left:0,width:"100%",height:"100%",borderRadius:vt(l),background:ht("linear","horizontal"===e.layoutDirection?"to top":"to right",c)},ft(e))}),h(bt,{isActive:!0,index:u.index,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:s.x,y:s.y}))})}function yt(e){var t=st(e),r=t.width,u=t.height,o=t.radius,l=e.colors,s=e.parent,n=e.activeIndex,c=void 0!==n&&n<e.colors.length?e.colors[n]:e.color,a=function(t,n){return[[[0,"#fff"],[100,"hsl("+n.hue+",100%,50%)"]],[[0,"rgba(0,0,0,0)"],[100,"#000"]]]}(0,c),f=l.map(function(t){return function(t,n){var i=st(t),r=i.width,e=i.height,u=i.radius,o=n.hsv,l=u,s=r-2*u,c=e-2*u;return{x:l+o.s/100*s,y:l+(c-o.v/100*c)}}(e,t)});return h(gt,Object.assign({},e,{onInput:function(t,n,i){if(0===i){var r=at(e,t,n,f);null!==r?s.setActiveColor(r):(s.inputActive=!0,c.hsv=ct(e,t,n),e.onInput(i,e.id))}else 1===i&&(s.inputActive=!0,c.hsv=ct(e,t,n));e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroBox",style:Object.assign({},{width:vt(r),height:vt(u),position:"relative"},i)}),h("div",{className:"IroBox",style:Object.assign({},{width:"100%",height:"100%",borderRadius:vt(o)},ft(e),{background:ht("linear","to bottom",a[1])+","+ht("linear","to right",a[0])})}),l.filter(function(t){return t!==c}).map(function(t){return h(bt,{isActive:!1,index:t.index,fill:t.hslString,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:f[t.index].x,y:f[t.index].y})}),h(bt,{isActive:!0,index:c.index,fill:c.hslString,r:e.activeHandleRadius||e.handleRadius,url:e.handleSvg,props:e.handleProps,x:f[c.index].x,y:f[c.index].y}))})}bt.defaultProps={fill:"none",x:0,y:0,r:8,url:null,props:{x:0,y:0}},pt.defaultProps=Object.assign({},{sliderShape:"bar",sliderType:"value",minTemperature:2200,maxTemperature:11e3});function wt(e){var r=ut(e).width,u=e.colors,o=(e.borderWidth,e.parent),l=e.color,s=l.hsv,c=u.map(function(t){return function(t,n){var i=n.hsv,r=ut(t),e=r.cx,u=r.cy,o=et(t),l=(180+ot(t,i.h,!0))*(nt/360),s=i.s/100*o,c="clockwise"===t.wheelDirection?-1:1;return{x:e+s*Math.cos(l)*c,y:u+s*Math.sin(l)*c}}(e,t)}),a={position:"absolute",top:0,left:0,width:"100%",height:"100%",borderRadius:"50%",boxSizing:"border-box"};return h(gt,Object.assign({},e,{onInput:function(t,n,i){if(0===i){if(!function(t,n,i){var r=ut(t),e=r.cx,u=r.cy,o=t.width/2;return rt(e-n,u-i)<o}(e,t,n))return!1;var r=at(e,t,n,c);null!==r?o.setActiveColor(r):(o.inputActive=!0,l.hsv=lt(e,t,n),e.onInput(i,e.id))}else 1===i&&(o.inputActive=!0,l.hsv=lt(e,t,n));e.onInput(i,e.id)}}),function(t,n,i){return h("div",Object.assign({},n,{className:"IroWheel",style:Object.assign({},{width:vt(r),height:vt(r),position:"relative"},i)}),h("div",{className:"IroWheelHue",style:Object.assign({},a,{transform:"rotateZ("+(e.wheelAngle+90)+"deg)",background:"clockwise"===e.wheelDirection?"conic-gradient(red, yellow, lime, aqua, blue, magenta, red)":"conic-gradient(red, magenta, blue, aqua, lime, yellow, red)"})}),h("div",{className:"IroWheelSaturation",style:Object.assign({},a,{background:"radial-gradient(circle closest-side, #fff, transparent)"})}),e.wheelLightness&&h("div",{className:"IroWheelLightness",style:Object.assign({},a,{background:"#000",opacity:1-s.v/100})}),h("div",{className:"IroWheelBorder",style:Object.assign({},a,ft(e))}),u.filter(function(t){return t!==l}).map(function(t){return h(bt,{isActive:!1,index:t.index,fill:t.hslString,r:e.handleRadius,url:e.handleSvg,props:e.handleProps,x:c[t.index].x,y:c[t.index].y})}),h(bt,{isActive:!0,index:l.index,fill:l.hslString,r:e.activeHandleRadius||e.handleRadius,url:e.handleSvg,props:e.handleProps,x:c[l.index].x,y:c[l.index].y}))})}var kt=function(i){function t(t){var n=this;i.call(this,t),this.colors=[],this.inputActive=!1,this.events={},this.activeEvents={},this.deferredEvents={},this.id=t.id,(0<t.colors.length?t.colors:[t.color]).forEach(function(t){return n.addColor(t)}),this.setActiveColor(0),this.state=Object.assign({},t,{color:this.color,colors:this.colors,layout:t.layout})}return i&&(t.__proto__=i),((t.prototype=Object.create(i&&i.prototype)).constructor=t).prototype.addColor=function(t,n){void 0===n&&(n=this.colors.length);var i=new V(t,this.onColorChange.bind(this));this.colors.splice(n,0,i),this.colors.forEach(function(t,n){return t.index=n}),this.state&&this.setState({colors:this.colors}),this.deferredEmit("color:init",i)},t.prototype.removeColor=function(t){var n=this.colors.splice(t,1)[0];n.unbind(),this.colors.forEach(function(t,n){return t.index=n}),this.state&&this.setState({colors:this.colors}),n.index===this.color.index&&this.setActiveColor(0),this.emit("color:remove",n)},t.prototype.setActiveColor=function(t){this.color=this.colors[t],this.state&&this.setState({color:this.color}),this.emit("color:setActive",this.color)},t.prototype.setColors=function(t,n){var i=this;void 0===n&&(n=0),this.colors.forEach(function(t){return t.unbind()}),this.colors=[],t.forEach(function(t){return i.addColor(t)}),this.setActiveColor(n),this.emit("color:setAll",this.colors)},t.prototype.on=function(t,n){var i=this,r=this.events;(Array.isArray(t)?t:[t]).forEach(function(t){(r[t]||(r[t]=[])).push(n),i.deferredEvents[t]&&(i.deferredEvents[t].forEach(function(t){n.apply(null,t)}),i.deferredEvents[t]=[])})},t.prototype.off=function(t,i){var r=this;(Array.isArray(t)?t:[t]).forEach(function(t){var n=r.events[t];n&&n.splice(n.indexOf(i),1)})},t.prototype.emit=function(t){for(var n=this,i=[],r=arguments.length-1;0<r--;)i[r]=arguments[r+1];var e=this.activeEvents;!!e.hasOwnProperty(t)&&e[t]||(e[t]=!0,(this.events[t]||[]).forEach(function(t){return t.apply(n,i)}),e[t]=!1)},t.prototype.deferredEmit=function(t){for(var n,i=[],r=arguments.length-1;0<r--;)i[r]=arguments[r+1];var e=this.deferredEvents;(n=this).emit.apply(n,[t].concat(i)),(e[t]||(e[t]=[])).push(i)},t.prototype.setOptions=function(t){this.setState(t)},t.prototype.resize=function(t){this.setOptions({width:t})},t.prototype.reset=function(){this.colors.forEach(function(t){return t.reset()}),this.setState({colors:this.colors})},t.prototype.onMount=function(t){this.el=t,this.deferredEmit("mount",this)},t.prototype.onColorChange=function(t,n){this.setState({color:this.color}),this.inputActive&&(this.inputActive=!1,this.emit("input:change",t,n)),this.emit("color:change",t,n)},t.prototype.emitInputEvent=function(t,n){0===t?this.emit("input:start",this.color,n):1===t?this.emit("input:move",this.color,n):2===t&&this.emit("input:end",this.color,n)},t.prototype.render=function(t,e){var u=this,n=e.layout;return Array.isArray(n)||(n=[{component:wt},{component:pt}],e.transparency&&n.push({component:pt,options:{sliderType:"alpha"}})),h("div",{class:"IroColorPicker",id:e.id,style:{display:e.display}},n.map(function(t,n){var i=t.component,r=t.options;return h(i,Object.assign({},e,r,{ref:void 0,onInput:u.emitInputEvent.bind(u),parent:u,index:n}))}))},t}(I);kt.defaultProps=Object.assign({},{width:300,height:300,color:"#fff",colors:[],padding:6,layoutDirection:"vertical",borderColor:"#fff",borderWidth:0,handleRadius:8,activeHandleRadius:null,handleSvg:null,handleProps:{x:0,y:0},wheelLightness:!0,wheelAngle:0,wheelDirection:"anticlockwise",sliderSize:null,sliderMargin:12,boxHeight:null},{colors:[],display:"block",id:null,layout:"default",margin:null});var mt,xt,jt,Mt,Ot=(It.prototype=(mt=kt).prototype,Object.assign(It,mt),It.I=mt,It);function It(n,t){var i,r=document.createElement("div");function e(){var t=n instanceof Element?n:document.querySelector(n);t.appendChild(i.base),i.onMount(t)}return function(t,n,i){var r,e,u;m.i&&m.i(t,n),e=(r=i===o)?null:i&&i.n||n.n,t=h(O,null,[t]),u=[],k(n,r?n.n=t:(i||n).n=t,e||x,x,void 0!==n.ownerSVGElement,i&&!r?[i]:e?null:j.slice.call(n.childNodes),u,!1,i||x,r),d(u,t)}(h(mt,Object.assign({},{ref:function(t){return i=t}},t)),r),"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e),i}return(jt=xt=xt||{}).version="5.5.2",jt.Color=V,jt.ColorPicker=Ot,(Mt=jt.ui||(jt.ui={})).h=h,Mt.ComponentBase=gt,Mt.Handle=bt,Mt.Slider=pt,Mt.Wheel=wt,Mt.Box=yt,xt});
@@ -418,7 +418,7 @@ class GUIController extends Controller {
418
418
  // Initialize controller buttons.
419
419
  this.node_btns = ['process', 'product', 'link', 'constraint',
420
420
  'cluster', 'module', 'note'];
421
- this.edit_btns = ['clone', 'paste', 'delete', 'undo', 'redo'];
421
+ this.edit_btns = ['replace', 'clone', 'paste', 'delete', 'undo', 'redo'];
422
422
  this.model_btns = ['settings', 'save', 'repository', 'actors',
423
423
  'dataset', 'equation', 'chart', 'sensitivity', 'experiment',
424
424
  'diagram', 'savediagram', 'finder', 'monitor', 'tex', 'solve'];
@@ -599,6 +599,8 @@ class GUIController extends Controller {
599
599
  UI.copySelection();
600
600
  }
601
601
  });
602
+ this.buttons.replace.addEventListener('click',
603
+ () => UI.replaceSelectedProduct());
602
604
  this.buttons.paste.addEventListener('click',
603
605
  () => UI.pasteSelection());
604
606
  this.buttons['delete'].addEventListener('click',
@@ -827,7 +829,7 @@ class GUIController extends Controller {
827
829
  this.modals.move.cancel.addEventListener('click',
828
830
  () => UI.doNotMoveNode());
829
831
 
830
- // The REPLACE dialog appears when a product is Ctrl-clicked.
832
+ // The REPLACE dialog appears when a product is Shift-Alt-clicked.
831
833
  this.modals.replace.ok.addEventListener('click',
832
834
  () => UI.replaceProduct());
833
835
  this.modals.replace.cancel.addEventListener('click',
@@ -925,6 +927,9 @@ class GUIController extends Controller {
925
927
  UNDO_STACK.clear();
926
928
  // Autosaving should start anew.
927
929
  AUTO_SAVE.setAutoSaveInterval();
930
+ // Finder dialog is closed, but may still display results for
931
+ // previous model.
932
+ FINDER.updateDialog();
928
933
  // Signal success or failure.
929
934
  return loaded;
930
935
  }
@@ -1132,7 +1137,6 @@ class GUIController extends Controller {
1132
1137
  'confirm when prompted by your browser.');
1133
1138
  // Hide "update" button in server dialog.
1134
1139
  UI.modals.server.element('update').style.display = 'none';
1135
- return;
1136
1140
  } else {
1137
1141
  // Inform user that install appears to have failed.
1138
1142
  msg.push(
@@ -1142,7 +1146,8 @@ class GUIController extends Controller {
1142
1146
  }
1143
1147
  md.element('msg').innerHTML = msg.join('<br>');
1144
1148
  // Reload `index.html`. This will start Linny-R anew.
1145
- window.open('./', '_self');
1149
+ // NOTE: Wait for 2 seconds so the message can be read.
1150
+ setTimeout(() => { window.open('./', '_self'); }, 2000);
1146
1151
  }
1147
1152
  })
1148
1153
  .catch((err) => {
@@ -1591,7 +1596,7 @@ class GUIController extends Controller {
1591
1596
  // Updates the buttons on the main GUI toolbars
1592
1597
  const
1593
1598
  node_btns = 'process product link constraint cluster note ',
1594
- edit_btns = 'clone paste delete undo redo ',
1599
+ edit_btns = 'replace clone paste delete undo redo ',
1595
1600
  model_btns = 'settings save actors dataset equation chart ' +
1596
1601
  'diagram savediagram finder monitor solve';
1597
1602
  if(MODEL === null) {
@@ -1617,9 +1622,30 @@ class GUIController extends Controller {
1617
1622
  this.enableButtons(node_btns + model_btns);
1618
1623
  this.active_button = this.stayActiveButton;
1619
1624
  this.disableButtons(edit_btns);
1620
- if(MODEL.selection.length > 0) this.enableButtons('clone delete');
1625
+ if(MODEL.selection.length > 0) {
1626
+ this.enableButtons('clone delete');
1627
+ // Replace applies only to a single product.
1628
+ if(MODEL.selection.length === 1) {
1629
+ const p = MODEL.selection[0];
1630
+ if(p instanceof Product) {
1631
+ const
1632
+ b = this.buttons.replace,
1633
+ t = 'Replace selected product by some other product (Alt-P)';
1634
+ // Differentiate between product types, as products can be
1635
+ // replaced only by products of the same type.
1636
+ if(p.is_data) {
1637
+ b.title = t.replaceAll('product', 'data product');
1638
+ b.src = 'images/replace-data-product.png';
1639
+ } else {
1640
+ b.title = t;
1641
+ b.src = 'images/replace-product.png';
1642
+ }
1643
+ this.enableButtons('replace');
1644
+ }
1645
+ }
1646
+ }
1621
1647
  if(this.canPaste) this.enableButtons('paste');
1622
- // Only allow target seeking when some target or process constraint is defined
1648
+ // Only allow soling when some target or process constraint is defined.
1623
1649
  if(MODEL.hasTargets) this.enableButtons('solve');
1624
1650
  var u = UNDO_STACK.canUndo;
1625
1651
  if(u) {
@@ -2315,13 +2341,16 @@ class GUIController extends Controller {
2315
2341
  } else if(alt && code === 'KeyR') {
2316
2342
  // Alt-R means: run to diagnose infeasible/unbounded problem.
2317
2343
  VM.solveModel(true);
2318
- } else if(alt && ['KeyC', 'KeyM'].indexOf(code) >= 0) {
2319
- // Special shortcut keys for "clone selection" and "model settings".
2344
+ } else if(alt && ['KeyC', 'KeyM', 'KeyP'].indexOf(code) >= 0) {
2345
+ // Special shortcut keys for "clone selection", "model settings"
2346
+ // and "replace product".
2320
2347
  const be = new Event('click');
2321
2348
  if(code === 'KeyC') {
2322
2349
  this.buttons.clone.dispatchEvent(be);
2323
- } else {
2350
+ } else if(code === 'KeyM') {
2324
2351
  this.buttons.settings.dispatchEvent(be);
2352
+ } else if(code === 'KeyP') {
2353
+ this.buttons.replace.dispatchEvent(be);
2325
2354
  }
2326
2355
  } else if(!e.shiftKey && !alt &&
2327
2356
  (!topmod || ['KeyA', 'KeyC', 'KeyV'].indexOf(code) < 0)) {
@@ -2333,7 +2362,9 @@ class GUIController extends Controller {
2333
2362
  CONSTRAINT_EDITOR.deleteBoundLine();
2334
2363
  } else if(!this.hidden('variable-modal')) {
2335
2364
  CHART_MANAGER.deleteVariable();
2336
- } else {
2365
+ } else if(!topmod) {
2366
+ // Do not delete entity from model diagram when some modal
2367
+ // is showing.
2337
2368
  this.buttons['delete'].dispatchEvent(new Event('click'));
2338
2369
  }
2339
2370
  } else if (code === 'Period' && (e.ctrlKey || e.metaKey)) {
@@ -3577,6 +3608,7 @@ console.log('HERE name conflicts', name_conflicts, mapping);
3577
3608
  this.setBox('settings-diagnose', model.always_diagnose);
3578
3609
  this.setBox('settings-power', model.with_power_flow);
3579
3610
  this.setBox('settings-cost-prices', model.infer_cost_prices);
3611
+ this.setBox('settings-negative-flows', model.ignore_negative_flows);
3580
3612
  this.setBox('settings-report-results', model.report_results);
3581
3613
  this.setBox('settings-encrypt', model.encrypt);
3582
3614
  const pg_btn = md.element('power-btn');
@@ -3652,6 +3684,7 @@ console.log('HERE name conflicts', name_conflicts, mapping);
3652
3684
  cb = UI.boxChecked('settings-cost-prices');
3653
3685
  redraw = redraw || cb !== model.infer_cost_prices;
3654
3686
  model.infer_cost_prices = cb;
3687
+ model.ignore_negative_flows = UI.boxChecked('settings-negative-flows');
3655
3688
  cb = UI.boxChecked('settings-block-arrows');
3656
3689
  redraw = redraw || cb !== model.show_block_arrows;
3657
3690
  model.show_block_arrows = cb;
@@ -4276,6 +4309,15 @@ console.log('HERE name conflicts', name_conflicts, mapping);
4276
4309
  soc = 0;
4277
4310
  this.warn('Cost can only be attributed to level-based links');
4278
4311
  }
4312
+ // For multipliers requiring a binary variable, and also for those
4313
+ // based on the node's upper bound, warn the modeler when the UB for
4314
+ // this node is infinite or unspecified.
4315
+ if(VM.LM_NEEDING_ON_OFF.indexOf(m) >= 0 || m === VM.LM_AVAILABLE_CAPACITY) {
4316
+ if(!l.from_node.upper_bound.text) {
4317
+ UI.warn('Infinite upper bound of <strong>' + l.from_node.displayName +
4318
+ `</strong> will cause issues for ${VM.LM_SYMBOLS[m]} link`);
4319
+ }
4320
+ }
4279
4321
  // NOTE: share of cost is input as a percentage, but stored as a floating
4280
4322
  // point value between 0 and 1
4281
4323
  l.share_of_cost = soc / 100;
@@ -4307,9 +4349,17 @@ console.log('HERE name conflicts', name_conflicts, mapping);
4307
4349
  'constraint-to-name').innerHTML = c.to_node.displayName;
4308
4350
  CONSTRAINT_EDITOR.showDialog();
4309
4351
  }
4352
+
4353
+ replaceSelectedProduct() {
4354
+ // Check whether selection contains one product, and if so, prompt
4355
+ // for replacement.
4356
+ if(MODEL.selection.length !== 1) return;
4357
+ const p = MODEL.selection[0];
4358
+ if(p instanceof Product) this.showReplaceProductDialog(p);
4359
+ }
4310
4360
 
4311
4361
  showReplaceProductDialog(p) {
4312
- // Prompts for a product (different from `p`) by which `p` should be
4362
+ // Prompt for a product (different from `p`) by which `p` should be
4313
4363
  // replaced for the selected product position
4314
4364
  const pp = MODEL.focal_cluster.indexOfProduct(p);
4315
4365
  if(pp >= 0) {
@@ -458,6 +458,19 @@ class Finder {
458
458
  xol.push(l.identifier);
459
459
  }
460
460
  }
461
+ // Check all constraint boundline index expressions.
462
+ for(let k in MODEL.constraints) if(MODEL.constraints.hasOwnProperty(k)) {
463
+ const c = MODEL.constraints[k];
464
+ for(let i = 0; i < c.bound_lines.length; i++) {
465
+ const bl = c.bound_lines[i];
466
+ for(let j = 0; j < bl.selectors.length; j++) {
467
+ if(re.test(bl.selectors[j].expression.text)) {
468
+ xal.push('I' + (i + 1));
469
+ xol.push(c.identifier);
470
+ }
471
+ }
472
+ }
473
+ }
461
474
  // Check all dataset modifier expressions.
462
475
  for(let k in MODEL.datasets) if(MODEL.datasets.hasOwnProperty(k)) {
463
476
  const ds = MODEL.datasets[k];
@@ -99,6 +99,7 @@ class LinnyRModel {
99
99
  this.align_to_grid = true;
100
100
  this.with_power_flow = false;
101
101
  this.infer_cost_prices = false;
102
+ this.ignore_negative_flows = false;
102
103
  this.report_results = false;
103
104
  this.show_block_arrows = true;
104
105
  this.last_zoom_factor = 1;
@@ -2585,6 +2586,15 @@ class LinnyRModel {
2585
2586
  const l = this.links[k];
2586
2587
  xl.push(l.relative_rate, l.flow_delay);
2587
2588
  }
2589
+ for(let k in this.constraints) if(this.constraints.hasOwnProperty(k)) {
2590
+ const c = this.constraints[k];
2591
+ for(let i = 0; i < c.bound_lines.length; i++) {
2592
+ const bl = c.bound_lines[i];
2593
+ for(let j = 0; j < bl.selectors.length; j++) {
2594
+ xl.push(bl.selectors[j].expression);
2595
+ }
2596
+ }
2597
+ }
2588
2598
  return xl;
2589
2599
  }
2590
2600
 
@@ -2736,6 +2746,7 @@ class LinnyRModel {
2736
2746
  this.align_to_grid = nodeParameterValue(node, 'align-to-grid') === '1';
2737
2747
  this.with_power_flow = nodeParameterValue(node, 'power-flow') === '1';
2738
2748
  this.infer_cost_prices = nodeParameterValue(node, 'cost-prices') === '1';
2749
+ this.ignore_negative_flows = nodeParameterValue(node, 'negative-flows') === '1';
2739
2750
  this.report_results = nodeParameterValue(node, 'report-results') === '1';
2740
2751
  this.show_block_arrows = nodeParameterValue(node, 'block-arrows') === '1';
2741
2752
  // NOTE: Diagnosis option should default to TRUE unless *set* to FALSE.
@@ -3106,6 +3117,7 @@ class LinnyRModel {
3106
3117
  if(this.align_to_grid) p += ' align-to-grid="1"';
3107
3118
  if(this.with_power_flow) p += ' power-flow="1"';
3108
3119
  if(this.infer_cost_prices) p += ' cost-prices="1"';
3120
+ if(this.ignore_negative_flows) p += ' negative-flows="1"';
3109
3121
  if(this.report_results) p += ' report-results="1"';
3110
3122
  if(this.show_block_arrows) p += ' block-arrows="1"';
3111
3123
  if(this.show_notices) p += ' show-notices="1"';
@@ -3522,6 +3534,15 @@ class LinnyRModel {
3522
3534
  }
3523
3535
  this.cleanVector(l.actual_flow, p * l.relative_rate.result(0));
3524
3536
  }
3537
+ for(let k in this.constraints) if(this.constraints.hasOwnProperty(k)) {
3538
+ const c = this.constraints[k];
3539
+ for(let i = 0; i < c.bound_lines.length; i++) {
3540
+ const bl = c.bound_lines[i];
3541
+ for(let j = 0; j < bl.selectors.length; j++) {
3542
+ bl.selectors[j].expression.reset(0);
3543
+ }
3544
+ }
3545
+ }
3525
3546
  for(obj in this.datasets) if(this.datasets.hasOwnProperty(obj)) {
3526
3547
  const ds = this.datasets[obj];
3527
3548
  ds.resetExpressions();
@@ -4076,16 +4097,24 @@ class LinnyRModel {
4076
4097
  replaceProduct(p, r, global) {
4077
4098
  const
4078
4099
  ppi = this.focal_cluster.indexOfProduct(p),
4079
- // NOTE: record whether `r` is show in focal cluster
4100
+ // NOTE: Record whether `r` is shown in focal cluster.
4080
4101
  rshown = this.focal_cluster.indexOfProduct(r) >= 0;
4081
4102
  // NOTE: since `ppi` should always be >= 0
4082
4103
  if(ppi >= 0) {
4083
- // Build list of information needed for "undo"
4084
- const undo_info = {p: p.displayName, r: r.displayName, g: global,
4085
- lf: [], lt: [], cf: [], ct: [], cl: []};
4086
- // Keep track of redirected links
4104
+ // Build list of information needed for "undo".
4105
+ const undo_info = {
4106
+ p: p.displayName,
4107
+ r: r.displayName,
4108
+ g: global,
4109
+ lf: [],
4110
+ lt: [],
4111
+ cf: [],
4112
+ ct: [],
4113
+ cl: []
4114
+ };
4115
+ // Keep track of redirected links.
4087
4116
  const rl = [];
4088
- // First replace product in (local) links
4117
+ // First replace product in (local) links.
4089
4118
  for(let i = p.inputs.length - 1; i >= 0; i--) {
4090
4119
  const l = p.inputs[i];
4091
4120
  if(global || l.hasArrow) {
@@ -4093,7 +4122,7 @@ class LinnyRModel {
4093
4122
  ml.copyPropertiesFrom(l);
4094
4123
  this.deleteLink(l);
4095
4124
  rl.push(ml);
4096
- // NOTE: push identifier of *modified* link
4125
+ // NOTE: push identifier of *modified* link.
4097
4126
  undo_info.lt.push(ml.identifier);
4098
4127
  }
4099
4128
  }
@@ -4107,7 +4136,7 @@ class LinnyRModel {
4107
4136
  }
4108
4137
  }
4109
4138
  // Then also replace product in (local) constraints
4110
- // (also keeping track of affected constraints)
4139
+ // (also keeping track of affected constraints).
4111
4140
  const rc = [];
4112
4141
  for(let k in this.constraints) {
4113
4142
  if(this.constraints.hasOwnProperty(k)) {
@@ -4125,26 +4154,26 @@ class LinnyRModel {
4125
4154
  }
4126
4155
  }
4127
4156
  }
4128
- // Replace `p` by `r` as the positioned product
4157
+ // Replace `p` by `r` as the positioned product.
4129
4158
  const pp = this.focal_cluster.product_positions[ppi];
4130
4159
  undo_info.x = pp.x;
4131
4160
  undo_info.y = pp.y;
4132
4161
  pp.product = r;
4133
- // Change coordinates only if `r` is also shown in the focal cluster
4162
+ // Change coordinates only if `r` is also shown in the focal cluster.
4134
4163
  if(rshown) {
4135
4164
  pp.x = r.x;
4136
4165
  pp.y = r.y;
4137
4166
  }
4138
- // Likewise replace product of other placeholders of `p` by `r`
4167
+ // Likewise replace product of other placeholders of `p` by `r`.
4139
4168
  for(let k in this.clusters) if(this.clusters.hasOwnProperty(k)) {
4140
4169
  const
4141
4170
  c = this.clusters[k],
4142
4171
  ppi = c.indexOfProduct(p);
4143
- // NOTE: when local, replace only if sub-cluster is in view
4172
+ // NOTE: When local, replace only if sub-cluster is in view...
4144
4173
  if(ppi >= 0 && (global || this.focal_cluster.containsCluster(c))) {
4145
4174
  const pp = c.product_positions[ppi];
4146
- // And then it MAY be that within this sub-cluster, the local
4147
- // links to `p` were NOT redirected
4175
+ // ... and then it MAY be that within this sub-cluster, the local
4176
+ // links to `p` were NOT redirected.
4148
4177
  const ll = [];
4149
4178
  for(let i = 0; i < p.inputs.length; i++) {
4150
4179
  const l = p.inputs[i];
@@ -4169,7 +4198,7 @@ class LinnyRModel {
4169
4198
  }
4170
4199
  // Now prepare for undo, so that deleteNode can add its XML
4171
4200
  UNDO_STACK.push('replace', undo_info);
4172
- // Delete original product `p` if it has no more product positions
4201
+ // Delete original product `p` if it has no more product positions.
4173
4202
  if(!this.top_cluster.containsProduct(p)) this.deleteNode(p);
4174
4203
  }
4175
4204
  // Prepare for redraw
@@ -12961,11 +12990,12 @@ class BoundLine {
12961
12990
  }
12962
12991
 
12963
12992
  get needsNoSOS() {
12964
- // Return 1 if boundline is NOT of type <= and line segments have an
12965
- // increasing slope, -1 if boundline is NOT of type >= and line segments
12993
+ // Return 1 if boundline is of type >= and line segments have an
12994
+ // increasing slope, -1 if boundline is of type <= and line segments
12966
12995
  // have a decreasing slope, and otherwise 0 (FALSE). If non-zero (TRUE),
12967
12996
  // the constraint can be implemented without the SOS2 constraint that
12968
12997
  // only two consecutive SOS variables may be non-zero.
12998
+ if(this.type === VM.EQ) return 0;
12969
12999
  if(this.type !== VM.LE) {
12970
13000
  let slope = 0,
12971
13001
  pp = this.points[0];
@@ -2157,6 +2157,10 @@ class VirtualMachine {
2157
2157
  // diagnostic purposes -- see below.
2158
2158
  this.PLUS_INFINITY = 1e+25;
2159
2159
  this.MINUS_INFINITY = -1e+25;
2160
+ // Expression results having an infinite term may be less than infinity,
2161
+ // but still exceptionally high, and this should be shown.
2162
+ this.NEAR_PLUS_INFINITY = this.PLUS_INFINITY / 200;
2163
+ this.NEAR_MINUS_INFINITY = this.MINUS_INFINITY / 200;
2160
2164
  // As of version 1.8.0, Linny-R imposes no +INF bounds on processes
2161
2165
  // unless diagnosing an unbounded problem. For such diagnosis, the
2162
2166
  // (relatively) low value 9.999999999e+9 is used.
@@ -2218,11 +2222,12 @@ class VirtualMachine {
2218
2222
  this.LM_FIRST_COMMIT = 9; // Symbol: hollow asterisk
2219
2223
  this.LM_SHUTDOWN = 10; // Symbol: thick chevron down
2220
2224
  this.LM_PEAK_INC = 11; // Symbol: plus inside triangle ("peak-plus")
2225
+ this.LM_AVAILABLE_CAPACITY = 12; // Symbol: up-arrow with baseline
2221
2226
  // List of link multipliers that require binary ON/OFF variables
2222
2227
  this.LM_NEEDING_ON_OFF = [5, 6, 7, 8, 9, 10];
2223
2228
  this.LM_SYMBOLS = ['', '\u21C9', '\u0394', '\u03A3', '\u03BC', '\u25B2',
2224
- '+', '0', '\u2934', '\u2732', '\u25BC', '\u2A39'];
2225
- this.LM_LETTERS = ' TDSMU+0RFDP';
2229
+ '+', '0', '\u2934', '\u2732', '\u25BC', '\u2A39', '\u21A5'];
2230
+ this.LM_LETTERS = ' TDSMU+0RFDPA';
2226
2231
 
2227
2232
  // VM max. expression stack size.
2228
2233
  this.MAX_STACK = 200;
@@ -2560,14 +2565,14 @@ class VirtualMachine {
2560
2565
  if(n <= this.CYCLIC) return [true, '#CYCLE!'];
2561
2566
  // Any other number less than or equal to 10^30 is considered as
2562
2567
  // minus infinity.
2563
- if(n <= this.MINUS_INFINITY) return [true, '-\u221E'];
2568
+ if(n <= this.NEAR_MINUS_INFINITY) return [true, '-\u221E'];
2564
2569
  // Other special values are very big POSITIVE numbers, so start
2565
2570
  // comparing `n` with the highest value.
2566
2571
  if(n >= this.COMPUTING) return [true, '\u25A6']; // Checkered square
2567
2572
  // NOTE: The prettier circled bold X 2BBF does not display on macOS !!
2568
2573
  if(n >= this.NOT_COMPUTED) return [true, '\u2297']; // Circled X
2569
2574
  if(n >= this.UNDEFINED) return [true, '\u2047']; // Double question mark ??
2570
- if(n >= this.PLUS_INFINITY) return [true, '\u221E'];
2575
+ if(n >= this.NEAR_PLUS_INFINITY) return [true, '\u221E'];
2571
2576
  if(n === this.NO_COST) return [true, '\u00A2']; // c-slash (cent symbol)
2572
2577
  return [false, n];
2573
2578
  }
@@ -3693,6 +3698,15 @@ class VirtualMachine {
3693
3698
  VM.PRODUCE, VM.SPIN_RES, p.on_off_var_index,
3694
3699
  l.flow_delay, vi, l.from_node.upper_bound, tnpx,
3695
3700
  l.relative_rate]]);
3701
+ } else if(l.multiplier === VM.LM_REMAINING_CAPACITY) {
3702
+ // "remaining capacity" equals UB - level. This is a
3703
+ // simpler version of "spinning reserve". We signal this
3704
+ // by passing -1 as the index of the secondary variable,
3705
+ // and the level variable index as the primary variable.
3706
+ this.code.push([VMI_update_cash_coefficient, [
3707
+ VM.PRODUCE, VM.SPIN_RES, vi, // <-- now as primary
3708
+ l.flow_delay, -1, // <-- signal that it is "REM_CAP"
3709
+ l.from_node.upper_bound, tnpx, l.relative_rate]]);
3696
3710
  } else if(l.multiplier === VM.LM_PEAK_INC) {
3697
3711
  // NOTE: "peak increase" may be > 0 only in the first
3698
3712
  // time step of the block being optimized, and in the
@@ -4035,6 +4049,12 @@ class VirtualMachine {
4035
4049
  // NOTE: no delay on this type of link
4036
4050
  this.code.push([VMI_add_peak_increase_at_t_0,
4037
4051
  [vi, l.relative_rate]]);
4052
+ } else if(l.multiplier === VM.LM_AVAILABLE_CAPACITY) {
4053
+ // The "available capacity" equals UB - level, so subtract
4054
+ // UB * rate from RHS, while considering the delay.
4055
+ // NOTE: New instruction style that passes pointers to
4056
+ // model entities instead of their properties.
4057
+ this.code.push([VMI_add_available_capacity, l]);
4038
4058
  } else if(l.relative_rate.isStatic) {
4039
4059
  // Static rates permit simpler VM instructions
4040
4060
  c = l.relative_rate.result(0);
@@ -4311,7 +4331,7 @@ class VirtualMachine {
4311
4331
  hub = ub;
4312
4332
  if(ub > VM.MEGA_UPPER_BOUND) {
4313
4333
  hub = p.highestUpperBound([]);
4314
- // If UB still very high, warn modeler on infoline and in monitor
4334
+ // If UB still very high, warn modeler on infoline and in monitor.
4315
4335
  if(hub > VM.MEGA_UPPER_BOUND) {
4316
4336
  const msg = 'High upper bound (' + this.sig4Dig(hub) +
4317
4337
  ') for <strong>' + p.displayName + '</strong>' +
@@ -4743,14 +4763,16 @@ class VirtualMachine {
4743
4763
  a.cash_out[b] = this.checkForInfinity(
4744
4764
  x[a.cash_out_var_index + j] * this.cash_scalar);
4745
4765
  a.cash_flow[b] = a.cash_in[b] - a.cash_out[b];
4746
- // Count occurrences of a negative cash flow (threshold -0.5 cent).
4747
- if(b <= this.nr_of_time_steps && a.cash_in[b] < -0.005) {
4748
- this.logMessage(block, `${this.WARNING}(t=${b}${round}) ` +
4749
- a.displayName + ' cash IN = ' + a.cash_in[b].toPrecision(2));
4750
- }
4751
- if(b <= this.nr_of_time_steps && a.cash_out[b] < -0.005) {
4752
- this.logMessage(block, `${this.WARNING}(t=${b}${round}) ` +
4753
- a.displayName + ' cash OUT = ' + a.cash_out[b].toPrecision(2));
4766
+ if(!MODEL.ignore_negative_flows) {
4767
+ // Count occurrences of a negative cash flow (threshold -0.5 cent).
4768
+ if(b <= this.nr_of_time_steps && a.cash_in[b] < -0.005) {
4769
+ this.logMessage(block, `${this.WARNING}(t=${b}${round}) ` +
4770
+ a.displayName + ' cash IN = ' + a.cash_in[b].toPrecision(2));
4771
+ }
4772
+ if(b <= this.nr_of_time_steps && a.cash_out[b] < -0.005) {
4773
+ this.logMessage(block, `${this.WARNING}(t=${b}${round}) ` +
4774
+ a.displayName + ' cash OUT = ' + a.cash_out[b].toPrecision(2));
4775
+ }
4754
4776
  }
4755
4777
  // Advance column offset in tableau by the # cols per time step.
4756
4778
  j += this.cols;
@@ -4765,8 +4787,7 @@ class VirtualMachine {
4765
4787
  p = MODEL.processes[o],
4766
4788
  has_OO = (p.on_off_var_index >= 0),
4767
4789
  has_SU = (p.start_up_var_index >= 0),
4768
- has_SD = (p.shut_down_var_index >= 0),
4769
- grid = p.grid;
4790
+ has_SD = (p.shut_down_var_index >= 0);
4770
4791
  // Clear all start-ups and shut-downs at t >= bb.
4771
4792
  if(has_SU) p.resetStartUps(bb);
4772
4793
  if(has_SD) p.resetShutDowns(bb);
@@ -5005,6 +5026,8 @@ class VirtualMachine {
5005
5026
  } else if(l.multiplier === VM.LM_SHUTDOWN) {
5006
5027
  // Similar to STARTUP, but now look in the shut-down list.
5007
5028
  pl = (p.shut_downs.indexOf(bt) < 0 ? 0 : 1);
5029
+ } else if(l.multiplier === VM.LM_AVAILABLE_CAPACITY) {
5030
+ pl = p.upper_bound.result(bt) - pl;
5008
5031
  } else if(l.multiplier === VM.LM_INCREASE) {
5009
5032
  const ppl = p.actualLevel(bt - 1);
5010
5033
  pl = this.severestIssue([pl, ppl], pl - ppl);
@@ -5171,11 +5194,11 @@ class VirtualMachine {
5171
5194
  MODEL.products_with_negative_delays = {};
5172
5195
  b = bb;
5173
5196
  for(let i = 0; i < cbl; i++) {
5174
- // NOTE: Issues with cost price calculation beyond simulation
5175
- // period need not be reported.
5176
5197
  if(b <= this.nr_of_time_steps && !MODEL.calculateCostPrices(b)) {
5177
- this.logMessage(block, `${this.WARNING}(t=${b}) ` +
5178
- 'Invalid cost prices due to negative flow(s)');
5198
+ // NOTE: Issues with cost price calculation beyond simulation
5199
+ // period need not be reported unless model is set to ignore this.
5200
+ if(!MODEL.ignore_negative_flows) this.logMessage(block,
5201
+ `${this.WARNING}(t=${b}) Invalid cost prices due to negative flow(s)`);
5179
5202
  }
5180
5203
  // Move on to the next time step of the block.
5181
5204
  b++;
@@ -6423,6 +6446,8 @@ Solver status = ${json.status}`);
6423
6446
  this.MINUS_INFINITY = this.SOLVER_MINUS_INFINITY;
6424
6447
  console.log('DIAGNOSIS OFF');
6425
6448
  }
6449
+ this.NEAR_PLUS_INFINITY = this.PLUS_INFINITY / 200;
6450
+ this.NEAR_MINUS_INFINITY = this.MINUS_INFINITY / 200;
6426
6451
  // The "propt to diagnose" flag is set when some block posed an
6427
6452
  // infeasible or unbounded problem.
6428
6453
  this.prompt_to_diagnose = false;
@@ -8538,9 +8563,12 @@ function VMI_update_cash_coefficient(args) {
8538
8563
  // The ON/OFF variable index is passed as third argument, hence `plvi`
8539
8564
  // (process level variable index) as first extra parameter, plus three
8540
8565
  // expressions (UB, price, rate).
8566
+ // NOTE: This type is also used to compute "available capacity".
8541
8567
  const
8542
- plvi = args[4],
8543
- // NOTE: Column of second variable will be relative to same offset.
8568
+ // args[4] = -1 signals that the remaining capacity should be
8569
+ // computed, which means that ON/OFF should be disregarded.
8570
+ plvi = (args[4] < 0 ? vi : args[4]),
8571
+ // Column of second variable will be relative to same offset.
8544
8572
  plk = k + plvi - vi,
8545
8573
  ub = args[5].result(VM.t),
8546
8574
  price_rate = args[6].result(VM.t) * args[7].result(VM.t);
@@ -9198,6 +9226,44 @@ function VMI_add_peak_increase_at_t_0(args) {
9198
9226
  // series of coefficient-setting instructions
9199
9227
  }
9200
9228
 
9229
+ function VMI_add_available_capacity(link) {
9230
+ // Adds the "available capacity" of the FROM node (process) to the
9231
+ // level of the TO node (data product) while considering the delay.
9232
+ // NOTE: New instruction style that passes pointers to model entities
9233
+ // instead of their properties.
9234
+ const
9235
+ d = link.actualDelay(VM.t),
9236
+ fnvi = link.from_node.level_var_index,
9237
+ // Column number in the tableau.
9238
+ fnk = VM.offset + fnvi - d * VM.cols,
9239
+ // Use flow rate and upper bound for t minus delay.
9240
+ t = VM.t - d,
9241
+ r = link.relative_rate.result(t),
9242
+ u = link.from_node.upper_bound.result(t);
9243
+ if(DEBUGGING) {
9244
+ console.log('VMI_add_available_capacity (t = ' + VM.t + ')',
9245
+ link.displayName, 'UB', u, 'rate', r);
9246
+ }
9247
+ // Available capacity equals UB - level, so subtract UB * rate
9248
+ // from RHS...
9249
+ VM.rhs -= u * r;
9250
+ // ... and subtract rate from FROM node coefficient.
9251
+ if(fnk <= 0) {
9252
+ // NOTE: If `fnk` falls PRIOR to the start of the block being solved,
9253
+ // this means that the value of the decision variable X for which the
9254
+ // coefficient C is to be set by this instruction has been calculated
9255
+ // while solving a previous block. Since the value of X is known,
9256
+ // adding X*rate to C is implemented as subtracting X*rate from the
9257
+ // right hand side of the constraint.
9258
+ VM.rhs += knownValue(fnvi, t) * r;
9259
+ } else if(fnk in VM.coefficients) {
9260
+ VM.coefficients[fnk] -= r;
9261
+ } else {
9262
+ VM.coefficients[fnk] = -r;
9263
+ }
9264
+ }
9265
+
9266
+
9201
9267
  // NOTE: the global constants below are not defined in linny-r-globals.js
9202
9268
  // because some comprise the identifiers of functions for VM instructions
9203
9269