<commit_before>"use strict";

class claraConfigurator {
  constructor(config) {
    this.api                    = null;
    this.claraSceneId           = null;
    this.playerDivId            = null;
    this.configuratorDivId      = null;
    this.configuratorInputDivId = null;
    this.configuratorForm       = null;
    this.addtocartClassName     = null;
    this.addtocartButton        = null;
    this.addtocartEnabled       = false;
    this.variation_idClassName  = null;
    this.variation_idInput      = null;
    this.variationInputId       = null;
    this.variationInputDiv      = null;
    this.priceId                = null;
    this.priceDiv               = null;
    /*
    *
    */
    this.attributes           = null;
    /*
    *
    */
    this.available_attributes = null;

    this.usingAddons          = false;

    if (config) {
      var self = this;
      // init variables
      this.playerDivId            = config.playerDivId;
      this.configuratorDivId      = config.configuratorDivId;
      this.claraSceneId           = config.claraSceneId;
      this.attributes             = config.attributes;
      this.available_attributes   = config.available_attributes;
      this.configuratorInputDivId = config.configuratorInputDivId;
      this.addtocartClassName     = config.addtocartClassName;
      this.variation_idClassName  = config.variation_idClassName;
      this.variationInputId       = config.variationInputId;
      this.priceId                = config.priceId;
      this.usingAddons            = config.usingAddons;

      this.variation_idInput = document.getElementsByClassName(this.variation_idClassName)[0];
      this.variationInputDiv = document.getElementById(this.variationInputId);
      this.addtocartButton = document.getElementsByClassName(this.addtocartClassName)[0];
      this.priceDiv = document.getElementById(this.priceId);

      if (this.addtocartButton) {
        this.addtocartButton.onclick = (ev) => {
          if (!self.addtocartEnabled) {
            event.preventDefault();
          }
        };
      }

    }

    this._initClara();
  }

  _initClara() {
    var self = this;
    // Fetch and initialize the sceneId
    this.api = claraplayer(this.playerDivId);
    this.api.sceneIO
      .fetchAndUse(this.claraSceneId, null, { waitForPublish: true })
      .then(() => {

        // use the first form in the scene
        self._getConfiguratorForm();

        var configuratorEl = document.getElementById(self.configuratorDivId);

        if (self.configuratorForm && configuratorEl) {
          self.api.configuration.initConfigurator({
            id    : self.claraSceneId,
            form  : self.configuratorForm,
            el    : configuratorEl
          });

          if (self.usingAddons) {
            self.api.on('configurationChange', (ev) => {
              self._onConfigurationChangeAddon();
            });
          }
          else {
            self.api.on('configurationChange', (ev) => {
              self._onConfigurationChange();
            });
          }

        }
      });
  }

  _getConfiguratorForm() {
    if (!this.api) {
      return;
    }
    var forms = this.api.configuration.getForms();
    if (forms.length > 0) {
      this.configuratorForm = forms[0].name;
    }
  }

  _onConfigurationChangeAddon() {
    var self = this;
    var config = this.api.configuration.getConfiguration();
    console.log(config);
    console.log(this.attributes);
  }

  _onConfigurationChange() {
    var self = this;
    var config = this.api.configuration.getConfiguration();
    console.log(config);

    var configuratorInputDiv = document.getElementById(this.configuratorInputDivId);
    if (!configuratorInputDiv) {
      return;
    }

    // check if config attribute name and value exist for the current product
    var additionalAttrs = [];
    var attrValueTobeSubmited = [];
    if (Object.keys(this.attributes).length < Object.keys(config).length) {
      console.warn("Threekit attribute number is smaller than in WooCommerce, product will not be able to added to cart");
    }
    for (var key in config) {
      // looking for "key" in attributes
      var found = false;
      var legal = true;
      for (var ele in this.attributes) {
        // remove "pa_"
        var trimEle = ele;
        if (trimEle.startsWith('pa_')) {
          trimEle = trimEle.substr(3);
        }
        if (this.ignoreCaseStrcmp(trimEle, key)) {
          found = true;
          if (!this.ignoreCaseIncludes(this.attributes[ele], config[key])) {
            // config attribute value is illegal
            legal = false;
          }
          break;
        }
      }
      if (!legal) {
        this._disableAddtocartButton();
        return;
      }
      if (!found) {
        // additional attributes will be posted to server as text
        additionalAttrs.push(key);
      }
    }

    /*
    *  Check if the product is available
    *  Attributes in WooCommerce can be overlapping,
    *  using the first matching attribute in this.available_attributes
    */
    var foundMatch = false;
    var selectedVaration = {};
    for (var i = 0; i < this.available_attributes.length; i++) {
      var attrs = this.available_attributes[i].attributes;
      if (Object.keys(attrs).length != Object.keys(config).length) {
        continue;
      }
      var match = true;
      selectedVaration = {};
      for (var key in config) {
        var found = false;
        for(var ele in attrs) {
          // remove "attribute_pa_"
          var trimEle = ele;
          if (trimEle.startsWith('attribute_pa_')) {
            trimEle = trimEle.substr(13);
          }
          if (this.ignoreCaseStrcmp(trimEle, key)) {
            if (attrs[ele] === "" || this.ignoreCaseStrcmp(attrs[ele], config[key])) {
              found = true;
              selectedVaration[ele] = config[key].toLowerCase();
              break;
            }
          }
        }
        if (!found) {
          // matching fail
          match = false;
          break;
        }
      }
      if (match && this.available_attributes[i].is_in_stock && this.available_attributes[i].is_purchasable) {
        // find a match!
        foundMatch = true;

        this.priceDiv.innerHTML = '$' + this.available_attributes[i].display_price;
        console.log(this.available_attributes[i].variation_id);
        this._enableAddtocartButton();
        this.variation_idInput.setAttribute('value', this.available_attributes[i].variation_id);

        if (this.variationInputDiv.hasChildNodes()) {
          // remove all child
          while (this.variationInputDiv.firstChild) {
            this.variationInputDiv.removeChild(this.variationInputDiv.firstChild);
          }
        }
        for (var key in selectedVaration) {
          var keyInput = document.createElement('input');
          keyInput.setAttribute('name', key);
          keyInput.setAttribute('value', selectedVaration[key]);
          keyInput.setAttribute('type','hidden');
          this.variationInputDiv.appendChild(keyInput);
        }
        break;
      }
    }
    if (!foundMatch) {
      this._disableAddtocartButton();
    }

    // calculate price

  }

  _disableAddtocartButton() {
    if (!this.addtocartButton) {
      return;
    }
    this.addtocartEnabled = false;
    this.addtocartButton.classList.add('disabled');
    if (this.priceDiv) {
      this.priceDiv.innerHTML = '$';
    }
  }

  _enableAddtocartButton() {
    if (!this.addtocartButton) {
      return;
    }
    this.addtocartEnabled = true;
    this.addtocartButton.classList.remove('disabled');
  }

  /*
  * Utility functions
  */
  ignoreCaseStrcmp(str1, str2) {
    return str1.toLowerCase() === str2.toLowerCase();
  }
  ignoreCaseIncludes(arr, ele) {
    var self = this;
    for (var iter in arr) {
      if (self.ignoreCaseStrcmp(arr[iter], ele)) {
        return true;
      }
    }
    return false;
  }
}

(function() {
  var opts = {
    addtocartClassName    : 'single_add_to_cart_button',
    variation_idClassName : 'variation_id',
    variationInputId      : 'threekit-add-to-cart-inputs',
    playerDivId           : 'clara-player',
    configuratorDivId     : 'panel-embed',
    configuratorInputDivId: 'threekit-add-to-cart-inputs',
    priceId               : 'threekit_price',
    claraSceneId          : php_vars.clarauuid,
    available_attributes  : php_vars.available_attributes,
    attributes            : php_vars.attributes,
    usingAddons           : php_vars.usingAddons
  };
  var cc = new claraConfigurator(opts);

}());
<commit_msg>post data to server<commit_after>"use strict";

class claraConfigurator {
  constructor(config) {
    this.api                    = null;
    this.claraSceneId           = null;
    this.playerDivId            = null;
    this.configuratorDivId      = null;
    this.configuratorInputDivId = null;
    this.configuratorForm       = null;
    this.addtocartClassName     = null;
    this.addtocartButton        = null;
    this.addtocartEnabled       = false;
    this.variation_idClassName  = null;
    this.variation_idInput      = null;
    this.variationInputId       = null;
    this.variationInputDiv      = null;
    this.priceId                = null;
    this.priceDiv               = null;
    /*
    *
    */
    this.attributes           = null;
    /*
    *
    */
    this.available_attributes = null;

    this.usingAddons          = false;

    if (config) {
      var self = this;
      // init variables
      this.playerDivId            = config.playerDivId;
      this.configuratorDivId      = config.configuratorDivId;
      this.claraSceneId           = config.claraSceneId;
      this.attributes             = config.attributes;
      this.available_attributes   = config.available_attributes;
      this.configuratorInputDivId = config.configuratorInputDivId;
      this.addtocartClassName     = config.addtocartClassName;
      this.variation_idClassName  = config.variation_idClassName;
      this.variationInputId       = config.variationInputId;
      this.priceId                = config.priceId;
      this.usingAddons            = config.usingAddons;

      this.variation_idInput = document.getElementsByClassName(this.variation_idClassName)[0];
      this.variationInputDiv = document.getElementById(this.variationInputId);
      this.addtocartButton = document.getElementsByClassName(this.addtocartClassName)[0];
      this.priceDiv = document.getElementById(this.priceId);

      if (this.addtocartButton) {
        this.addtocartButton.onclick = (ev) => {
          if (!self.addtocartEnabled) {
            event.preventDefault();
          }
        };
      }

    }

    this._initClara();
  }

  _initClara() {
    var self = this;
    // Fetch and initialize the sceneId
    this.api = claraplayer(this.playerDivId);
    this.api.sceneIO
      .fetchAndUse(this.claraSceneId, null, { waitForPublish: true })
      .then(() => {

        // use the first form in the scene
        self._getConfiguratorForm();

        var configuratorEl = document.getElementById(self.configuratorDivId);

        if (self.configuratorForm && configuratorEl) {
          self.api.configuration.initConfigurator({
            id    : self.claraSceneId,
            form  : self.configuratorForm,
            el    : configuratorEl
          });

          if (self.usingAddons) {
            self.api.on('configurationChange', (ev) => {
              self._onConfigurationChangeAddon();
            });
          }
          else {
            self.api.on('configurationChange', (ev) => {
              self._onConfigurationChange();
            });
          }

        }
      });
  }

  _getConfiguratorForm() {
    if (!this.api) {
      return;
    }
    var forms = this.api.configuration.getForms();
    if (forms.length > 0) {
      this.configuratorForm = forms[0].name;
    }
  }

  _onConfigurationChangeAddon() {
    var self = this;
    var config = this.api.configuration.getConfiguration();
    console.log(config);
    console.log(this.attributes);

    var configuratorInputDiv = document.getElementById(this.configuratorInputDivId);
    if (!configuratorInputDiv) {
      return;
    }

    var selectedVaration = {};

    for (var key in config) {
      // looking for key in attributes
      var nameFound = false;
      for (var ele in this.attributes) {
        nameFound = true;
        if (key === this.attributes[ele].name) {
          switch (this.attributes[ele].type) {
            case 'select':
              // looking for config[key] in attributes[ele].options
              var optionFound = false;
              for (var opt in this.attributes[ele].options) {
                if (config[key] === this.attributes[ele].options[opt].label) {
                  optionFound = true;
                  // add input to form
                  var tailNumber = opt + 1;
                  selectedVaration['addon-' + this.attributes[ele]['field-name']] = config[key].toLowerCase() + tailNumber;
                  // calculate price
                }
              }
              if ( !optionFound ) {
                console.warn("Option " + config[key] + " not found in " + key);
              }
            break;
            case 'checkbox':
              if (config[key]) {
                selectedVaration['addon-' + this.attributes[ele]['field-name'] + '[]'] = this.attributes[ele].options[0].label;
              }
            break;
            case 'custom':
              selectedVaration['addon-' + this.attributes[ele]['field-name'] + '[0]' = config[key];
            break;
          }
        }
      }
      if (!nameFound) {
        console.warn("Configuration " + key + " not found, unable to post to server");
      }
    }

    if (this.variationInputDiv.hasChildNodes()) {
      // remove all child
      while (this.variationInputDiv.firstChild) {
        this.variationInputDiv.removeChild(this.variationInputDiv.firstChild);
      }
    }

    for (var key in selectedVaration) {
      var keyInput = document.createElement('input');
      keyInput.setAttribute('name', key);
      keyInput.setAttribute('value', selectedVaration[key]);
      keyInput.setAttribute('type','hidden');
      this.variationInputDiv.appendChild(keyInput);
    }
  }

  _onConfigurationChange() {
    var self = this;
    var config = this.api.configuration.getConfiguration();
    console.log(config);

    var configuratorInputDiv = document.getElementById(this.configuratorInputDivId);
    if (!configuratorInputDiv) {
      return;
    }

    // check if config attribute name and value exist for the current product
    var additionalAttrs = [];
    var attrValueTobeSubmited = [];
    if (Object.keys(this.attributes).length < Object.keys(config).length) {
      console.warn("Threekit attribute number is smaller than in WooCommerce, product will not be able to added to cart");
    }
    for (var key in config) {
      // looking for "key" in attributes
      var found = false;
      var legal = true;
      for (var ele in this.attributes) {
        // remove "pa_"
        var trimEle = ele;
        if (trimEle.startsWith('pa_')) {
          trimEle = trimEle.substr(3);
        }
        if (this.ignoreCaseStrcmp(trimEle, key)) {
          found = true;
          if (!this.ignoreCaseIncludes(this.attributes[ele], config[key])) {
            // config attribute value is illegal
            legal = false;
          }
          break;
        }
      }
      if (!legal) {
        this._disableAddtocartButton();
        return;
      }
      if (!found) {
        // additional attributes will be posted to server as text
        additionalAttrs.push(key);
      }
    }

    /*
    *  Check if the product is available
    *  Attributes in WooCommerce can be overlapping,
    *  using the first matching attribute in this.available_attributes
    */
    var foundMatch = false;
    var selectedVaration = {};
    for (var i = 0; i < this.available_attributes.length; i++) {
      var attrs = this.available_attributes[i].attributes;
      if (Object.keys(attrs).length != Object.keys(config).length) {
        continue;
      }
      var match = true;
      selectedVaration = {};
      for (var key in config) {
        var found = false;
        for(var ele in attrs) {
          // remove "attribute_pa_"
          var trimEle = ele;
          if (trimEle.startsWith('attribute_pa_')) {
            trimEle = trimEle.substr(13);
          }
          if (this.ignoreCaseStrcmp(trimEle, key)) {
            if (attrs[ele] === "" || this.ignoreCaseStrcmp(attrs[ele], config[key])) {
              found = true;
              selectedVaration[ele] = config[key].toLowerCase();
              break;
            }
          }
        }
        if (!found) {
          // matching fail
          match = false;
          break;
        }
      }
      if (match && this.available_attributes[i].is_in_stock && this.available_attributes[i].is_purchasable) {
        // find a match!
        foundMatch = true;

        this.priceDiv.innerHTML = '$' + this.available_attributes[i].display_price;
        console.log(this.available_attributes[i].variation_id);
        this._enableAddtocartButton();
        this.variation_idInput.setAttribute('value', this.available_attributes[i].variation_id);

        if (this.variationInputDiv.hasChildNodes()) {
          // remove all child
          while (this.variationInputDiv.firstChild) {
            this.variationInputDiv.removeChild(this.variationInputDiv.firstChild);
          }
        }
        for (var key in selectedVaration) {
          var keyInput = document.createElement('input');
          keyInput.setAttribute('name', key);
          keyInput.setAttribute('value', selectedVaration[key]);
          keyInput.setAttribute('type','hidden');
          this.variationInputDiv.appendChild(keyInput);
        }
        break;
      }
    }
    if (!foundMatch) {
      this._disableAddtocartButton();
    }

    // calculate price

  }

  _disableAddtocartButton() {
    if (!this.addtocartButton) {
      return;
    }
    this.addtocartEnabled = false;
    this.addtocartButton.classList.add('disabled');
    if (this.priceDiv) {
      this.priceDiv.innerHTML = '$';
    }
  }

  _enableAddtocartButton() {
    if (!this.addtocartButton) {
      return;
    }
    this.addtocartEnabled = true;
    this.addtocartButton.classList.remove('disabled');
  }

  /*
  * Utility functions
  */
  ignoreCaseStrcmp(str1, str2) {
    return str1.toLowerCase() === str2.toLowerCase();
  }
  ignoreCaseIncludes(arr, ele) {
    var self = this;
    for (var iter in arr) {
      if (self.ignoreCaseStrcmp(arr[iter], ele)) {
        return true;
      }
    }
    return false;
  }
}

(function() {
  var opts = {
    addtocartClassName    : 'single_add_to_cart_button',
    variation_idClassName : 'variation_id',
    variationInputId      : 'threekit-add-to-cart-inputs',
    playerDivId           : 'clara-player',
    configuratorDivId     : 'panel-embed',
    configuratorInputDivId: 'threekit-add-to-cart-inputs',
    priceId               : 'threekit_price',
    claraSceneId          : php_vars.clarauuid,
    available_attributes  : php_vars.available_attributes,
    attributes            : php_vars.attributes,
    usingAddons           : php_vars.usingAddons
  };
  var cc = new claraConfigurator(opts);

}());
<|endoftext|>


<commit_before>/* eslint-disable no-template-curly-in-string */
const b = require('substance-bundler')
const fs = require('fs')
const path = require('path')
const fork = require('substance-bundler/extensions/fork')
const vfs = require('substance-bundler/extensions/vfs')
const yazl = require('yazl')

const DIST = 'dist/'
const APPDIST = 'app-dist/'
const TMP = 'tmp/'
const RNG_SEARCH_DIRS = [
  path.join(__dirname, 'src', 'article')
]
const JATS = 'JATS-archiving'
const RNG_FILES = [
  `src/article/${JATS}.rng`,
  'src/article/TextureJATS.rng'
]

// Server configuration
let port = process.env['PORT'] || 4000
b.setServerPort(port)
b.yargs.option('d', {
  type: 'string',
  alias: 'rootDir',
  describe: 'Root directory of served archives'
})
let argv = b.yargs.argv
if (argv.d) {
  const serve = require('./src/dar/serve')
  const rootDir = argv.d
  const archiveDir = path.resolve(path.join(__dirname, rootDir))
  serve(b.server, {
    port,
    serverUrl: 'http://localhost:' + port,
    rootDir: archiveDir,
    apiUrl: '/archives'
  })
}
b.serve({ static: true, route: '/', folder: './dist' })

// Make Targets

b.task('clean', function () {
  b.rm(DIST)
  b.rm(TMP)
  b.rm(APPDIST)
}).describe('removes all generated files and folders.')

b.task('lib', ['clean', 'build:schema', 'build:assets', 'build:lib'])
  .describe('builds the library bundle.')

b.task('browser', ['clean', 'build:schema', 'build:assets', 'build:browser'])
  .describe('builds the browser bundle.')

b.task('publish', ['clean', 'build:schema', 'build:assets', 'build:lib', 'build:web'])
  .describe('builds the release bundle (library + web).')

b.task('web', ['clean', 'build:schema', 'build:assets', 'build:browser', 'build:web'])
  .describe('builds the web bundle (browser + web).')

b.task('app', ['clean', 'build:schema', 'build:assets', 'build:browser', 'build:app'])
  .describe('builds the app bundle (electron app).')

b.task('test-nodejs', ['clean', 'build:schema', 'build:test-assets'])
  .describe('prepares everything necessary to run tests in node.')

b.task('test-browser', ['clean', 'build:schema', 'build:browser', 'build:test-assets', 'build:test-browser'])
  .describe('builds the test-suite for the browser.')

// an alias because in all our other projects it is named this way
b.task('test:browser', ['test-browser'])

b.task('default', ['publish'])
  .describe('default: publish')

// spawns electron after build is ready
b.task('run-app', ['app'], () => {
  // Note: `await=false` is important, as otherwise bundler would await this to finish
  fork(b, require.resolve('electron/cli.js'), '.', { verbose: true, cwd: APPDIST, await: false })
})
  .describe('runs the application in electron.')

// low-level make targets

b.task('schema:jats', () => {
  _compileSchema(JATS, RNG_FILES[0], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 1))
})

b.task('schema:texture-article', () => {
  _compileSchema('TextureJATS', RNG_FILES[1], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 2))
  b.custom(`Copy schema documentation...`, {
    src: './tmp/TextureJATS.schema.md',
    dest: './docs/TextureJATS.md',
    execute () {
      b.copy('./tmp/TextureJATS.schema.md', './docs/TextureJATS.md')
    }
  })
})

b.task('schema:debug', () => {
  _compileSchema(JATS, RNG_FILES[0], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 1), { debug: true })
  _compileSchema('TextureJATS', RNG_FILES[1], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 2), { debug: true })
})

b.task('build:assets', function () {
  b.copy('./node_modules/font-awesome', DIST + 'font-awesome')
  b.copy('./node_modules/inter-ui', DIST + 'inter-ui')
  b.copy('./node_modules/katex/dist', DIST + 'katex')
  b.copy('./node_modules/substance/dist', DIST + 'substance/dist')
  b.css('texture.css', DIST + 'texture.css')
  b.css('texture-reset.css', DIST + 'texture-reset.css')
})

b.task('build:schema', ['schema:jats', 'schema:texture-article'])

b.task('build:browser', () => {
  _buildLib(DIST, 'browser')
})

b.task('build:nodejs', () => {
  _buildLib(DIST, 'nodejs')
})

b.task('build:lib', () => {
  _buildLib(DIST, 'all')
})

b.task('build:cover', () => {
  _buildLib(TMP, 'cover')
})

b.task('build:app', ['build:app:dars'], () => {
  b.copy('app/index.html', APPDIST)
  b.copy('app/build-resources', APPDIST)
  // FIXME: this command leads to an extra run when a  file is updated
  // .. instead copying the files explicitly for now
  // b.copy('dist', APPDIST+'lib/')
  b.copy('dist/font-awesome', APPDIST + 'lib/')
  b.copy('dist/katex', APPDIST + 'lib/')
  b.copy('dist/inter-ui', APPDIST + 'lib/')
  b.copy('dist/substance', APPDIST + 'lib/')
  ;[
    'texture.js',
    'texture.css',
    'texture-reset.css'
  ].forEach(f => {
    b.copy(`dist/${f}`, APPDIST + 'lib/')
    b.copy(`dist/${f}.map`, APPDIST + 'lib/')
  })

  // TODO: maybe we could come up with an extension
  // that expands a source file using a given dict.
  b.custom('Creating application package.json...', {
    src: 'app/package.json.in',
    dest: APPDIST + 'package.json',
    execute () {
      let { version, dependencies, devDependencies } = require('./package.json')
      let tpl = fs.readFileSync('app/package.json.in', 'utf8')
      let out = tpl.replace('${version}', version)
        .replace('${electronVersion}', devDependencies.electron)
        .replace('${dependencies}', JSON.stringify(dependencies))
      fs.writeFileSync(APPDIST + 'package.json', out)
    }
  })
  b.js('app/main.js', {
    output: [{
      file: APPDIST + 'main.js',
      format: 'cjs'
    }],
    external: ['electron', 'path', 'url']
  })
  b.js('app/app.js', {
    output: [{
      file: APPDIST + 'app.js',
      format: 'umd',
      name: 'textureApp',
      globals: {
        'substance': 'substance',
        'substance-texture': 'texture',
        'katex': 'katex'
      }
    }],
    external: [ 'substance', 'substance-texture', 'katex' ]
  })
  // execute 'install-app-deps'
  fork(b, require.resolve('electron-builder/out/cli/cli.js'), 'install-app-deps', { verbose: true, cwd: APPDIST, await: true })
})

b.task('build:app:dars', () => {
  // templates
  _packDar('data/blank', APPDIST + 'templates/blank.dar')
  _packDar('data/blank-figure-package', APPDIST + 'templates/blank-figure-package.dar')
  // examples
  _packDar('data/elife-32671', APPDIST + 'examples/elife-32671.dar')
  _packDar('data/kitchen-sink', APPDIST + 'examples/kitchen-sink.dar')
})

b.task('build:vfs', () => {
  vfs(b, {
    src: ['./data/**/*'],
    dest: DIST + 'vfs.js',
    format: 'umd',
    moduleName: 'vfs',
    rootDir: path.join(__dirname, 'data')
  })
})

b.task('_copy-data-folder', () => {
  b.copy('./data', DIST + 'data')
})

b.task('build:web', ['build:vfs', '_copy-data-folder'], () => {
  b.copy('web/index.html', DIST)
  b.js('./web/editor.js', {
    output: [{
      file: DIST + 'editor.js',
      format: 'umd',
      name: 'textureEditor',
      globals: {
        'substance': 'substance',
        'substance-texture': 'texture',
        'katex': 'katex'
      }
    }],
    external: ['substance', 'substance-texture', 'katex']
  })
})

b.task('build:test-assets', ['build:vfs', '_copy-data-folder', 'build:app:dars'], () => {
  vfs(b, {
    src: ['./test/fixture/**/*.xml'],
    dest: DIST + 'test/test-vfs.js',
    format: 'umd',
    moduleName: 'TEST_VFS',
    rootDir: path.join(__dirname, 'test', 'fixture')
  })
})

b.task('build:test-browser', ['build:assets', 'build:test-assets'], () => {
  b.copy('test/index.html', 'dist/test/index.html')
  b.copy('test/_test.css', 'dist/test/_test.css')
  b.copy('node_modules/substance-test/dist/testsuite.js', 'dist/test/testsuite.js')
  b.copy('node_modules/substance-test/dist/test.css', 'dist/test/test.css')

  // NOTE: by declaring texture/index.js as external we manage to serve both environments, browser and nodejs
  // with the same code.
  // In the browser, texture is used via the regular texture bundle, in nodejs it is resolved in the regular way
  const INDEX_JS = path.join(__dirname, 'index.js')
  const TEST_VFS = path.join(__dirname, 'tmp', 'test-vfs.js')
  let globals = {
    'substance': 'substance',
    'substance-test': 'substanceTest',
    'katex': 'katex',
    // TODO: this should be done in the same way as INDEX_JS and TEST_VFS
    'vfs': 'vfs'
  }
  globals[INDEX_JS] = 'texture'
  globals[TEST_VFS] = 'testVfs'

  b.js('test/index.js', {
    output: [{
      file: 'dist/test/tests.js',
      format: 'umd',
      name: 'tests',
      globals
    }],
    external: [
      'substance',
      'substance-test',
      INDEX_JS,
      'katex',
      'vfs',
      TEST_VFS
    ]
  })
})

/* HELPERS */

function _buildLib (DEST, platform) {
  let targets = []
  let istanbul
  if (platform === 'browser' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.js',
      format: 'umd',
      name: 'texture',
      sourcemapRoot: __dirname,
      sourcemapPrefix: 'texture',
      globals: {
        'substance': 'substance',
        'katex': 'katex',
        'vfs': 'vfs'
      }
    })
  }
  if (platform === 'nodejs' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.cjs.js',
      format: 'cjs'
    })
  }
  if (platform === 'es' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.es.js',
      format: 'es'
    })
  }
  b.js('./index.js', {
    output: targets,
    external: ['substance', 'katex', 'vfs'],
    istanbul
  })
}

function _packDar (dataFolder, darPath) {
  b.custom(`Creating ${darPath}...`, {
    src: dataFolder + '/**/*',
    dest: darPath,
    execute (files) {
      return new Promise((resolve, reject) => {
        let zipfile = new yazl.ZipFile()
        for (let f of files) {
          let relPath = path.relative(dataFolder, f)
          zipfile.addFile(f, relPath)
        }
        zipfile.outputStream.pipe(fs.createWriteStream(darPath))
          .on('close', (err) => {
            if (err) {
              console.error(err)
              reject(err)
            } else {
              resolve()
            }
          })
        zipfile.end()
      })
    }
  })
}

function _compileSchema (name, src, searchDirs, deps, options = {}) {
  const DEST = `tmp/${name}.data.js`
  const ISSUES = `tmp/${name}.issues.txt`
  const SCHEMA = `tmp/${name}.schema.md`
  const entry = path.basename(src)
  b.custom(`Compiling schema '${name}'...`, {
    src: [src].concat(deps),
    dest: DEST,
    execute () {
      return new Promise(resolve => {
        setTimeout(() => {
          const { compileRNG, checkSchema } = require('substance')
          const xmlSchema = compileRNG(fs, searchDirs, entry)
          b.writeFileSync(DEST, `export default ${JSON.stringify(xmlSchema)}`)
          b.writeFileSync(SCHEMA, _xmlSchemaToMD(xmlSchema))
          if (options.debug) {
            const issues = checkSchema(xmlSchema)
            const issuesData = [`${issues.length} issues:`, ''].concat(issues).join('\n')
            b.writeFileSync(ISSUES, issuesData)
          }
          resolve()
        }, 250)
      })
    }
  })
}

function _xmlSchemaToMD (xmlSchema) {
  const { _analyzeSchema } = require('substance')
  const PRE_START = '
'
  const PRE_END = '
'

  let result = []
  let elementSchemas = xmlSchema._elementSchemas
  let elementNames = Object.keys(elementSchemas)
  _analyzeSchema(elementSchemas)

  elementNames.sort()
  let notImplemented = []
  result.push('# Texture Article')
  result.push('')
  result.push('This schema defines a strict sub-set of JATS-archiving 1.1 .')
  result.push('')
  result.push('## Supported Elements')
  result.push('')
  elementNames.forEach(name => {
    let elementSchema = elementSchemas[name]
    if (elementSchema.type === 'not-implemented') {
      notImplemented.push(elementSchema)
      return
    }
    result.push('### `<' + elementSchema.name + '>`')
    if (elementSchema.type === 'not-implemented') {
      result.push('Not implemented.')
    } else {
      let attributes = elementSchema.attributes
      let elementSpec = elementSchema.expr.toString()
      if (elementSpec.startsWith('(') && elementSpec.endsWith(')')) {
        elementSpec = elementSpec.slice(1, -1)
      }
      if (/^\s*$/.exec(elementSpec)) elementSpec = 'EMPTY'

      let parents = Object.keys(elementSchema.parents)
      if (parents.length === 0 && xmlSchema.getStartElement() !== name) {
        console.error('FIXME: element <%s> is not used anymore, we should remove it for now.', name)
      }

      result.push('')
      result.push('**Attributes**:')
      result.push(PRE_START)
      result.push(Object.keys(attributes).join(', '))
      result.push(PRE_END)
      result.push('**Contains**:')
      result.push(PRE_START)
      result.push(elementSpec)
      result.push(PRE_END)
      if (parents.length > 0) {
        result.push('**This element may be contained in:**')
        result.push(PRE_START)
        result.push(parents.join(', '))
        result.push(PRE_END)
      }
      result.push('')
    }
  })
  if (notImplemented.length > 0) {
    result.push('## Not Implemented')
    result.push(`
These elements have not been implemented yet and need go through the recommendation process.
If you want to contribute, go to [https://github.com/substance/texture/issues](https://github.com/substance/texture/issues)
and open a request if it does not exist yet. Please provide one ore multiple XML examples
and explanations that help understanding the use-case.
`)
    notImplemented.forEach(elementSchema => {
      result.push('- ' + elementSchema.name)
    })
  }

  return result.join('\n')
}
<commit_msg>Disable RNG compilation.<commit_after>/* eslint-disable no-template-curly-in-string */
const b = require('substance-bundler')
const fs = require('fs')
const path = require('path')
const fork = require('substance-bundler/extensions/fork')
const vfs = require('substance-bundler/extensions/vfs')
const yazl = require('yazl')

const DIST = 'dist/'
const APPDIST = 'app-dist/'
const TMP = 'tmp/'
// const RNG_SEARCH_DIRS = [
//   path.join(__dirname, 'src', 'article')
// ]
// const JATS = 'JATS-archiving'
// const RNG_FILES = [
//   `src/article/${JATS}.rng`,
//   'src/article/TextureJATS.rng'
// ]

// Server configuration
let port = process.env['PORT'] || 4000
b.setServerPort(port)
b.yargs.option('d', {
  type: 'string',
  alias: 'rootDir',
  describe: 'Root directory of served archives'
})
let argv = b.yargs.argv
if (argv.d) {
  const serve = require('./src/dar/serve')
  const rootDir = argv.d
  const archiveDir = path.resolve(path.join(__dirname, rootDir))
  serve(b.server, {
    port,
    serverUrl: 'http://localhost:' + port,
    rootDir: archiveDir,
    apiUrl: '/archives'
  })
}
b.serve({ static: true, route: '/', folder: './dist' })

// Make Targets

b.task('clean', function () {
  b.rm(DIST)
  b.rm(TMP)
  b.rm(APPDIST)
}).describe('removes all generated files and folders.')

b.task('lib', ['clean', 'build:schema', 'build:assets', 'build:lib'])
  .describe('builds the library bundle.')

b.task('browser', ['clean', 'build:schema', 'build:assets', 'build:browser'])
  .describe('builds the browser bundle.')

b.task('publish', ['clean', 'build:schema', 'build:assets', 'build:lib', 'build:web'])
  .describe('builds the release bundle (library + web).')

b.task('web', ['clean', 'build:schema', 'build:assets', 'build:browser', 'build:web'])
  .describe('builds the web bundle (browser + web).')

b.task('app', ['clean', 'build:schema', 'build:assets', 'build:browser', 'build:app'])
  .describe('builds the app bundle (electron app).')

b.task('test-nodejs', ['clean', 'build:schema', 'build:test-assets'])
  .describe('prepares everything necessary to run tests in node.')

b.task('test-browser', ['clean', 'build:schema', 'build:browser', 'build:test-assets', 'build:test-browser'])
  .describe('builds the test-suite for the browser.')

// an alias because in all our other projects it is named this way
b.task('test:browser', ['test-browser'])

b.task('default', ['publish'])
  .describe('default: publish')

// spawns electron after build is ready
b.task('run-app', ['app'], () => {
  // Note: `await=false` is important, as otherwise bundler would await this to finish
  fork(b, require.resolve('electron/cli.js'), '.', { verbose: true, cwd: APPDIST, await: false })
})
  .describe('runs the application in electron.')

// low-level make targets

b.task('schema:texture-article', () => {
  // TODO: bring this back after factoring out xml utilities and prebuilt JATS schemas
  // _compileSchema('TextureJATS', RNG_FILES[1], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 2))
  // b.custom(`Copy schema documentation...`, {
  //   src: './tmp/TextureJATS.schema.md',
  //   dest: './docs/TextureJATS.md',
  //   execute () {
  //     b.copy('./tmp/TextureJATS.schema.md', './docs/TextureJATS.md')
  //   }
  // })
})

b.task('schema:debug', () => {
  // _compileSchema('TextureJATS', RNG_FILES[1], RNG_SEARCH_DIRS, RNG_FILES.slice(0, 2), { debug: true })
})

b.task('build:assets', function () {
  b.copy('./node_modules/font-awesome', DIST + 'font-awesome')
  b.copy('./node_modules/inter-ui', DIST + 'inter-ui')
  b.copy('./node_modules/katex/dist', DIST + 'katex')
  b.copy('./node_modules/substance/dist', DIST + 'substance/dist')
  b.css('texture.css', DIST + 'texture.css')
  b.css('texture-reset.css', DIST + 'texture-reset.css')
})

b.task('build:schema', ['schema:texture-article'])

b.task('build:browser', () => {
  _buildLib(DIST, 'browser')
})

b.task('build:nodejs', () => {
  _buildLib(DIST, 'nodejs')
})

b.task('build:lib', () => {
  _buildLib(DIST, 'all')
})

b.task('build:cover', () => {
  _buildLib(TMP, 'cover')
})

b.task('build:app', ['build:app:dars'], () => {
  b.copy('app/index.html', APPDIST)
  b.copy('app/build-resources', APPDIST)
  // FIXME: this command leads to an extra run when a  file is updated
  // .. instead copying the files explicitly for now
  // b.copy('dist', APPDIST+'lib/')
  b.copy('dist/font-awesome', APPDIST + 'lib/')
  b.copy('dist/katex', APPDIST + 'lib/')
  b.copy('dist/inter-ui', APPDIST + 'lib/')
  b.copy('dist/substance', APPDIST + 'lib/')
  ;[
    'texture.js',
    'texture.css',
    'texture-reset.css'
  ].forEach(f => {
    b.copy(`dist/${f}`, APPDIST + 'lib/')
    b.copy(`dist/${f}.map`, APPDIST + 'lib/')
  })

  // TODO: maybe we could come up with an extension
  // that expands a source file using a given dict.
  b.custom('Creating application package.json...', {
    src: 'app/package.json.in',
    dest: APPDIST + 'package.json',
    execute () {
      let { version, dependencies, devDependencies } = require('./package.json')
      let tpl = fs.readFileSync('app/package.json.in', 'utf8')
      let out = tpl.replace('${version}', version)
        .replace('${electronVersion}', devDependencies.electron)
        .replace('${dependencies}', JSON.stringify(dependencies))
      fs.writeFileSync(APPDIST + 'package.json', out)
    }
  })
  b.js('app/main.js', {
    output: [{
      file: APPDIST + 'main.js',
      format: 'cjs'
    }],
    external: ['electron', 'path', 'url']
  })
  b.js('app/app.js', {
    output: [{
      file: APPDIST + 'app.js',
      format: 'umd',
      name: 'textureApp',
      globals: {
        'substance': 'substance',
        'substance-texture': 'texture',
        'katex': 'katex'
      }
    }],
    external: [ 'substance', 'substance-texture', 'katex' ]
  })
  // execute 'install-app-deps'
  fork(b, require.resolve('electron-builder/out/cli/cli.js'), 'install-app-deps', { verbose: true, cwd: APPDIST, await: true })
})

b.task('build:app:dars', () => {
  // templates
  _packDar('data/blank', APPDIST + 'templates/blank.dar')
  _packDar('data/blank-figure-package', APPDIST + 'templates/blank-figure-package.dar')
  // examples
  _packDar('data/elife-32671', APPDIST + 'examples/elife-32671.dar')
  _packDar('data/kitchen-sink', APPDIST + 'examples/kitchen-sink.dar')
})

b.task('build:vfs', () => {
  vfs(b, {
    src: ['./data/**/*'],
    dest: DIST + 'vfs.js',
    format: 'umd',
    moduleName: 'vfs',
    rootDir: path.join(__dirname, 'data')
  })
})

b.task('_copy-data-folder', () => {
  b.copy('./data', DIST + 'data')
})

b.task('build:web', ['build:vfs', '_copy-data-folder'], () => {
  b.copy('web/index.html', DIST)
  b.js('./web/editor.js', {
    output: [{
      file: DIST + 'editor.js',
      format: 'umd',
      name: 'textureEditor',
      globals: {
        'substance': 'substance',
        'substance-texture': 'texture',
        'katex': 'katex'
      }
    }],
    external: ['substance', 'substance-texture', 'katex']
  })
})

b.task('build:test-assets', ['build:vfs', '_copy-data-folder', 'build:app:dars'], () => {
  vfs(b, {
    src: ['./test/fixture/**/*.xml'],
    dest: DIST + 'test/test-vfs.js',
    format: 'umd',
    moduleName: 'TEST_VFS',
    rootDir: path.join(__dirname, 'test', 'fixture')
  })
})

b.task('build:test-browser', ['build:assets', 'build:test-assets'], () => {
  b.copy('test/index.html', 'dist/test/index.html')
  b.copy('test/_test.css', 'dist/test/_test.css')
  b.copy('node_modules/substance-test/dist/testsuite.js', 'dist/test/testsuite.js')
  b.copy('node_modules/substance-test/dist/test.css', 'dist/test/test.css')

  // NOTE: by declaring texture/index.js as external we manage to serve both environments, browser and nodejs
  // with the same code.
  // In the browser, texture is used via the regular texture bundle, in nodejs it is resolved in the regular way
  const INDEX_JS = path.join(__dirname, 'index.js')
  const TEST_VFS = path.join(__dirname, 'tmp', 'test-vfs.js')
  let globals = {
    'substance': 'substance',
    'substance-test': 'substanceTest',
    'katex': 'katex',
    // TODO: this should be done in the same way as INDEX_JS and TEST_VFS
    'vfs': 'vfs'
  }
  globals[INDEX_JS] = 'texture'
  globals[TEST_VFS] = 'testVfs'

  b.js('test/index.js', {
    output: [{
      file: 'dist/test/tests.js',
      format: 'umd',
      name: 'tests',
      globals
    }],
    external: [
      'substance',
      'substance-test',
      INDEX_JS,
      'katex',
      'vfs',
      TEST_VFS
    ]
  })
})

/* HELPERS */

function _buildLib (DEST, platform) {
  let targets = []
  let istanbul
  if (platform === 'browser' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.js',
      format: 'umd',
      name: 'texture',
      sourcemapRoot: __dirname,
      sourcemapPrefix: 'texture',
      globals: {
        'substance': 'substance',
        'katex': 'katex',
        'vfs': 'vfs'
      }
    })
  }
  if (platform === 'nodejs' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.cjs.js',
      format: 'cjs'
    })
  }
  if (platform === 'es' || platform === 'all') {
    targets.push({
      file: DEST + 'texture.es.js',
      format: 'es'
    })
  }
  b.js('./index.js', {
    output: targets,
    external: ['substance', 'katex', 'vfs'],
    istanbul
  })
}

function _packDar (dataFolder, darPath) {
  b.custom(`Creating ${darPath}...`, {
    src: dataFolder + '/**/*',
    dest: darPath,
    execute (files) {
      return new Promise((resolve, reject) => {
        let zipfile = new yazl.ZipFile()
        for (let f of files) {
          let relPath = path.relative(dataFolder, f)
          zipfile.addFile(f, relPath)
        }
        zipfile.outputStream.pipe(fs.createWriteStream(darPath))
          .on('close', (err) => {
            if (err) {
              console.error(err)
              reject(err)
            } else {
              resolve()
            }
          })
        zipfile.end()
      })
    }
  })
}
<|endoftext|>


<commit_before>'use strict';

const {
  app,
  Menu,
  Tray,
  BrowserWindow,
  globalShortcut,
  ipcMain,
  clipboard,
  dialog,
  shell } = require('electron');

const path     = require('path');
const platform = require('os').platform();

let mainWindow    = null;
let tray          = null;
let updateOffered = false;

// Hide the icon from the dock if the OS has it.
if (app.dock) {
  app.dock.hide();
}

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    frame: false,
    height: 396,
    width: 300,
    backgroundColor: '#2B2F3B',
    resizable: false,
    center: true,
    skipTaskbar: true,
    show: false,
    title: 'Brownie'
  });

  // The trigger used to show/hide the app window.
  // TODO: allow user to set a custom shortcut.
  globalShortcut.register('Alt+Space', () => {
    if (mainWindow.isVisible()) {
      if (app.hide) {
        // NOTE: to get focus back to the previous window on MacOS we need to
        // hide the app not only the window.
        app.hide();
      } else {
        // NOTE: Windows doesn't have app.hide method, but combination of
        // window.blur and window.hide does the same thing.
        mainWindow.blur();
        mainWindow.hide()
      }
    } else {
      mainWindow.show();
    }
  });

  if (platform === 'darwin') {
    tray = new Tray(path.join(__dirname, 'img', 'iconTemplate.png'));
  } else {
    tray = new Tray(path.join(__dirname, 'img', 'iconHighlight.png'));
  }

  const contextMenu = Menu.buildFromTemplate([
    { label: 'Clear clipboard history', click(item, focusedWindow) {
      mainWindow.webContents.send('clearClipboardHistory');
    }},
    { type: 'separator' },
    { label: 'Quit Olden', click(item, focusedWindow) {
      app.quit();
    }}
  ]);

  tray.setToolTip('Olden')
  tray.setContextMenu(contextMenu)

  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.setVisibleOnAllWorkspaces(true);
  // TODO: execute the line below based on the input argument value.
  // mainWindow.webContents.openDevTools();

  ipcMain.on('hideWindow', (event) => {
    if (app.hide) {
        app.hide();
      } else {
        mainWindow.blur();
        mainWindow.hide()
      }
  });

  ipcMain.on('offer-update', (event, data) => {
    if (!updateOffered) {
      dialog.showMessageBox({
        type:      'question',
        buttons:   [ 'Cancel', 'Download' ],
        defaultId: 0,
        title:     'A newer version of Olden is available',
        message:   'Would you like to download the update?'
      }, (response) => {
        if (response === 1) {
          shell.openExternal(data.url);
        }

        updateOffered = true;
      });
    }
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On MacOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
<commit_msg>Uses process.platform to get OS version.<commit_after>'use strict';

const {
  app,
  Menu,
  Tray,
  BrowserWindow,
  globalShortcut,
  ipcMain,
  clipboard,
  dialog,
  shell } = require('electron');

const path = require('path');

let mainWindow    = null;
let tray          = null;
let updateOffered = false;

// Hide the icon from the dock if the OS has it.
if (app.dock) {
  app.dock.hide();
}

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    frame: false,
    height: 396,
    width: 300,
    backgroundColor: '#2B2F3B',
    resizable: false,
    center: true,
    skipTaskbar: true,
    show: false,
    title: 'Brownie'
  });

  // The trigger used to show/hide the app window.
  // TODO: allow user to set a custom shortcut.
  globalShortcut.register('Alt+Space', () => {
    if (mainWindow.isVisible()) {
      if (app.hide) {
        // NOTE: to get focus back to the previous window on MacOS we need to
        // hide the app not only the window.
        app.hide();
      } else {
        // NOTE: Windows doesn't have app.hide method, but combination of
        // window.blur and window.hide does the same thing.
        mainWindow.blur();
        mainWindow.hide()
      }
    } else {
      mainWindow.show();
    }
  });

  if (process.platform === 'darwin') {
    tray = new Tray(path.join(__dirname, 'img', 'iconTemplate.png'));
  } else {
    tray = new Tray(path.join(__dirname, 'img', 'iconHighlight.png'));
  }

  const contextMenu = Menu.buildFromTemplate([
    { label: 'Clear clipboard history', click(item, focusedWindow) {
      mainWindow.webContents.send('clearClipboardHistory');
    }},
    { type: 'separator' },
    { label: 'Quit Olden', click(item, focusedWindow) {
      app.quit();
    }}
  ]);

  tray.setToolTip('Olden')
  tray.setContextMenu(contextMenu)

  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.setVisibleOnAllWorkspaces(true);
  // TODO: execute the line below based on the input argument value.
  // mainWindow.webContents.openDevTools();

  ipcMain.on('hideWindow', (event) => {
    if (app.hide) {
        app.hide();
      } else {
        mainWindow.blur();
        mainWindow.hide()
      }
  });

  ipcMain.on('offer-update', (event, data) => {
    if (!updateOffered) {
      dialog.showMessageBox({
        type:      'question',
        buttons:   [ 'Cancel', 'Download' ],
        defaultId: 0,
        title:     'A newer version of Olden is available',
        message:   'Would you like to download the update?'
      }, (response) => {
        if (response === 1) {
          shell.openExternal(data.url);
        }

        updateOffered = true;
      });
    }
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On MacOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
<|endoftext|>


<commit_before>import SEGMENT_INFO from './segment-info.json'
import SEGMENT_LOOKUP from './segment-lookup.json'

/**
 * The placeholder object for unknown segments, to be used for rendering
 * in place of bad data, experimental data, missing data, etc.
 *
 * Placeholder objects have a property `unknown` set to `true` so that
 * receivers of this object can tell the difference between a placeholder
 * and normal segment / variant data.
 */
const SEGMENT_UNKNOWN = {
  unknown: true,
  name: 'Unknown',
  owner: 'NONE',
  zIndex: 1,
  variants: [],
  details: {}
}

const SEGMENT_UNKNOWN_VARIANT = {
  unknown: true,
  name: 'Unknown',
  graphics: {
    center: 'missing'
  }
}

const SEGMENT_COMPONENTS_UNKNOWN = {
  unknown: true,
  lanes: [],
  objects: [],
  vehicles: []
}

/**
 * Gets segment components data for segment `type` and `variantString`. Safer than reading
 * `type` and `variantString` directly from `SEGMENT_LOOKUP`, because this will return the
 * `SEGMENT_COMPONENTS_UNKNOWN` placeholder if the segment components data is not found.
 *
 * @param {string} type
 * @param {string} variantString
 * @returns {Object} - { lanesArray, objectsArray, vehiclesArray }
 */
function getSegmentComponents (type, variant) {
  return (SEGMENT_LOOKUP[type] && SEGMENT_LOOKUP[type][variant]) || SEGMENT_COMPONENTS_UNKNOWN
}

/**
 * Gets segment info for segment of `type` and `variantString`. Returns an object in shape of
 * { characteristics, variants, rules } which describes that particular segment or the
 * `SEGMENT_UNKNOWN` placeholder if segment is not found.
 *
 * @param {string} type
 * @param {string} id
 * @returns {Object} - { characteristics, rules, variants }
 */
function getSegmentInfo (type, id) {
  return (SEGMENT_INFO[type] && SEGMENT_INFO[type][id]) || SEGMENT_UNKNOWN
}

/**
 *
 * @param {string} type
 * @param {Array} componentPieces
 * @returns {Object} - { id: { characteristics, rules, variants } }
 */
function getComponentPiecesInfo (type, componentPieces) {
  const componentPiecesInfo = componentPieces.reduce((obj, item) => {
    const componentPieceInfo = getSegmentInfo(type, item.id)
    obj[item.id] = componentPieceInfo
    return obj
  }, {})

  return componentPiecesInfo
}

function appendVariantSprites (target, source) {
  let newGraphicsInfo

  if (Array.isArray(target) && Array.isArray(source)) {
    newGraphicsInfo = target.concat(source)
  } else if (Array.isArray(target)) {
    newGraphicsInfo = target.push(source)
  } else if (Array.isArray(source)) {
    newGraphicsInfo = [...target].concat(source)
  } else {
    newGraphicsInfo = [...target, ...source]
  }

  return newGraphicsInfo
}

function mergeVariantGraphics (graphics, variantInfo) {
  const graphicsInfo = { ...graphics }

  Object.keys(variantInfo).forEach((key) => {
    if (graphicsInfo[key]) {
      graphicsInfo[key] = appendVariantSprites(graphicsInfo[key], variantInfo[key])
    } else {
      graphicsInfo[key] = variantInfo[key]
    }
  })

  return graphicsInfo
}

/**
 *
 * @param {Array} componentPieces - [ { id, variants } ]
 * @param {Object} componentPiecesInfo - { id: { characteristics, rules, variants } }
 * @returns {Object} - { graphics: [ { graphicsForComponentPiece1 }, { graphicsForComponentPiece2 }, ... ], rules: {} }
 */
function getComponentPiecesVariantInfo (componentPieces, componentPiecesInfo) {
  let componentRules = {}

  const componentPiecesVariantInfo = componentPieces.map((componentPiece) => {
    const { id, variants } = componentPiece

    const componentPieceVariantInfo = Object.entries(variants).reduce((graphics, variant) => {
      const [ variantType, variantKey ] = variant

      const componentPieceRules = { ...componentPiecesInfo[id] && componentPiecesInfo[id].rules }
      componentRules = Object.assign(componentRules, componentPieceRules)

      const componentPieceVariants = componentPiecesInfo[id] && componentPiecesInfo[id].variants
      const variantInfo = (componentPieceVariants[variantType] && componentPieceVariants[variantType][variantKey]) || SEGMENT_UNKNOWN_VARIANT

      return mergeVariantGraphics(graphics, variantInfo.graphics)
    }, {})

    return componentPieceVariantInfo
  })

  return { graphics: componentPiecesVariantInfo, rules: componentRules }
}

function mergeComponentVariants (componentPiecesVariantInfo) {
  return componentPiecesVariantInfo.reduce((graphics, componentPieceVariantInfo) => {
    return mergeVariantGraphics(graphics, componentPieceVariantInfo)
  }, {})
}

function getSegmentVariantInfo (type, variant) {
  const segmentComponents = getSegmentComponents(type, variant)

  if (segmentComponents.unknown) {
    return SEGMENT_UNKNOWN_VARIANT
  }

  let segmentRules = {}

  const segmentVariantInfoArray = Object.entries(segmentComponents).map((segmentComponent) => {
    const [ type, componentPieces ] = segmentComponent

    if (componentPieces.length) {
      const componentPiecesInfo = getComponentPiecesInfo(type, componentPieces)
      const componentPiecesVariantInfo = getComponentPiecesVariantInfo(componentPieces, componentPiecesInfo)
      const componentVariantInfo = mergeComponentVariants(componentPiecesVariantInfo.graphics)

      segmentRules = Object.assign(segmentRules, componentPiecesVariantInfo.rules)
      return componentVariantInfo
    }
  })

  const segmentVariantInfo = segmentVariantInfoArray.reduce((graphics, variantInfo) => {
    return (variantInfo) ? mergeVariantGraphics(graphics, variantInfo) : graphics
  })

  return { graphics: segmentVariantInfo, ...segmentRules }
}

function verifyCorrectness (original, test) {
  const filteredKeys = Object.keys(original).filter((key) => !(test[key]))
  const filteredGraphics = Object.entries(original.graphics).filter((item) => {
    const [ key, value ] = item
    return !(JSON.stringify(value) === JSON.stringify(test.graphics[key]))
  })

  return !(filteredKeys.length && filteredGraphics.length)
}

export function testSegmentLookup (type, variant, segmentVariantInfo) {
  const testSegmentVariantInfo = getSegmentVariantInfo(type, variant)

  if (verifyCorrectness(segmentVariantInfo, testSegmentVariantInfo)) {
    console.log(variant, testSegmentVariantInfo)
    return testSegmentVariantInfo
  } else {
    return segmentVariantInfo
  }
}
<commit_msg>added some comments explaining each function<commit_after>import SEGMENT_INFO from './segment-info.json'
import SEGMENT_LOOKUP from './segment-lookup.json'

/**
 * The placeholder object for unknown segments, to be used for rendering
 * in place of bad data, experimental data, missing data, etc.
 *
 * Placeholder objects have a property `unknown` set to `true` so that
 * receivers of this object can tell the difference between a placeholder
 * and normal segment / variant data.
 */
const SEGMENT_UNKNOWN = {
  unknown: true,
  name: 'Unknown',
  owner: 'NONE',
  zIndex: 1,
  variants: [],
  details: {}
}

const SEGMENT_UNKNOWN_VARIANT = {
  unknown: true,
  name: 'Unknown',
  graphics: {
    center: 'missing'
  }
}

/**
 * Gets segment components data for segment `type` and `variantString` which includes
 * lanes, objects, and vehicles that make up the segment.
 *
 * @param {string} type
 * @param {string} variantString
 * @returns {object} - { lanesArray, objectsArray, vehiclesArray }
 */
function getSegmentComponents (type, variant) {
  return SEGMENT_LOOKUP[type] && SEGMENT_LOOKUP[type][variant]
}

/**
 * Gets segment info for segment of `type` and `variantString`. Returns an object in shape of
 * { characteristics, variants, rules } which describes that particular segment or the
 * `SEGMENT_UNKNOWN` placeholder if segment is not found.
 *
 * @param {string} type
 * @param {string} id
 * @returns {object} - { characteristics, rules, variants }
 */
function getSegmentInfo (type, id) {
  return (SEGMENT_INFO[type] && SEGMENT_INFO[type][id]) || SEGMENT_UNKNOWN
}

/**
 * Retrieves the segment pieces that make up the component (lane, object, or vehicle).
 *
 * @param {string} type
 * @param {Array} componentPieces
 * @returns {object} - { id: { characteristics, rules, variants } }
 */
function getComponentPiecesInfo (type, componentPieces) {
  const componentPiecesInfo = componentPieces.reduce((obj, item) => {
    const componentPieceInfo = getSegmentInfo(type, item.id)
    obj[item.id] = componentPieceInfo
    return obj
  }, {})

  return componentPiecesInfo
}

/**
 * Creates one object with all the graphic definitions to draw a segment.
 *
 * @param {object} graphics
 * @param {object} variantInfo
 * @returns {object}
 */
function mergeVariantGraphics (graphics, variantInfo) {
  const graphicsInfo = { ...graphics }

  Object.keys(variantInfo).forEach((key) => {
    const target = graphics[key]
    const source = variantInfo[key]

    if (graphicsInfo[key]) {
      graphicsInfo[key] = [...target, ...source]
    } else {
      graphicsInfo[key] = source
    }
  })

  return graphicsInfo
}

/**
 * Collects graphics definitions for each segment piece that makes up a component into an array.
 *
 * @param {Array} componentPieces - [ { id, variants } ]
 * @param {object} componentPiecesInfo - { id: { characteristics, rules, variants } }
 * @returns {object} - { graphics: [ { graphicsForComponentPiece1 }, { graphicsForComponentPiece2 }, ... ], rules: {} }
 */
function getComponentPiecesVariantInfo (componentPieces, componentPiecesInfo) {
  let componentRules = {}

  const componentPiecesVariantInfo = componentPieces.map((componentPiece) => {
    const { id, variants } = componentPiece

    const componentPieceVariantInfo = Object.entries(variants).reduce((graphics, variant) => {
      const [ variantType, variantKey ] = variant

      const componentPieceRules = { ...componentPiecesInfo[id] && componentPiecesInfo[id].rules }
      componentRules = Object.assign(componentRules, componentPieceRules)

      const componentPieceVariants = componentPiecesInfo[id] && componentPiecesInfo[id].variants
      const variantInfo = (componentPieceVariants[variantType] && componentPieceVariants[variantType][variantKey]) || SEGMENT_UNKNOWN_VARIANT

      return mergeVariantGraphics(graphics, variantInfo.graphics)
    }, {})

    return componentPieceVariantInfo
  })

  return { graphics: componentPiecesVariantInfo, rules: componentRules }
}

/**
 * Combines all graphics definitions from each segment piece that makes up a component into one graphics definition for the component.
 *
 * @param {Array} componentPiecesVariantInfo - [ { graphicsForComponentPiece1 }, { graphicsForComponentPiece2 }, ...]
 * @returns {object}
 */
function mergeComponentVariants (componentPiecesVariantInfo) {
  return componentPiecesVariantInfo.reduce((graphics, componentPieceVariantInfo) => {
    return mergeVariantGraphics(graphics, componentPieceVariantInfo)
  }, {})
}

function getSegmentVariantInfo (type, variant) {
  const segmentComponents = getSegmentComponents(type, variant)

  if (!segmentComponents) {
    return SEGMENT_UNKNOWN_VARIANT
  }

  let segmentRules = {}

  // 1) Go through each segment component (lanes, objects, vehicles).
  const segmentVariantInfoArray = Object.entries(segmentComponents).map((segmentComponent) => {
    const [ type, componentPieces ] = segmentComponent

    if (componentPieces.length) {
      // 2) For each segment component, retrieve information about each segment that makes up the component.
      const componentPiecesInfo = getComponentPiecesInfo(type, componentPieces)
      // 3) For each segment component, retrieve graphics information for each segment that makes up the component.
      const componentPiecesVariantInfo = getComponentPiecesVariantInfo(componentPieces, componentPiecesInfo)
      // 4) Combine graphics information from each segment that makes up the component into one object for the entire component.
      const componentVariantInfo = mergeComponentVariants(componentPiecesVariantInfo.graphics)

      segmentRules = Object.assign(segmentRules, componentPiecesVariantInfo.rules)
      return componentVariantInfo
    }
  })

  // 5) Combine graphics information from each segment component into one object for the whole segment.
  const segmentVariantInfo = segmentVariantInfoArray.reduce((graphics, variantInfo) => {
    return (variantInfo) ? mergeVariantGraphics(graphics, variantInfo) : graphics
  })

  // 6) Return graphics information for whole segment along with any rules that apply to the segment.
  return { graphics: segmentVariantInfo, ...segmentRules }
}

/**
 * Temporary helper method that compares the original segment variant info with the variant info returned
 * by the new data model. If the new variant info contains all the keys from the original variant info, then
 * the variant info is correct.
 *
 * @param {object} original
 * @param {object} test
 * @returns {boolean}
 */
function verifyCorrectness (original, test) {
  const filteredKeys = Object.keys(original).filter((key) => !(test[key]))
  const filteredGraphics = Object.entries(original.graphics).filter((item) => {
    const [ key, value ] = item
    return !(JSON.stringify(value) === JSON.stringify(test.graphics[key]))
  })

  return !(filteredKeys.length && filteredGraphics.length)
}

export function testSegmentLookup (type, variant, segmentVariantInfo) {
  const testSegmentVariantInfo = getSegmentVariantInfo(type, variant)

  if (verifyCorrectness(segmentVariantInfo, testSegmentVariantInfo)) {
    console.log(variant, testSegmentVariantInfo)
    return testSegmentVariantInfo
  } else {
    return segmentVariantInfo
  }
}
<|endoftext|>


<commit_before>'use strict'

const cols = 9
const rows = 27

let state = zeros(cols, rows)

state[4][0] = 1

let prevP = zeros(cols, rows) // I,J
let prevX = zeros(cols + 1, rows) // i,J
let prevY = zeros(cols, rows + 1) // I,j

prevX[4][4] = 0.00005

let oldP = zeros(cols, rows) // I,J
let newP

let tempX
let tempY

let nextP
let nextX
let nextY

const params = {
  size: 0.01, // 10mm face area
  rho: 998.2, // 998.2kg/m^3 density
  mu: 0.0 // viscosity
}

function zeros (cols, rows) {
  let grid = []
  for (let j = 0; j < cols; j++) {
    let line = []
    for (let i = 0; i < rows; i++) {
      line.push(0)
    }
    grid.push(line)
  }
  return grid
}

function couple (cArr, pArr, xArr, yArr) {
  let iArr = zeros(xArr.length, xArr[0].length)
  let jArr = zeros(yArr.length, yArr[0].length)

  // performs velocity calculation in x-axis
  for (let j = 1; j < iArr.length - 1; j++) {
    for (let i = 1; i < iArr[j].length - 1; i++) {
      const vx = {
        n: xArr[j - 1][i],
        s: xArr[j + 1][i],
        w: xArr[j][i - 1],
        e: xArr[j][i + 1]
      }

      const p = {
        n: pArr[j - 1][i],
        w: pArr[j][i - 1]
      }

      const ox = vx.n * 5 + vx.s + vx.w + vx.e + (p.w - pArr[j][i]) * params.size // + divergence

      iArr[j][i] = ox
    }
  }

  // performs velocity calculation in y-axis
  for (let j = 1; j < jArr.length - 1; j++) {
    for (let i = 1; i < jArr[j].length - 1; i++) {
      const vy = {
        n: yArr[j - 1][i],
        s: yArr[j + 1][i],
        w: yArr[j][i - 1],
        e: yArr[j][i + 1]
      }

      const p = {
        n: pArr[j - 1][i],
        w: pArr[j][i - 1]
      }

      const oy = vy.n + vy.s + vy.w + vy.e + (p.n - pArr[j][i]) * params.size // + divergence

      jArr[j][i] = oy
    }
  }

  for (let j = 0; j < cArr.length; j++) {
    let bool = {
      w: cArr[j][0] === 1,
      e: cArr[j][cArr[j].length - 1] === 1
    }

    jArr[j][0] += bool.w * 0.00005 // west wall

    jArr[j][cArr[j].length] -= bool.e * 0.00005 // east wall
  }

  for (let i = 0; i < cArr[0].length; i++) {
    let bool = {
      n: cArr[0][i] === 1,
      s: cArr[cArr.length - 1][i] === 1
    }

    iArr[0][i] += bool.n * 0.00005 // north wall

    iArr[cArr.length][i] -= bool.s * 0.00005 // south wall
  }

  return {
    x: iArr,
    y: jArr
  }
}

function jacobi (cArr, pArr, xArr, yArr) {
  let kArr = zeros(pArr.length, pArr[0].length)

  for (let j = 1; j < kArr.length - 1; j++) {
    for (let i = 1; i < kArr[j].length - 1; i++) {
      const vx = {
        w: xArr[j][i],
        e: xArr[j][i + 1]
      }

      const vy = {
        n: yArr[j][i],
        s: yArr[j + 1][i]
      }

      const p = {
        n: pArr[j - 1][i],
        s: pArr[j + 1][i],
        w: pArr[j][i - 1],
        e: pArr[j][i + 1]
      }

      kArr[j][i] = p.n + p.s + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
    }
  }

  // west side
  for (let j = 1; j < kArr.length - 1; j++) {
    const vx = {
      w: xArr[j][0],
      e: xArr[j][1]
    }

    const vy = {
      n: yArr[j][0],
      s: yArr[j + 1][0]
    }

    const p = {
      n: pArr[j - 1][0],
      s: pArr[j + 1][0],
      e: pArr[j][1]
    }

    kArr[j][0] = p.n + p.s + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  // east wall
  for (let j = 1; j < kArr.length - 1; j++) {
    const vx = {
      w: xArr[j][kArr[j].length - 1],
      e: xArr[j][kArr[j].length]
    }

    const vy = {
      n: yArr[j][kArr[j].length - 1],
      s: yArr[j + 1][kArr[j].length - 1]
    }

    const p = {
      n: pArr[j - 1][kArr[j].length - 1],
      s: pArr[j + 1][kArr[j].length - 1],
      w: pArr[j][kArr[j].length]
    }

    kArr[j][kArr.length - 1] = p.n + p.s + p.w + (vx.w - vx.e + vy.n - vy.s)
  }

  // north edge
  for (let i = 1; i < kArr[0].length - 1; i++) {
    const vx = {
      w: xArr[0][i],
      e: xArr[0][i + 1]
    }

    const vy = {
      n: yArr[0][i],
      s: yArr[1][i]
    }

    const p = {
      s: pArr[1][i],
      w: pArr[0][i - 1],
      e: pArr[0][i + 1]
    }

    kArr[0][i] = p.s + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  // south side
  for (let i = 1; i < kArr[0].length - 1; i++) {
    const vx = {
      w: xArr[kArr.length - 1][i],
      e: xArr[kArr.length - 1][i + 1]
    }

    const vy = {
      n: yArr[kArr.length - 1][i],
      s: yArr[kArr.length][i]
    }

    const p = {
      n: pArr[kArr.length - 2][i],
      w: pArr[kArr.length - 1][i - 1],
      e: pArr[kArr.length - 1][i + 1]
    }

    kArr[kArr.length - 1][i] = p.n + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  return kArr
}

function bounds (j, i, arr) {
  return j >= 0 && i >= 0 && j < arr.length && i < arr[j].length
}

function execute () {
  let temp = couple(state, prevP, prevX, prevY)

  console.log('New Estimated Velocity:', temp)

  tempX = temp.x
  tempY = temp.y

  newP = jacobi(state, oldP, prevX, prevY)

  console.log('New Estimated Pressure:', newP)
}

window.addEventListener('DOMContentLoaded', function () {
  setInterval(execute, 20)
}, false)
<commit_msg>modified: altered loop code; fixed indexing issues<commit_after>'use strict'

const cols = 27
const rows = 9

let state = zeros(cols, rows)

state[4][0] = 1

let prevP = zeros(cols, cols) //     (27C,  9R)
let prevX = zeros(cols + 1, rows) // (28C,  9R)
let prevY = zeros(cols, rows + 1) // (27C, 10R)

prevX[6][2] = 0.00005

let oldP = zeros(cols, rows)
let newP

let tempX
let tempY

let nextP
let nextX
let nextY

const params = {
  size: 0.01, // 10mm face area
  rho: 998.2, // 998.2kg/m^3 density
  mu: 0.0 // viscosity
}

function zeros (cols, rows) {
  let grid = []
  for (let j = 0; j < rows; j++) {
    let line = []
    for (let i = 0; i < cols; i++) {
      line.push(0)
    }
    grid.push(line)
  }
  return grid
}

function couple (cArr, pArr, xArr, yArr) {
  let iArr = zeros(cols + 1, rows)
  let jArr = zeros(cols, rows + 1)

  // performs velocity calculation in x-axis
  for (let j = 1; j < iArr.length - 1; j++) {
    for (let i = 1; i < iArr[j].length - 1; i++) {
      const vx = {
        n: xArr[j - 1][i],
        s: xArr[j + 1][i],
        w: xArr[j][i - 1],
        e: xArr[j][i + 1]
      }

      const p = {
        n: pArr[j - 1][i],
        w: pArr[j][i - 1]
      }

      const ox = vx.n + vx.s + vx.w + vx.e + (p.w - pArr[j][i]) * params.size // + divergence

      iArr[j][i] = ox
    }
  }

  // performs velocity calculation in y-axis
  for (let j = 1; j < jArr.length - 1; j++) {
    for (let i = 1; i < jArr[j].length - 1; i++) {
      const vy = {
        n: yArr[j - 1][i],
        s: yArr[j + 1][i],
        w: yArr[j][i - 1],
        e: yArr[j][i + 1]
      }

      const p = {
        n: pArr[j - 1][i],
        w: pArr[j][i - 1]
      }

      const oy = vy.n + vy.s + vy.w + vy.e + (p.n - pArr[j][i]) * params.size // + divergence

      jArr[j][i] = oy
    }
  }

  for (let j = 0; j < rows; j++) {
    let bool = {
      w: cArr[j][0] === 1,
      e: cArr[j][cols - 1] === 1
    }

    iArr[j][0] += bool.w * 0.00005 // west wall

    iArr[j][cols] -= bool.e * 0.00005 // east wall
  }

  for (let i = 0; i < cols; i++) {
    let bool = {
      n: cArr[0][i] === 1,
      s: cArr[rows - 1][i] === 1
    }

    jArr[0][i] += bool.n * 0.00005 // north wall

    jArr[rows][i] -= bool.s * 0.00005 // south wall
  }

  return {
    x: iArr,
    y: jArr
  }
}

function jacobi (cArr, pArr, xArr, yArr) {
  let kArr = zeros(cols, rows)

  for (let j = 1; j < kArr.length - 1; j++) {
    for (let i = 1; i < kArr[j].length - 1; i++) {
      const vx = {
        w: xArr[j][i],
        e: xArr[j][i + 1]
      }

      const vy = {
        n: yArr[j][i],
        s: yArr[j + 1][i]
      }

      const p = {
        n: pArr[j - 1][i],
        s: pArr[j + 1][i],
        w: pArr[j][i - 1],
        e: pArr[j][i + 1]
      }

      kArr[j][i] = p.n + p.s + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
    }
  }

  // west side
  for (let j = 1; j < rows - 1; j++) {
    const vx = {
      w: xArr[j][0],
      e: xArr[j][1]
    }

    const vy = {
      n: yArr[j][0],
      s: yArr[j + 1][0]
    }

    const p = {
      n: pArr[j - 1][0],
      s: pArr[j + 1][0],
      e: pArr[j][1]
    }

    kArr[j][0] = p.n + p.s + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  // east wall
  for (let j = 1; j < rows - 1; j++) {
    const vx = {
      w: xArr[j][kArr[j].length - 1],
      e: xArr[j][kArr[j].length]
    }

    const vy = {
      n: yArr[j][kArr[j].length - 1],
      s: yArr[j + 1][kArr[j].length - 1]
    }

    const p = {
      n: pArr[j - 1][kArr[j].length - 1],
      s: pArr[j + 1][kArr[j].length - 1],
      w: pArr[j][kArr[j].length - 2]
    }

    kArr[j][kArr[j].length - 1] = p.n + p.s + p.w + (vx.w - vx.e + vy.n - vy.s)
  }

  // north edge
  for (let i = 1; i < cols - 1; i++) {
    const vx = {
      w: xArr[0][i],
      e: xArr[0][i + 1]
    }

    const vy = {
      n: yArr[0][i],
      s: yArr[1][i]
    }

    const p = {
      s: pArr[1][i],
      w: pArr[0][i - 1],
      e: pArr[0][i + 1]
    }

    kArr[0][i] = p.s + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  // south side
  for (let i = 1; i < cols - 1; i++) {
    const vx = {
      w: xArr[kArr.length - 1][i],
      e: xArr[kArr.length - 1][i + 1]
    }

    const vy = {
      n: yArr[kArr.length - 1][i],
      s: yArr[kArr.length][i]
    }

    const p = {
      n: pArr[kArr.length - 2][i],
      w: pArr[kArr.length - 1][i - 1],
      e: pArr[kArr.length - 1][i + 1]
    }

    kArr[kArr.length - 1][i] = p.n + p.w + p.e + (vx.w - vx.e + vy.n - vy.s)
  }

  return kArr
}

function bounds (j, i, arr) {
  return j >= 0 && i >= 0 && j < arr.length && i < arr[j].length
}

function execute () {
  let temp = couple(state, prevP, prevX, prevY)

  console.log('New Estimated Velocity:', temp)

  tempX = temp.x
  tempY = temp.y

  newP = jacobi(state, oldP, prevX, prevY)

  console.log('New Estimated Pressure:', newP)
}

window.addEventListener('DOMContentLoaded', function () {
//  setInterval(execute, 20)
  execute()
}, false)
<|endoftext|>


<commit_before>'use strict';

/**
 * @file
 * Configure and start our server
 */

// loading config etc.
// import config from '../config.js';
import dbcConfig from '@dbcdk/dbc-config';
// newrelic needs to be required the es5 way because we only wants to load new relic if specified in config.js
const newrelic = dbcConfig.palle.newrelic && require('newrelic') || null;
import {version} from '../package.json';

// loading libraries
import express from 'express';
import http from 'http';
import socketio from 'socket.io';
import path from 'path';
import Logger from 'dbc-node-logger';
import ServiceProvider from 'dbc-node-serviceprovider';
import bodyParser from 'body-parser';
import expressValidator from 'express-validator';
import compression from 'compression';
import expressSession from 'express-session';
import RedisStore from 'connect-redis';
import helmet from 'helmet';

// loading routes
import MainRoutes from './server/routes/main.routes.js';
import LibraryRoutes from './server/routes/library.routes.js';
import PassportRoutes from './server/routes/passport.routes.js';
import WorkRoutes from './server/routes/work.routes.js';
import GroupRoutes from './server/routes/group.routes.js';

// loading configurations
import passportConfig from './passport.config.js';

const app = express();
const server = http.Server(app);
const socket = socketio.listen(server);
const ENV = app.get('env');
const PRODUCTION = ENV === 'production';
const APP_NAME = process.env.NEW_RELIC_APP_NAME || 'app_name'; // eslint-disable-line no-process-env
const logger = new Logger({app_name: APP_NAME});
const expressLoggers = logger.getExpressLoggers();

// Setting bodyparser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

// Helmet configuration
// app.use(helmet());
app.use(helmet.xssFilter());
app.use(helmet.frameguard());
app.use(helmet.hsts({
  maxAge: 112200,
  includeSubdomains: true
}));
app.use(helmet.hidePoweredBy({setTo: 'Funkys Venner!'}));
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());

// Port config
app.set('port', process.env.PORT || 8080); // eslint-disable-line no-process-env

// EMAIL Redirect requires port to be defined therefore it must come after
const EMAIL_REDIRECT = process.env.EMAIL_REDIRECT || 'localhost:' + app.get('port'); // eslint-disable-line no-process-env

// Configure app variables
app.set('serviceProvider', ServiceProvider(dbcConfig.palle.provider, logger).setupSockets(socket));
app.set('logger', logger);
app.set('EMAIL_REDIRECT', EMAIL_REDIRECT);

// Configure templating
app.set('views', path.join(__dirname, 'server/templates'));
app.set('view engine', 'jade');

// setting proxy
app.enable('trust proxy');

// disabling 'X-Powered-By:Express' in response header
// app.disable('x-powered-by');

// settings production specific options
if (!PRODUCTION && newrelic) {
  newrelic.agent_enabled = false;
}

// setting local vars that should be available to our template engine
app.locals.newrelic = newrelic;
app.locals.env = ENV;
app.locals.version = version;
app.locals.production = PRODUCTION;

// setup environments
let redisConfig;
let fileHeaders = {};

switch (ENV) {
  case 'development':
    redisConfig = dbcConfig.palle.services.redis.development;
    break;
  case 'production':
    fileHeaders = {index: false, dotfiles: 'ignore', maxAge: '1d'};
    redisConfig = dbcConfig.palle.services.redis.production;
    break;
  default:
    redisConfig = dbcConfig.palle.services.redis.local;
    break;
}

let redisStore = RedisStore(expressSession);

let sessionMiddleware = expressSession({
  store: new redisStore({
    host: redisConfig.host,
    port: redisConfig.port,
    prefix: APP_NAME + '_session_'
  }),
  secret: redisConfig.secret + APP_NAME,
  name: APP_NAME,
  rolling: true,
  resave: false,
  saveUninitialized: false,
  cookie: {
    path: '/',
    httpOnly: true,
    secure: PRODUCTION
  }
});

// adding gzip'ing
app.use(compression());

// setting paths
app.use(express.static(path.join(__dirname, '../public'), fileHeaders));
app.use(express.static(path.join(__dirname, '../static'), fileHeaders));

// Setting logger
app.use(expressLoggers.logger);
app.use(expressLoggers.errorLogger);

// Setting Input Validation
const validatorOptions = {};
app.use(expressValidator([validatorOptions]));

// Setting sessions
socket.use((_socket, next) => {
  sessionMiddleware(_socket.request, _socket.request.res, next);
});

app.use(sessionMiddleware);

// Setup passport
passportConfig(app);

// Setup Routes
app.use('/', MainRoutes);
app.use('/library', LibraryRoutes);
app.use('/profile', PassportRoutes);
app.use('/work', WorkRoutes);
app.use('/groups', GroupRoutes);

// starting server
server.listen(app.get('port'), () => {
  logger.log('debug', 'Server listening on port ' + app.get('port'));
  logger.log('debug', 'NEW_RELIC_APP_NAME: ' + APP_NAME);
  logger.log('debug', 'EMAIL_REDIRECT: ' + EMAIL_REDIRECT);
  logger.log('info', 'Versions: ', process.versions);
  logger.log('info', version + ' is up and running');
});
<commit_msg>us103: HELMET sd103 Reviewing<commit_after>'use strict';

/**
 * @file
 * Configure and start our server
 */

// loading config etc.
// import config from '../config.js';
import dbcConfig from '@dbcdk/dbc-config';
// newrelic needs to be required the es5 way because we only wants to load new relic if specified in config.js
const newrelic = dbcConfig.palle.newrelic && require('newrelic') || null;
import {version} from '../package.json';

// loading libraries
import express from 'express';
import http from 'http';
import socketio from 'socket.io';
import path from 'path';
import Logger from 'dbc-node-logger';
import ServiceProvider from 'dbc-node-serviceprovider';
import bodyParser from 'body-parser';
import expressValidator from 'express-validator';
import compression from 'compression';
import expressSession from 'express-session';
import RedisStore from 'connect-redis';
import helmet from 'helmet';

// loading routes
import MainRoutes from './server/routes/main.routes.js';
import LibraryRoutes from './server/routes/library.routes.js';
import PassportRoutes from './server/routes/passport.routes.js';
import WorkRoutes from './server/routes/work.routes.js';
import GroupRoutes from './server/routes/group.routes.js';

// loading configurations
import passportConfig from './passport.config.js';

const app = express();
const server = http.Server(app);
const socket = socketio.listen(server);
const ENV = app.get('env');
const PRODUCTION = ENV === 'production';
const APP_NAME = process.env.NEW_RELIC_APP_NAME || 'app_name'; // eslint-disable-line no-process-env
const logger = new Logger({app_name: APP_NAME});
const expressLoggers = logger.getExpressLoggers();

// Setting bodyparser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

// Helmet configuration
app.use(helmet.xssFilter());
app.use(helmet.frameguard());
app.use(helmet.hsts({
  maxAge: 112200,
  includeSubdomains: true
}));
app.use(helmet.hidePoweredBy({setTo: 'Funkys Venner!'}));
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());

// Port config
app.set('port', process.env.PORT || 8080); // eslint-disable-line no-process-env

// EMAIL Redirect requires port to be defined therefore it must come after
const EMAIL_REDIRECT = process.env.EMAIL_REDIRECT || 'localhost:' + app.get('port'); // eslint-disable-line no-process-env

// Configure app variables
app.set('serviceProvider', ServiceProvider(dbcConfig.palle.provider, logger).setupSockets(socket));
app.set('logger', logger);
app.set('EMAIL_REDIRECT', EMAIL_REDIRECT);

// Configure templating
app.set('views', path.join(__dirname, 'server/templates'));
app.set('view engine', 'jade');

// setting proxy
app.enable('trust proxy');

// disabling 'X-Powered-By:Express' in response header
// app.disable('x-powered-by');

// settings production specific options
if (!PRODUCTION && newrelic) {
  newrelic.agent_enabled = false;
}

// setting local vars that should be available to our template engine
app.locals.newrelic = newrelic;
app.locals.env = ENV;
app.locals.version = version;
app.locals.production = PRODUCTION;

// setup environments
let redisConfig;
let fileHeaders = {};

switch (ENV) {
  case 'development':
    redisConfig = dbcConfig.palle.services.redis.development;
    break;
  case 'production':
    fileHeaders = {index: false, dotfiles: 'ignore', maxAge: '1d'};
    redisConfig = dbcConfig.palle.services.redis.production;
    break;
  default:
    redisConfig = dbcConfig.palle.services.redis.local;
    break;
}

let redisStore = RedisStore(expressSession);

let sessionMiddleware = expressSession({
  store: new redisStore({
    host: redisConfig.host,
    port: redisConfig.port,
    prefix: APP_NAME + '_session_'
  }),
  secret: redisConfig.secret + APP_NAME,
  name: APP_NAME,
  rolling: true,
  resave: false,
  saveUninitialized: false,
  cookie: {
    path: '/',
    httpOnly: true,
    secure: PRODUCTION
  }
});

// adding gzip'ing
app.use(compression());

// setting paths
app.use(express.static(path.join(__dirname, '../public'), fileHeaders));
app.use(express.static(path.join(__dirname, '../static'), fileHeaders));

// Setting logger
app.use(expressLoggers.logger);
app.use(expressLoggers.errorLogger);

// Setting Input Validation
const validatorOptions = {};
app.use(expressValidator([validatorOptions]));

// Setting sessions
socket.use((_socket, next) => {
  sessionMiddleware(_socket.request, _socket.request.res, next);
});

app.use(sessionMiddleware);

// Setup passport
passportConfig(app);

// Setup Routes
app.use('/', MainRoutes);
app.use('/library', LibraryRoutes);
app.use('/profile', PassportRoutes);
app.use('/work', WorkRoutes);
app.use('/groups', GroupRoutes);

// starting server
server.listen(app.get('port'), () => {
  logger.log('debug', 'Server listening on port ' + app.get('port'));
  logger.log('debug', 'NEW_RELIC_APP_NAME: ' + APP_NAME);
  logger.log('debug', 'EMAIL_REDIRECT: ' + EMAIL_REDIRECT);
  logger.log('info', 'Versions: ', process.versions);
  logger.log('info', version + ' is up and running');
});
<|endoftext|>


<commit_before>const path = require('path')
const fs = require('fs')
const YAML = require('yamljs')
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const isWin = /^win/.test(process.platform)

if (!fs.existsSync(path.resolve(__dirname, '..', 'local'))) {
  fs.mkdirSync(path.resolve(__dirname, '..', 'local'))
}
// Kill screenwerk processes if any ...
fs.readdirSync(path.resolve(__dirname, '..', 'local')).forEach((filename) => {
  // console.log(filename.split('.'))
  if (filename.split('.')[2] !== 'pid') { return }
  let pid = filename.split('.')[1]
  // console.log('must terminate ' + pid)
  try {
    process.kill(pid, 'SIGTERM')
  } catch (e) {
    // console.log('Kill failed ' + path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
    fs.unlinkSync(path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
  }
  if(isWin) {
    try {
      fs.unlinkSync(path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
    } catch (e) {
      // console.log(e)
    }
  }
})
// ... and create my own
let pidFilePath = path.resolve(__dirname, '..', 'local', '.' + process.pid + '.pid')
fs.writeFileSync(pidFilePath, process.pid, 'utf8')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

let displayNum = 2
let devMode = false
let skipTaskbar = true
function createWindow () {

  let confFilePath = path.resolve(__dirname, '..', 'local', 'screen.yml')
  try {
    let data = fs.readFileSync(confFilePath, 'utf8')
    let conf = YAML.parse(data)
    displayNum = conf.DISPLAY_NUM || displayNum
    skipTaskbar = conf.SKIP_TASKBAR || skipTaskbar
    devMode = conf.DEV_MODE || devMode
    console.log('Configured as', JSON.stringify(conf, null, 4))
  }
  catch (e) {
    console.log('Cant read from configuration file from ' + confFilePath + '. Not a problem (yet).')
  }

  // Create the browser window.
  let electronScreen = electron.screen
  let displays = electronScreen.getAllDisplays()
  if (displays.length < displayNum) {
    displayNum = 1
  }
  // displayNum should be either 0 (main screen) or the number set in configuration minus one.
  displayNum --
  let display = displays[displayNum]

  mainWindow = new BrowserWindow({ x: display.bounds.x, y: display.bounds.y, width: 900, height: 600 })
  mainWindow.setMenu(null)
  if (devMode) {
    mainWindow.setFullScreen(true)
    mainWindow.webContents.openDevTools()
    process.env.DEBUG = '*'
  } else {
    mainWindow.setFullScreen(true)
    mainWindow.setKiosk(true)
  }
  if (skipTaskbar) {
    mainWindow.setSkipTaskbar(skipTaskbar)
  }
  if (isWin) {
    mainWindow.setIcon(path.resolve(__dirname, '..', 'public', 'icon.ico'))
  }
  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html')

  const debug = require('debug')('main')
  debug('Running in DEBUG=* mode')

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    let pidFilePath = path.resolve(__dirname, '..', 'local', '.' + process.pid + '.pid')
    console.log('Unlink ' + pidFilePath)
    try {
      fs.unlinkSync(pidFilePath)
    } catch (e) {
      // console.log(e)
    }
    mainWindow = null
    app.quit()
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})
<commit_msg>not fullscreen in dev mode<commit_after>const path = require('path')
const fs = require('fs')
const YAML = require('yamljs')
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const isWin = /^win/.test(process.platform)

if (!fs.existsSync(path.resolve(__dirname, '..', 'local'))) {
  fs.mkdirSync(path.resolve(__dirname, '..', 'local'))
}
// Kill screenwerk processes if any ...
fs.readdirSync(path.resolve(__dirname, '..', 'local')).forEach((filename) => {
  // console.log(filename.split('.'))
  if (filename.split('.')[2] !== 'pid') { return }
  let pid = filename.split('.')[1]
  // console.log('must terminate ' + pid)
  try {
    process.kill(pid, 'SIGTERM')
  } catch (e) {
    // console.log('Kill failed ' + path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
    fs.unlinkSync(path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
  }
  if(isWin) {
    try {
      fs.unlinkSync(path.resolve(__dirname, '..', 'local', '.' + pid + '.pid'))
    } catch (e) {
      // console.log(e)
    }
  }
})
// ... and create my own
let pidFilePath = path.resolve(__dirname, '..', 'local', '.' + process.pid + '.pid')
fs.writeFileSync(pidFilePath, process.pid, 'utf8')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

let displayNum = 2
let devMode = false
let skipTaskbar = true
function createWindow () {

  let confFilePath = path.resolve(__dirname, '..', 'local', 'screen.yml')
  try {
    let data = fs.readFileSync(confFilePath, 'utf8')
    let conf = YAML.parse(data)
    displayNum = conf.DISPLAY_NUM || displayNum
    skipTaskbar = conf.SKIP_TASKBAR || skipTaskbar
    devMode = conf.DEV_MODE || devMode
    console.log('Configured as', JSON.stringify(conf, null, 4))
  }
  catch (e) {
    console.log('Cant read from configuration file from ' + confFilePath + '. Not a problem (yet).')
  }

  // Create the browser window.
  let electronScreen = electron.screen
  let displays = electronScreen.getAllDisplays()
  if (displays.length < displayNum) {
    displayNum = 1
  }
  // displayNum should be either 0 (main screen) or the number set in configuration minus one.
  displayNum --
  let display = displays[displayNum]

  mainWindow = new BrowserWindow({ x: display.bounds.x, y: display.bounds.y, width: 900, height: 600 })
  mainWindow.setMenu(null)
  if (devMode) {
    mainWindow.setFullScreen(false)
    mainWindow.webContents.openDevTools()
    process.env.DEBUG = '*'
  } else {
    mainWindow.setFullScreen(true)
    mainWindow.setKiosk(true)
  }
  if (skipTaskbar) {
    mainWindow.setSkipTaskbar(skipTaskbar)
  }
  if (isWin) {
    mainWindow.setIcon(path.resolve(__dirname, '..', 'public', 'icon.ico'))
  }
  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html')

  const debug = require('debug')('main')
  debug('Running in DEBUG=* mode')

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    let pidFilePath = path.resolve(__dirname, '..', 'local', '.' + process.pid + '.pid')
    console.log('Unlink ' + pidFilePath)
    try {
      fs.unlinkSync(pidFilePath)
    } catch (e) {
      // console.log(e)
    }
    mainWindow = null
    app.quit()
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})
<|endoftext|>


<commit_before>'use strict';

var request = require('request');

function giphy(bot, controller, message) {
  var msg = '';
  var url = 'http://api.giphy.com/v1/gifs/search?q=';
  url += message.match[1] + '&api_key=dc6zaTOxFJmzC';
  request.get(url, function(err, res, body) {
    if (!err && res.statusCode === 200) {
      var response = JSON.parse(body);
      var gifs = response.data.length;
      var urls = response.data[0].images.fixedHeight.url;
      if (gifs > 0 && urls !== null) {
        bot.reply(message, urls);
      } else {
        msg = 'Huh... I couldn\'t find `' + message.match[1] + '` on Giphy.';
        bot.reply(message, msg);
      }
    } else {
      msg = 'Huh... I couldn\'t find `' + message.match[1] + '` on Giphy.';
      bot.reply(message, msg);
    }
  });
}

module.exports = {
  name: 'giphy me',
  author: 'Deiby Toralva (deibytb)',
  patterns: ['giphy me (.*)'],
  types: ['direct_message', 'direct_mention'],
  description: 'Search for a gif on Giphy',
  command: giphy,
};<commit_msg>Add missing line<commit_after>'use strict';

var request = require('request');

function giphy(bot, controller, message) {
  var msg = '';
  var url = 'http://api.giphy.com/v1/gifs/search?q=';
  url += message.match[1] + '&api_key=dc6zaTOxFJmzC';
  request.get(url, function(err, res, body) {
    if (!err && res.statusCode === 200) {
      var response = JSON.parse(body);
      var gifs = response.data.length;
      var urls = response.data[0].images.fixedHeight.url;
      if (gifs > 0 && urls !== null) {
        bot.reply(message, urls);
      } else {
        msg = 'Huh... I couldn\'t find `' + message.match[1] + '` on Giphy.';
        bot.reply(message, msg);
      }
    } else {
      msg = 'Huh... I couldn\'t find `' + message.match[1] + '` on Giphy.';
      bot.reply(message, msg);
    }
  });
}

module.exports = {
  name: 'giphy me',
  author: 'Deiby Toralva (deibytb)',
  patterns: ['giphy me (.*)'],
  types: ['direct_message', 'direct_mention'],
  description: 'Search for a gif on Giphy',
  command: giphy,
};
<|endoftext|>