<commit_before>import 'core-js/shim';

export default class SystemHotReloader {
  /**
   * Constructor.
   *
   * @param {Object} options
   * @prop  {Object} loader   SystemJS instance, default to SystemJS || System
   * @prop  {Number} logLevel 0 - none, 1 - error, 2 - info (default), 3 - debug
   */
  constructor(options) {
    const opts = options || {};

    this.loader = opts.loader || SystemJS || System;

    if (!this.loader) {
      throw new Error('Unable to instantiate SystemJS Hot Reloader without SystemJS');
    }

    if (this.loader.hotReloaderOptions) {
      Object.assign(opts, this.loader.hotReloaderOptions);
    }

    this.logLevel = opts.logLevel === undefined ? 2 : opts.logLevel;

    this.logger = this.createLogger('HMR');

    if (!this.loader.trace) {
      this.logger.info('Set "SystemJS.trace = true" to be able to auto unload not used modules');
    }
  }

  /**
   * Create logger.
   */
  createLogger(prefix) {
    return {
      debug: (message) => {
        if (this.logLevel >= 3 && console && console.debug) {
          console.debug(`[${prefix}] ${message}`);
        }
      },
      info: (message) => {
        if (this.logLevel >= 2 && console && console.info) {
          console.info(`[${prefix}] ${message}`);
        }
      },
      error: (message) => {
        if (this.logLevel >= 1 && console && console.warn) {
          console.warn(`[${prefix}] ${message}`);
        }
      },
    };
  }

  /**
   * Resolve module file path to module name.
   */
  resolvePath(path) {
    // try obvious resolve filename.ext => filename.ext
    const name1 = this.loader.normalizeSync(path);
    if (this.loader.get(name1)) {
      return name1;
    }

    // try less obvious resolve filename.ext => filename.ext!
    const name2 = this.loader.normalizeSync(`${path}!`);
    if (this.loader.get(name2)) {
      return name2;
    }

    // try to find by filename path in all registered modules, slow :-(
    const name3 = Object.keys(this.loader._loader.modules).find((name) => {
      return name.startsWith(`${name1}!`);
    });
    if (name3) {
      return name3;
    }

    return undefined;
  }

  /**
   * Reload module by file path.
   */
  reloadPath(path) {
    this.logger.debug(`Reloading file: ${path}`);

    const name = this.resolvePath(path);

    if (name) {
      return this.reloadModule(name);
    }

    // we did not find module :-(
    this.logger.info('Nothing to update');

    return Promise.resolve();
  }

  /**
   * Clean full module name from useless base url prefix and loader related suffix.
   */
  cleanName(name) {
    // remove base url prefix
    if (name.startsWith(this.loader.baseURL)) {
      name = `./${name.substr(this.loader.baseURL.length)}`;
    }

    // remove loader related garbage
    return name.replace(/!.*$/, '');
  }

  /**
   * Reload module by full module name.
   */
  reloadModule(moduleName) {
    const startTime = window.performance.now();

    this.logger.info(`Reloading module ${this.cleanName(moduleName)}`);

    if (!this.loader.get(moduleName)) {
      this.logger.info('Nothing to update');
      return Promise.resolve();
    }

    const moduleChain = this.getReloadChain([moduleName]);
    const moduleBackups = {};

    return Promise.resolve()
      .then(() => {
        this.logger.debug('Reload chain:');
        moduleChain.forEach((name) => {
          this.logger.debug(` - ${this.cleanName(name)}`);
        });
      })
      .then(() => {
        this.logger.debug('Saving backup');
        moduleChain.forEach((name) => {
          moduleBackups[name] = this.getModuleBackup(name);
        });
      })
      .then(() => {
        let promise = Promise.resolve();
        moduleChain.forEach((name) => {
          promise = promise.then(() => this.reloadModuleInstance(name, moduleChain));
        });
        return promise;
      })
      .then(() => {
        if (moduleChain.length) {
          this.logger.info('Updated modules:');
          moduleChain.forEach((name) => {
            const exports = this.loader.get(name);
            const options = [];
            if (exports && exports.__reload) {
              options.push('__reload()');
            } else if (exports && exports.__unload) {
              options.push('__unload()');
            }
            const suffix = options.length ? `{ ${options.join(', ')} }` : '';
            this.logger.info(` - ${this.cleanName(name)} ${suffix}`);
          });
        } else {
          this.logger.info('Nothing to update');
        }

        const time = (window.performance.now() - startTime) / 1000;
        const timeSecRound = Math.floor(time * 100) / 100;
        this.logger.info(`Reload took ${timeSecRound} sec`);
      })
      .catch((error) => {
        if (error) {
          const realError = error.originalErr || error;
          this.logger.error(realError.stack || realError);
        }

        this.logger.error('An error occured during reloading. Reverting...');

        let promise = Promise.resolve();

        moduleChain.forEach((name) => {
          promise = promise.then(() => {
            return this.reloadModuleInstance(name, moduleChain, moduleBackups[name]);
          });
        });

        promise = promise.then(() => {
          this.logger.info('Application state was restored');
        });

        return promise;
      })
      .catch((error) => {
        if (error) {
          this.logger.error(error.stack || error);
        }
        this.logger.error('An unrecoverable error occured during reverting');
      });
  }

  /**
   * Reload module instance with option to reload from backup.
   */
  reloadModuleInstance(name, moduleChain, backup) {
    const exports = backup ? backup.exports : this.loader.get(name);

    const unload = exports ? exports.__unload : undefined;
    const reload = exports ? exports.__reload : undefined;

    let oldDeps = [];

    if (reload) {
      return Promise.resolve()
        .then(() => this.fixModuleDeps(name))
        .then(() => {
          this.logger.debug(`Calling module ${this.cleanName(name)} __reload() hook`);
          return reload(moduleChain);
        });
    }

    return Promise.resolve()
      .then(() => {
        if (!unload) {
          return undefined;
        }
        this.logger.debug(`Calling module ${this.cleanName(name)} unload() hook`);
        return unload(moduleChain);
      })
      .then(() => {
        oldDeps = this.getModuleDepNames(name);
      })
      .then(() => (backup ? this.restoreModuleBackup(backup) : this.deleteModule(name)))
      .then(() => this.importModule(name))
      .then(() => {
        const newDeps = this.getModuleDepNames(name);
        this.deleteOldDeps(oldDeps, newDeps);
      });
  }

  /**
   * Delete modules from oldDeps if they do not exist in newDeps.
   */
  deleteOldDeps(oldDeps, newDeps) {
    const depDiff = oldDeps.filter(depName => newDeps.indexOf(depName) === -1);
    depDiff.forEach(depName => this.deleteModule(depName));
  }

  /**
   * Get normalized list of module dependency names based on trace information
   * or based on module records.
   */
  getModuleDepNames(name) {
    const load = this.loader.loads[name];

    if (load) {
      return load.deps.map((address) => {
        return load.depMap[address];
      });
    }

    const moduleRecord = this.loader._loader.moduleRecords[name];

    if (moduleRecord) {
      return moduleRecord.dependencies
        .map(record => (record ? record.name : false))
        .filter(depName => !!depName);
    }

    return [];
  }

  /**
   * Fix module dependencies before hooked reload.
   */
  fixModuleDeps(name) {
    const moduleRecords = this.loader._loader.moduleRecords;

    const moduleRecord = moduleRecords[name];

    moduleRecord.dependencies
      .forEach((depModuleRecord, index) => {
        if (!depModuleRecord) {
          return;
        }

        const newDepModuleRecord = moduleRecords[depModuleRecord.name];

        if (!newDepModuleRecord) {
          return;
        }

        if (newDepModuleRecord !== depModuleRecord) {
          this.logger.debug(`Fixing dependency ${this.cleanName(depModuleRecord.name)} for module ${this.cleanName(moduleRecord.name)}`);

          moduleRecord.setters[index](newDepModuleRecord.exports);

          if (moduleRecord.dependencies[index] !== newDepModuleRecord.exports) {
            moduleRecord.dependencies[index] = newDepModuleRecord;
          }

          const impRecord = newDepModuleRecord.importers
            .find(record => record && record.name === moduleRecord);
          if (!impRecord) {
            newDepModuleRecord.importers.push(moduleRecord);
          }
        }
      });
  }

  /**
   * Import module.
   */
  importModule(name) {
    this.logger.debug(`Importing module ${this.cleanName(name)}`);
    return this.loader.import(name);
  }

  /**
   * Delete module and fix importers for dependencies.
   */
  deleteModule(name) {
    const moduleRecord = this.loader._loader.moduleRecords[name];

    if (moduleRecord) {
      moduleRecord.dependencies
        .forEach((depModuleRecord) => {
          if (!depModuleRecord) {
            return;
          }
          depModuleRecord.importers
            .forEach((impModuleRecord, index) => {
              if (impModuleRecord && moduleRecord.name === impModuleRecord.name) {
                this.logger.debug(`Removing importer ${this.cleanName(impModuleRecord.name)} from module ${this.cleanName(depModuleRecord.name)}`);
                depModuleRecord.importers.splice(index, 1);
              }
            });
        });
    }

    this.logger.debug(`Removing module ${this.cleanName(name)}`);
    this.loader.delete(name);

    this.clearModuleResources(name);
  }

  /**
   * Clear module resources located in DOM.
   *
   * Usefull for CSS/LESS/SASS/SCSS/Stylus plugins who keep CSS as style or link tags.
   */
  clearModuleResources(name) {
    const address = this.getModuleAddress(name);

    // for example, plugin-sass
    Array.from(document.querySelectorAll(`[data-url="${address}"]`))
      .forEach(node => node.remove());

    // for example, plugin-css
    Array.from(document.querySelectorAll('[data-systemjs-css]'))
      .filter(node => node.href === address)
      .forEach((node) => {
        if (node.href.startsWith('blob:') && window.URL) {
          URL.revokeObjectURL(node.href);
        }
        node.remove();
      });
  }

  /**
   * Get module address by name.
   *
   * Try to use trace information if availabe, if not then try to guess it.
   * Address guessing should work well for plugins without custom translation hook.
   */
  getModuleAddress(name) {
    const load = this.loader.loads[name];
    return load ? load.address : name.replace(/!.*$/, '');
  }

  /**
   * Get module backup which could be used to restore module state.
   */
  getModuleBackup(name) {
    const exports = this.loader.get(name);
    const record = this.loader._loader.moduleRecords[name];
    return { name, record, exports };
  }

  /**
   * Restore module from backup.
   */
  restoreModuleBackup(data) {
    this.loader.set(data.name, data.exports);
    this.loader._loader.moduleRecords[data.name] = data.record;
  }

  /**
   * Get shortest distance to the root module (root modules have no importers).
   */
  getModuleDistanceToRoot(name, record, cache) {
    let distance;
    if (cache[name] !== undefined) {
      return cache[name];
    }
    if (!record || !record.importers.length) {
      distance = 0;
    } else {
      distance = record.importers.reduce((result, impRecord) => {
        const impDistance = 1 + this.getModuleDistanceToRoot(impRecord.name, impRecord, cache);
        return result === null ? impDistance : Math.min(result, impDistance);
      }, null);
    }
    cache[name] = distance;
    return distance;
  }

  /**
   * Reduce dependency tree and return modules in the order they should be reloaded.
   */
  getReloadChain(modules, cache) {
    if (modules.length === 0) {
      return modules;
    }

    const records = this.loader._loader.moduleRecords;

    if (!cache) {
      cache = {};
    }

    const farNode = modules.reduce((result, name, index) => {
      const record = records[name] ? records[name] : undefined;
      const distance = this.getModuleDistanceToRoot(name, record, cache);
      const importers = !record ? [] : record.importers.map(item => item.name);
      const reload = record && record.exports && record.exports.__reload;
      const meta = { distance, index, name, importers, reload };
      if (result === undefined) {
        return meta;
      }
      return result.distance >= distance ? result : meta;
    }, undefined);

    const nextModules = modules.slice(0);
    nextModules.splice(farNode.index, 1);
    if (!farNode.reload) {
      farNode.importers.forEach((name) => {
        if (nextModules.indexOf(name) === -1) {
          nextModules.push(name);
        }
      });
    }

    const nextResult = this.getReloadChain(nextModules, cache);

    const result = [farNode.name].concat(nextResult);

    return result;
  }
}
<commit_msg>universal css style/link blob href disposal<commit_after>import 'core-js/shim';

export default class SystemHotReloader {
  /**
   * Constructor.
   *
   * @param {Object} options
   * @prop  {Object} loader   SystemJS instance, default to SystemJS || System
   * @prop  {Number} logLevel 0 - none, 1 - error, 2 - info (default), 3 - debug
   */
  constructor(options) {
    const opts = options || {};

    this.loader = opts.loader || SystemJS || System;

    if (!this.loader) {
      throw new Error('Unable to instantiate SystemJS Hot Reloader without SystemJS');
    }

    if (this.loader.hotReloaderOptions) {
      Object.assign(opts, this.loader.hotReloaderOptions);
    }

    this.logLevel = opts.logLevel === undefined ? 2 : opts.logLevel;

    this.logger = this.createLogger('HMR');

    if (!this.loader.trace) {
      this.logger.info('Set "SystemJS.trace = true" to be able to auto unload not used modules');
    }
  }

  /**
   * Create logger.
   */
  createLogger(prefix) {
    return {
      debug: (message) => {
        if (this.logLevel >= 3 && console && console.debug) {
          console.debug(`[${prefix}] ${message}`);
        }
      },
      info: (message) => {
        if (this.logLevel >= 2 && console && console.info) {
          console.info(`[${prefix}] ${message}`);
        }
      },
      error: (message) => {
        if (this.logLevel >= 1 && console && console.warn) {
          console.warn(`[${prefix}] ${message}`);
        }
      },
    };
  }

  /**
   * Resolve module file path to module name.
   */
  resolvePath(path) {
    // try obvious resolve filename.ext => filename.ext
    const name1 = this.loader.normalizeSync(path);
    if (this.loader.get(name1)) {
      return name1;
    }

    // try less obvious resolve filename.ext => filename.ext!
    const name2 = this.loader.normalizeSync(`${path}!`);
    if (this.loader.get(name2)) {
      return name2;
    }

    // try to find by filename path in all registered modules, slow :-(
    const name3 = Object.keys(this.loader._loader.modules).find((name) => {
      return name.startsWith(`${name1}!`);
    });
    if (name3) {
      return name3;
    }

    return undefined;
  }

  /**
   * Reload module by file path.
   */
  reloadPath(path) {
    this.logger.debug(`Reloading file: ${path}`);

    const name = this.resolvePath(path);

    if (name) {
      return this.reloadModule(name);
    }

    // we did not find module :-(
    this.logger.info('Nothing to update');

    return Promise.resolve();
  }

  /**
   * Clean full module name from useless base url prefix and loader related suffix.
   */
  cleanName(name) {
    // remove base url prefix
    if (name.startsWith(this.loader.baseURL)) {
      name = `./${name.substr(this.loader.baseURL.length)}`;
    }

    // remove loader related garbage
    return name.replace(/!.*$/, '');
  }

  /**
   * Reload module by full module name.
   */
  reloadModule(moduleName) {
    const startTime = window.performance.now();

    this.logger.info(`Reloading module ${this.cleanName(moduleName)}`);

    if (!this.loader.get(moduleName)) {
      this.logger.info('Nothing to update');
      return Promise.resolve();
    }

    const moduleChain = this.getReloadChain([moduleName]);
    const moduleBackups = {};

    return Promise.resolve()
      .then(() => {
        this.logger.debug('Reload chain:');
        moduleChain.forEach((name) => {
          this.logger.debug(` - ${this.cleanName(name)}`);
        });
      })
      .then(() => {
        this.logger.debug('Saving backup');
        moduleChain.forEach((name) => {
          moduleBackups[name] = this.getModuleBackup(name);
        });
      })
      .then(() => {
        let promise = Promise.resolve();
        moduleChain.forEach((name) => {
          promise = promise.then(() => this.reloadModuleInstance(name, moduleChain));
        });
        return promise;
      })
      .then(() => {
        if (moduleChain.length) {
          this.logger.info('Updated modules:');
          moduleChain.forEach((name) => {
            const exports = this.loader.get(name);
            const options = [];
            if (exports && exports.__reload) {
              options.push('__reload()');
            } else if (exports && exports.__unload) {
              options.push('__unload()');
            }
            const suffix = options.length ? `{ ${options.join(', ')} }` : '';
            this.logger.info(` - ${this.cleanName(name)} ${suffix}`);
          });
        } else {
          this.logger.info('Nothing to update');
        }

        const time = (window.performance.now() - startTime) / 1000;
        const timeSecRound = Math.floor(time * 100) / 100;
        this.logger.info(`Reload took ${timeSecRound} sec`);
      })
      .catch((error) => {
        if (error) {
          const realError = error.originalErr || error;
          this.logger.error(realError.stack || realError);
        }

        this.logger.error('An error occured during reloading. Reverting...');

        let promise = Promise.resolve();

        moduleChain.forEach((name) => {
          promise = promise.then(() => {
            return this.reloadModuleInstance(name, moduleChain, moduleBackups[name]);
          });
        });

        promise = promise.then(() => {
          this.logger.info('Application state was restored');
        });

        return promise;
      })
      .catch((error) => {
        if (error) {
          this.logger.error(error.stack || error);
        }
        this.logger.error('An unrecoverable error occured during reverting');
      });
  }

  /**
   * Reload module instance with option to reload from backup.
   */
  reloadModuleInstance(name, moduleChain, backup) {
    const exports = backup ? backup.exports : this.loader.get(name);

    const unload = exports ? exports.__unload : undefined;
    const reload = exports ? exports.__reload : undefined;

    let oldDeps = [];

    if (reload) {
      return Promise.resolve()
        .then(() => this.fixModuleDeps(name))
        .then(() => {
          this.logger.debug(`Calling module ${this.cleanName(name)} __reload() hook`);
          return reload(moduleChain);
        });
    }

    return Promise.resolve()
      .then(() => {
        if (!unload) {
          return undefined;
        }
        this.logger.debug(`Calling module ${this.cleanName(name)} unload() hook`);
        return unload(moduleChain);
      })
      .then(() => {
        oldDeps = this.getModuleDepNames(name);
      })
      .then(() => (backup ? this.restoreModuleBackup(backup) : this.deleteModule(name)))
      .then(() => this.importModule(name))
      .then(() => {
        const newDeps = this.getModuleDepNames(name);
        this.deleteOldDeps(oldDeps, newDeps);
      });
  }

  /**
   * Delete modules from oldDeps if they do not exist in newDeps.
   */
  deleteOldDeps(oldDeps, newDeps) {
    const depDiff = oldDeps.filter(depName => newDeps.indexOf(depName) === -1);
    depDiff.forEach(depName => this.deleteModule(depName));
  }

  /**
   * Get normalized list of module dependency names based on trace information
   * or based on module records.
   */
  getModuleDepNames(name) {
    const load = this.loader.loads[name];

    if (load) {
      return load.deps.map((address) => {
        return load.depMap[address];
      });
    }

    const moduleRecord = this.loader._loader.moduleRecords[name];

    if (moduleRecord) {
      return moduleRecord.dependencies
        .map(record => (record ? record.name : false))
        .filter(depName => !!depName);
    }

    return [];
  }

  /**
   * Fix module dependencies before hooked reload.
   */
  fixModuleDeps(name) {
    const moduleRecords = this.loader._loader.moduleRecords;

    const moduleRecord = moduleRecords[name];

    moduleRecord.dependencies
      .forEach((depModuleRecord, index) => {
        if (!depModuleRecord) {
          return;
        }

        const newDepModuleRecord = moduleRecords[depModuleRecord.name];

        if (!newDepModuleRecord) {
          return;
        }

        if (newDepModuleRecord !== depModuleRecord) {
          this.logger.debug(`Fixing dependency ${this.cleanName(depModuleRecord.name)} for module ${this.cleanName(moduleRecord.name)}`);

          moduleRecord.setters[index](newDepModuleRecord.exports);

          if (moduleRecord.dependencies[index] !== newDepModuleRecord.exports) {
            moduleRecord.dependencies[index] = newDepModuleRecord;
          }

          const impRecord = newDepModuleRecord.importers
            .find(record => record && record.name === moduleRecord);
          if (!impRecord) {
            newDepModuleRecord.importers.push(moduleRecord);
          }
        }
      });
  }

  /**
   * Import module.
   */
  importModule(name) {
    this.logger.debug(`Importing module ${this.cleanName(name)}`);
    return this.loader.import(name);
  }

  /**
   * Delete module and fix importers for dependencies.
   */
  deleteModule(name) {
    const moduleRecord = this.loader._loader.moduleRecords[name];

    if (moduleRecord) {
      moduleRecord.dependencies
        .forEach((depModuleRecord) => {
          if (!depModuleRecord) {
            return;
          }
          depModuleRecord.importers
            .forEach((impModuleRecord, index) => {
              if (impModuleRecord && moduleRecord.name === impModuleRecord.name) {
                this.logger.debug(`Removing importer ${this.cleanName(impModuleRecord.name)} from module ${this.cleanName(depModuleRecord.name)}`);
                depModuleRecord.importers.splice(index, 1);
              }
            });
        });
    }

    this.logger.debug(`Removing module ${this.cleanName(name)}`);
    this.loader.delete(name);

    this.clearModuleResources(name);
  }

  /**
   * Clear module resources located in DOM.
   *
   * Usefull for CSS/LESS/SASS/SCSS/Stylus plugins who keep CSS as style or link tags.
   */
  clearModuleResources(name) {
    const address = this.getModuleAddress(name);

    const removeNode = (node) => {
      if (window.URL && node.href.startsWith('blob:')) {
        URL.revokeObjectURL(node.href);
      }
      node.remove();
    };

    // for example, plugin-sass
    Array.from(document.querySelectorAll(`[data-url="${address}"]`))
      .forEach(node => removeNode(node));

    // for example, plugin-css
    Array.from(document.querySelectorAll('[data-systemjs-css]'))
      .filter(node => node.href === address)
      .forEach(node => removeNode(node));
  }

  /**
   * Get module address by name.
   *
   * Try to use trace information if availabe, if not then try to guess it.
   * Address guessing should work well for plugins without custom translation hook.
   */
  getModuleAddress(name) {
    const load = this.loader.loads[name];
    return load ? load.address : name.replace(/!.*$/, '');
  }

  /**
   * Get module backup which could be used to restore module state.
   */
  getModuleBackup(name) {
    const exports = this.loader.get(name);
    const record = this.loader._loader.moduleRecords[name];
    return { name, record, exports };
  }

  /**
   * Restore module from backup.
   */
  restoreModuleBackup(data) {
    this.loader.set(data.name, data.exports);
    this.loader._loader.moduleRecords[data.name] = data.record;
  }

  /**
   * Get shortest distance to the root module (root modules have no importers).
   */
  getModuleDistanceToRoot(name, record, cache) {
    let distance;
    if (cache[name] !== undefined) {
      return cache[name];
    }
    if (!record || !record.importers.length) {
      distance = 0;
    } else {
      distance = record.importers.reduce((result, impRecord) => {
        const impDistance = 1 + this.getModuleDistanceToRoot(impRecord.name, impRecord, cache);
        return result === null ? impDistance : Math.min(result, impDistance);
      }, null);
    }
    cache[name] = distance;
    return distance;
  }

  /**
   * Reduce dependency tree and return modules in the order they should be reloaded.
   */
  getReloadChain(modules, cache) {
    if (modules.length === 0) {
      return modules;
    }

    const records = this.loader._loader.moduleRecords;

    if (!cache) {
      cache = {};
    }

    const farNode = modules.reduce((result, name, index) => {
      const record = records[name] ? records[name] : undefined;
      const distance = this.getModuleDistanceToRoot(name, record, cache);
      const importers = !record ? [] : record.importers.map(item => item.name);
      const reload = record && record.exports && record.exports.__reload;
      const meta = { distance, index, name, importers, reload };
      if (result === undefined) {
        return meta;
      }
      return result.distance >= distance ? result : meta;
    }, undefined);

    const nextModules = modules.slice(0);
    nextModules.splice(farNode.index, 1);
    if (!farNode.reload) {
      farNode.importers.forEach((name) => {
        if (nextModules.indexOf(name) === -1) {
          nextModules.push(name);
        }
      });
    }

    const nextResult = this.getReloadChain(nextModules, cache);

    const result = [farNode.name].concat(nextResult);

    return result;
  }
}
<|endoftext|>


<commit_before>// Karma configuration
// Generated on 2017-04-26

module.exports = function(config) {
  'use strict';

  config.set({
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // base path, that will be used to resolve files and exclude
    basePath: '../',

    // testing framework to use (jasmine/mocha/qunit/...)
    // as well as any additional frameworks (requirejs/chai/sinon/...)
    frameworks: [
      'jasmine'
    ],

    // list of files / patterns to load in the browser
    files: [
      // bower:js
      'bower_components/jquery/dist/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/bootstrap/dist/js/bootstrap.js',
      'bower_components/angular-animate/angular-animate.js',
      'bower_components/angular-aria/angular-aria.js',
      'bower_components/angular-cookies/angular-cookies.js',
      'bower_components/angular-messages/angular-messages.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/highcharts/highcharts.js',
      'bower_components/highcharts-ng/dist/highcharts-ng.js',
      'bower_components/moment/moment.js',
      'bower_components/bootstrap-daterangepicker/daterangepicker.js',
      'bower_components/ng-bs-daterangepicker/src/ng-bs-daterangepicker.js',
      'bower_components/angular-ui-select/dist/select.js',
      'bower_components/angular-mocks/angular-mocks.js',
      // endbower
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [
    ],

    // web server port
    port: 8080,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [
      'PhantomJS'
    ],

    // Which plugins to enable
    plugins: [
      'karma-phantomjs-launcher',
      'karma-jasmine'
    ],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false,

    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // Uncomment the following lines if you are using grunt's server to run the tests
    // proxies: {
    //   '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};
<commit_msg>update karma conf<commit_after>// Karma configuration
// Generated on 2017-04-26

module.exports = function(config) {
  'use strict';

  config.set({
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // base path, that will be used to resolve files and exclude
    basePath: '../',

    // testing framework to use (jasmine/mocha/qunit/...)
    // as well as any additional frameworks (requirejs/chai/sinon/...)
    frameworks: [
      'jasmine'
    ],

    // list of files / patterns to load in the browser
    files: [
      // bower:js
      'bower_components/jquery/dist/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/bootstrap/dist/js/bootstrap.js',
      'bower_components/angular-animate/angular-animate.js',
      'bower_components/angular-aria/angular-aria.js',
      'bower_components/angular-cookies/angular-cookies.js',
      'bower_components/angular-messages/angular-messages.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/highcharts/highstocks.js',
      'bower_components/moment/moment.js',
      'bower_components/bootstrap-daterangepicker/daterangepicker.js',
      'bower_components/ng-bs-daterangepicker/src/ng-bs-daterangepicker.js',
      'bower_components/angular-ui-select/dist/select.js',
      'bower_components/angular-mocks/angular-mocks.js',
      // endbower
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [
    ],

    // web server port
    port: 8080,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [
      'PhantomJS'
    ],

    // Which plugins to enable
    plugins: [
      'karma-phantomjs-launcher',
      'karma-jasmine'
    ],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false,

    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // Uncomment the following lines if you are using grunt's server to run the tests
    // proxies: {
    //   '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};
<|endoftext|>


<commit_before>// const webpackCommon = require('./build/webpack.common.js')
// const wpResolveAlias = webpackCommon.resolve.alias
// const webpackAliases = {
//   models: wpResolveAlias.models,
//   views: wpResolveAlias.views,
//   conf: wpResolveAlias.conf,
//   operations: wpResolveAlias.operations,
//   components: wpResolveAlias.components,
//   common: wpResolveAlias.common,
//   images: wpResolveAlias.images,
// }
// console.log('!!!', webpackAliases)
const moduleNameMapper = {
  '^models(.*)$': '<rootDir>/app/assets/javascripts/models$1',
  '^views(.*)$': '<rootDir>/app/assets/javascripts/views$1',
  '^conf(.*)$': '<rootDir>/app/assets/javascripts/configuration$1',
  '^operations(.*)$': '<rootDir>/app/assets/javascripts/operations$1',
  '^components(.*)$': '<rootDir>/app/assets/javascripts/components$1',
  '^common(.*)$': '<rootDir>/app/assets/javascripts/common$1',
  '^images(.*)$': '<rootDir>/app/assets/images$1',
  '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
    '<rootDir>/__mocks__/fileMock.js',
  '\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
}

module.exports = {
  verbose: true,
  modulePathIgnorePatterns: [
    '/app/assets/games/',
    '/app/assets/javascripts/views/pages/test.js',
    '/app/assets/javascripts/__tests__/test.js',
    '/cypress/',
    '/app/assets/javascripts/views/components/Legacy/',
    '/build/',
    '__tests__/__mocks__/',
  ],
  // Note: jsdom is a bit slower to run than `node`
  testEnvironment: 'jsdom',
  moduleNameMapper,
  collectCoverageFrom: ['<rootDir>/app/assets/javascripts/**/*.js'],
  coverageThreshold: {
    global: {
      statements: 0,
      branches: 0,
      functions: 0,
      lines: 0,
    },
  },
}
<commit_msg>Adding webpack alias to Jest config<commit_after>// const webpackCommon = require('./build/webpack.common.js')
// const wpResolveAlias = webpackCommon.resolve.alias
// const webpackAliases = {
//   models: wpResolveAlias.models,
//   views: wpResolveAlias.views,
//   conf: wpResolveAlias.conf,
//   operations: wpResolveAlias.operations,
//   components: wpResolveAlias.components,
//   common: wpResolveAlias.common,
//   images: wpResolveAlias.images,
// }
// console.log('!!!', webpackAliases)
const moduleNameMapper = {
  '^models(.*)$': '<rootDir>/app/assets/javascripts/models$1',
  '^views(.*)$': '<rootDir>/app/assets/javascripts/views$1',
  '^conf(.*)$': '<rootDir>/app/assets/javascripts/configuration$1',
  '^operations(.*)$': '<rootDir>/app/assets/javascripts/operations$1',
  '^providers(.*)$': '<rootDir>/app/assets/javascripts/providers$1',
  '^components(.*)$': '<rootDir>/app/assets/javascripts/components$1',
  '^common(.*)$': '<rootDir>/app/assets/javascripts/common$1',
  '^images(.*)$': '<rootDir>/app/assets/images$1',
  '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
    '<rootDir>/__mocks__/fileMock.js',
  '\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
}

module.exports = {
  verbose: true,
  modulePathIgnorePatterns: [
    '/app/assets/games/',
    '/app/assets/javascripts/views/pages/test.js',
    '/app/assets/javascripts/__tests__/test.js',
    '/cypress/',
    '/app/assets/javascripts/views/components/Legacy/',
    '/build/',
    '__tests__/__mocks__/',
  ],
  // Note: jsdom is a bit slower to run than `node`
  testEnvironment: 'jsdom',
  moduleNameMapper,
  collectCoverageFrom: ['<rootDir>/app/assets/javascripts/**/*.js'],
  coverageThreshold: {
    global: {
      statements: 0,
      branches: 0,
      functions: 0,
      lines: 0,
    },
  },
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text, Image, FlatList, StyleSheet, TouchableHighlight, View } from 'react-native';

import branch from 'react-native-branch';

import Article from './Article';

export default class ArticleList extends Component {
  _unsubscribeFromBranch = null;

  constructor(props) {
    super(props);

    this.state = {
      listData: props.listData || [
        { title: 'Mercury', url: 'https://en.wikipedia.org/wiki/Mercury_(planet)', image: 'https://upload.wikimedia.org/wikipedia/commons/d/d9/Mercury_in_color_-_Prockter07-edit1.jpg' },
        { title: 'Venus', url: 'https://en.wikipedia.org/wiki/Venus', image: 'https://upload.wikimedia.org/wikipedia/commons/e/e5/Venus-real_color.jpg' },
        { title: 'Earth', url: 'https://en.wikipedia.org/wiki/Earth', image: 'https://upload.wikimedia.org/wikipedia/commons/9/97/The_Earth_seen_from_Apollo_17.jpg' },
        { title: 'Mars', url: 'https://en.wikipedia.org/wiki/Mars', image: 'https://upload.wikimedia.org/wikipedia/commons/0/02/OSIRIS_Mars_true_color.jpg' },
        { title: 'Jupiter', url: 'https://en.wikipedia.org/wiki/Jupiter', image: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/Jupiter_and_its_shrunken_Great_Red_Spot.jpg' },
        { title: 'Saturn', url: 'https://en.wikipedia.org/wiki/Saturn', image: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Saturn-27-03-04.jpeg' },
        { title: 'Uranus', url: 'https://en.wikipedia.org/wiki/Uranus', image: 'https://upload.wikimedia.org/wikipedia/commons/3/3d/Uranus2.jpg' },
        { title: 'Neptune', url: 'https://en.wikipedia.org/wiki/Neptune', image: 'https://upload.wikimedia.org/wikipedia/commons/5/56/Neptune_Full.jpg' },
        { title: 'Pluto', url: 'https://en.wikipedia.org/wiki/Pluto', image: 'https://upload.wikimedia.org/wikipedia/commons/2/2a/Nh-pluto-in-true-color_2x_JPEG-edit-frame.jpg' },
      ],
    };
  }

  componentDidMount() {
    this._unsubscribeFromBranch = branch.subscribe(({ error, params, uri }) => {
      if (error) {
        console.error(`Error from Branch opening URI ${uri}: ${error}`);
        return;
      }

      console.log(`Branch params: ${JSON.stringify(params)}`);

      if (!params['+clicked_branch_link']) return;

      // Get title and url for route
      let title = params.$og_title;
      let url = params.$canonical_url;
      let image = params.$og_image_url;

      // Now push the view for this URL
      this.props.navigation.navigate('Article', { url: url, title: title, image: image });
    })
  }

  componentWillUnmount() {
    if (this._unsubscribeFromBranch) {
      this._unsubscribeFromBranch();
      this._unsubscribeFromBranch = null;
    }
  }

  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.listData}
          keyExtractor={(item, index) => index.toString()}
          renderItem={({item}) =>
            <TouchableHighlight
              onPress={() => { this._showArticle(item) }}>
              <View style={styles.item}>
                <Image
                  style={styles.image}
                  source={{uri: item.image}}/>
                <Text
                  style={styles.label}>
                  {item.title}
                </Text>
              </View>
            </TouchableHighlight>}
        />
      </View>
    );
  }

  _showArticle(data) {
    console.log("Show article with URL " + data.url);
    this.props.navigation.navigate('Article', data);
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    marginTop: 0,
  },
  item: {
    height: 88,
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
  },
  image: {
    width: 80,
    height: 80,
    marginLeft: 8
  },
  label: {
    fontWeight: 'bold',
    fontSize: 17,
    margin: 20,
  },
});
<commit_msg>Add onOpenStart to webview_example.<commit_after>import React, { Component } from 'react';
import { Text, Image, FlatList, StyleSheet, TouchableHighlight, View } from 'react-native';

import branch from 'react-native-branch';

import Article from './Article';

export default class ArticleList extends Component {
  _unsubscribeFromBranch = null;

  constructor(props) {
    super(props);

    this.state = {
      listData: props.listData || [
        { title: 'Mercury', url: 'https://en.wikipedia.org/wiki/Mercury_(planet)', image: 'https://upload.wikimedia.org/wikipedia/commons/d/d9/Mercury_in_color_-_Prockter07-edit1.jpg' },
        { title: 'Venus', url: 'https://en.wikipedia.org/wiki/Venus', image: 'https://upload.wikimedia.org/wikipedia/commons/e/e5/Venus-real_color.jpg' },
        { title: 'Earth', url: 'https://en.wikipedia.org/wiki/Earth', image: 'https://upload.wikimedia.org/wikipedia/commons/9/97/The_Earth_seen_from_Apollo_17.jpg' },
        { title: 'Mars', url: 'https://en.wikipedia.org/wiki/Mars', image: 'https://upload.wikimedia.org/wikipedia/commons/0/02/OSIRIS_Mars_true_color.jpg' },
        { title: 'Jupiter', url: 'https://en.wikipedia.org/wiki/Jupiter', image: 'https://upload.wikimedia.org/wikipedia/commons/2/2b/Jupiter_and_its_shrunken_Great_Red_Spot.jpg' },
        { title: 'Saturn', url: 'https://en.wikipedia.org/wiki/Saturn', image: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Saturn-27-03-04.jpeg' },
        { title: 'Uranus', url: 'https://en.wikipedia.org/wiki/Uranus', image: 'https://upload.wikimedia.org/wikipedia/commons/3/3d/Uranus2.jpg' },
        { title: 'Neptune', url: 'https://en.wikipedia.org/wiki/Neptune', image: 'https://upload.wikimedia.org/wikipedia/commons/5/56/Neptune_Full.jpg' },
        { title: 'Pluto', url: 'https://en.wikipedia.org/wiki/Pluto', image: 'https://upload.wikimedia.org/wikipedia/commons/2/2a/Nh-pluto-in-true-color_2x_JPEG-edit-frame.jpg' },
      ],
    };
  }

  componentDidMount() {
    this._unsubscribeFromBranch = branch.subscribe({
      onOpenStart: ({ uri }) => {
        console.log(`Opening URI ${uri}`);
      },
      onOpenComplete: ({ error, params, uri }) => {
        if (error) {
          console.error(`Error from Branch opening URI ${uri}: ${error}`);
          return;
        }

        console.log(`Branch params: ${JSON.stringify(params)}`);

        if (!params['+clicked_branch_link']) return;

        // Get title and url for route
        let title = params.$og_title;
        let url = params.$canonical_url;
        let image = params.$og_image_url;

        // Now push the view for this URL
        this.props.navigation.navigate('Article', { url: url, title: title, image: image });
      },
    });
  }

  componentWillUnmount() {
    if (this._unsubscribeFromBranch) {
      this._unsubscribeFromBranch();
      this._unsubscribeFromBranch = null;
    }
  }

  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.listData}
          keyExtractor={(item, index) => index.toString()}
          renderItem={({item}) =>
            <TouchableHighlight
              onPress={() => { this._showArticle(item) }}>
              <View style={styles.item}>
                <Image
                  style={styles.image}
                  source={{uri: item.image}}/>
                <Text
                  style={styles.label}>
                  {item.title}
                </Text>
              </View>
            </TouchableHighlight>}
        />
      </View>
    );
  }

  _showArticle(data) {
    console.log("Show article with URL " + data.url);
    this.props.navigation.navigate('Article', data);
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    marginTop: 0,
  },
  item: {
    height: 88,
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
  },
  image: {
    width: 80,
    height: 80,
    marginLeft: 8
  },
  label: {
    fontWeight: 'bold',
    fontSize: 17,
    margin: 20,
  },
});
<|endoftext|>


<commit_before>(function(window) {
    var Matrix = function(array) {
        if (!(array instanceof Array) ||
            array.length === 0 ||
            !(array[0] instanceof Array) ||
            array[0].length === 0) {
            throw new Error('invalid argument');
        }

        this.col = array.length;
        this.row = array[0].length;
        this.val = [];

        var i, j;
        for (i = 0; i < this.col; i++) {
            if (this.row !== array[i].length) {
                throw new Error('invalid argument');
            }
            this.val[i] = [];
            for (j = 0; j < this.row; j++) {
                this.val[i][j] = array[i][j];
            }
        }
    };

    Matrix.prototype = {

        getRowSize: function() {
            return this.row;
        },

        getColSize: function() {
            return this.col;
        },

        getVal: function(col, row) {
            if (typeof col === 'undefined' ||
                typeof row === 'undefined' ||
                col < 0 ||
                row < 0 ||
                col > this.col ||
                row > this.row) {
                throw new Error('invalid argument');
            }
            return this.val[col][row];
        },

        add: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                throw new Error('invalid argument');
            }
            if (matrix.col !== this.col ||
                matrix.row !== this.row) {
                throw new Error('input matrix size is wrong');
            }

            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = matrix.val[i][j] + this.val[i][j];
                }
            }

            return new Matrix(newVal);
        },

        sub: function(matrix) {
            return this.add(matrix.scalar(-1));
        },

        scalar: function(n) {
            if (typeof n !== 'number') {
                throw new Error('invalid argument');
            }

            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = n * this.val[i][j];
                }
            }

            return new Matrix(newVal);
        },

        mul: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                throw new Error('invalid argument');
            }
            if (matrix.col !== this.row) {
                throw new Error('input matrix size is wrong');
            }

            var newVal = [],
                i, j, k;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < matrix.row; j++) {
                    var temp = 0;
                    for (k = 0; k < this.row; k++) {
                        temp += this.val[i][k] * matrix.val[k][j];
                    }
                    newVal[i][j] = temp;
                }
            }

            return new Matrix(newVal);
        },

        clone: function() {
            return this.scalar(1);
        },

        compare: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                return false;
            }
            var i, j;

            if (this.col !== matrix.col ||
                this.row !== matrix.row) {
                return false;
            }

            for (i = 0; i < this.col; i++) {
                for (j = 0; j < this.row; j++) {
                    if (this.val[i][j] !== matrix.val[i][j]) {
                        return false;
                    }
                }
            }

            return true;
        },

        det: function() {
            if (this.col !== this.row) {
                // determinant exists only square matrix
                return undefined;
            }

            var det = 1,
                clone = this.clone(),
                n = clone.col,
                i, j, k;

            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++) {
                    if (i < j) {
                        var temp = clone.val[j][i] / clone.val[i][i];
                        for(k = 0; k < n; k++){
                            clone.val[j][k] -= clone.val[i][k] * temp;
                        }
                    }
                }
                det *= clone.val[i][i];
            }

            return det;
        },

        inv: function() {
            var det = this.det();
            if (det === undefined ||
                det === 0) {
                return undefined;
            }

            var clone = this.clone(),
                n = clone.col,
                i, j, k;

            // make identity matrix value
            var newVal = [];
            for (i = 0; i < n; i++) {
                newVal[i] = [];
                for (j = 0; j < n; j++) {
                    if (i === j) {
                        newVal[i][j] = 1;
                    } else {
                        newVal[i][j] = 0;
                    }
                }
            }

            // Gauss-Jordan method
            for (i = 0; i < n; i++) {
                var temp = 1 / clone.val[i][i];
                for (j = 0; j < n; j++) {
                    clone.val[i][j] *= temp;
                    newVal[i][j] *= temp;
                }
                for (j = 0; j < n; j++) {
                    if (i !==j) {
                        temp = clone.val[j][i];
                        for (k = 0; k < n; k++) {
                            clone.val[j][k] -= clone.val[i][k] * temp;
                            newVal[j][k] -= newVal[i][k] * temp;
                        }
                    }
                }
            }

            return new Matrix(newVal);
        },

        trans: function() {
            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = this.val[j][i];
                }
            }

            return new Matrix(newVal);
        }
    };

    if (typeof exports !== 'undefined') {
        exports.Matrix = Matrix;
    } else {
        window.Matrix = Matrix;
    }
})(window);<commit_msg>insert some comments<commit_after>/**
 * Simple Matrix v0.1.0
 *
 * Copyright (c) 2013 westzaki
 * Released under MIT license
 */
(function(window) {
    /**
     * constructor
     */
    var Matrix = function(array) {
        if (!(array instanceof Array) ||
            array.length === 0 ||
            !(array[0] instanceof Array) ||
            array[0].length === 0) {
            throw new Error('invalid argument');
        }

        this.col = array.length;
        this.row = array[0].length;
        this.val = [];

        var i, j;
        for (i = 0; i < this.col; i++) {
            if (this.row !== array[i].length) {
                throw new Error('invalid argument');
            }
            this.val[i] = [];
            for (j = 0; j < this.row; j++) {
                this.val[i][j] = array[i][j];
            }
        }
    };

    Matrix.prototype = {

        /**
         * Get the number of rows
         */
        getRowSize: function() {
            return this.row;
        },

        /**
         * Get the number of columns
         */
        getColSize: function() {
            return this.col;
        },

        /**
         * Get element of this matrix
         */
        getVal: function(col, row) {
            if (typeof col === 'undefined' ||
                typeof row === 'undefined' ||
                col < 0 ||
                row < 0 ||
                col > this.col ||
                row > this.row) {
                throw new Error('invalid argument');
            }
            return this.val[col][row];
        },

        /**
         * Add a matrix to this matrix
         */
        add: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                throw new Error('invalid argument');
            }
            if (matrix.col !== this.col ||
                matrix.row !== this.row) {
                throw new Error('input matrix size is wrong');
            }

            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = matrix.val[i][j] + this.val[i][j];
                }
            }

            return new Matrix(newVal);
        },

        /**
         * Subtruct a matrix from this matrix
         */
        sub: function(matrix) {
            return this.add(matrix.scalar(-1));
        },

        /**
         * Scalar multiple
         */
        scalar: function(n) {
            if (typeof n !== 'number') {
                throw new Error('invalid argument');
            }

            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = n * this.val[i][j];
                }
            }

            return new Matrix(newVal);
        },

        /**
         * Multiple 2 matrix
         */
        mul: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                throw new Error('invalid argument');
            }
            if (matrix.col !== this.row) {
                throw new Error('input matrix size is wrong');
            }

            var newVal = [],
                i, j, k;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < matrix.row; j++) {
                    var temp = 0;
                    for (k = 0; k < this.row; k++) {
                        temp += this.val[i][k] * matrix.val[k][j];
                    }
                    newVal[i][j] = temp;
                }
            }

            return new Matrix(newVal);
        },

        /**
         * Return a copy of this matrix
         */
        clone: function() {
            return this.scalar(1);
        },

        /**
         * Compare the values of the 2 matrix
         */
        compare: function(matrix) {
            if (!(matrix instanceof Matrix)) {
                return false;
            }
            var i, j;

            if (this.col !== matrix.col ||
                this.row !== matrix.row) {
                return false;
            }

            for (i = 0; i < this.col; i++) {
                for (j = 0; j < this.row; j++) {
                    if (this.val[i][j] !== matrix.val[i][j]) {
                        return false;
                    }
                }
            }

            return true;
        },

        /**
         * Return the determinant of this matrix
         */
        det: function() {
            if (this.col !== this.row) {
                // determinant exists only square matrix
                return undefined;
            }

            var det = 1,
                clone = this.clone(),
                n = clone.col,
                i, j, k;

            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++) {
                    if (i < j) {
                        var temp = clone.val[j][i] / clone.val[i][i];
                        for(k = 0; k < n; k++){
                            clone.val[j][k] -= clone.val[i][k] * temp;
                        }
                    }
                }
                det *= clone.val[i][i];
            }

            return det;
        },

        /**
         * Return a new matrix that is the inverse of this matrix
         */
        inv: function() {
            var det = this.det();
            if (det === undefined ||
                det === 0) {
                return undefined;
            }

            var clone = this.clone(),
                n = clone.col,
                i, j, k;

            // make identity matrix value
            var newVal = [];
            for (i = 0; i < n; i++) {
                newVal[i] = [];
                for (j = 0; j < n; j++) {
                    if (i === j) {
                        newVal[i][j] = 1;
                    } else {
                        newVal[i][j] = 0;
                    }
                }
            }

            // Gauss-Jordan method
            for (i = 0; i < n; i++) {
                var temp = 1 / clone.val[i][i];
                for (j = 0; j < n; j++) {
                    clone.val[i][j] *= temp;
                    newVal[i][j] *= temp;
                }
                for (j = 0; j < n; j++) {
                    if (i !==j) {
                        temp = clone.val[j][i];
                        for (k = 0; k < n; k++) {
                            clone.val[j][k] -= clone.val[i][k] * temp;
                            newVal[j][k] -= newVal[i][k] * temp;
                        }
                    }
                }
            }

            return new Matrix(newVal);
        },

        /**
         * Return a new matrix that is the transpose of this matrix
         */
        trans: function() {
            var newVal = [],
                i, j;
            for (i = 0; i < this.col; i++) {
                newVal[i] = [];
                for (j = 0; j < this.row; j++) {
                    newVal[i][j] = this.val[j][i];
                }
            }

            return new Matrix(newVal);
        }
    };

    if (typeof exports !== 'undefined') {
        exports.Matrix = Matrix;
    } else {
        window.Matrix = Matrix;
    }
})(window);<|endoftext|>


<commit_before>// ==UserScript==
// @name         Banner Carousel
// @namespace    http://terrasoft.gr/userscripts/
// @version      0.2.2
// @description  Banner Carousel
// @author       George Schizas
// @match        https://www.reddit.com/r/greece/comments/2zg5ou/*
// @downloadUrl  https://openuserjs.org/install/gschizas/Banner_Carousel.user.js
// @grant        unsafeWindow
// ==/UserScript==

var bannerImages = [
    'https://i.imgur.com/ptC8pyl.jpg',
    'https://i.imgur.com/Ece3hYj.jpg',
    'https://i.imgur.com/T22nJc6.png',
    'https://i.imgur.com/EzEYiEC.png',
    'https://i.imgur.com/RVV7fVL.png',
    'https://i.imgur.com/oM4QXGP.png',
    'https://dl.dropboxusercontent.com/u/6166376/banner.png',
    'https://i.imgur.com/z6oul4p.jpg',
    'https://i.imgur.com/JzMaSvM.jpg',
    'https://i.imgur.com/DpLvIm8.jpg',
    'https://i.imgur.com/GwVgxvD.jpg',
    'https://i.imgur.com/oV3xsfC.jpg',
    'https://i.imgur.com/V2kYfgv.jpg',
    'https://i.imgur.com/7gRJxLy.png',
    'https://i.imgur.com/eFlc02U.jpg'
];

var $ = unsafeWindow.jQuery;

var bannerControl = $("<select id='bannerSelect'><option value='0'>--Default Banner--</option></select><button id='bannerPrev'>« Prev</button><button id='bannerNext'>Next »</button>");

$('#siteTable').prepend(bannerControl);

console.log(bannerControl);

bannerImages.forEach(function (el, i) {
    // console.log(el, i);
    $('#bannerSelect').append("<option value='" + (i+1) + "'>" + el + "</option>");
});

// console.log(combo);
// console.log($('.commentarea'));

$('#bannerSelect').change(function() {
    selectedImage = parseInt($(this).val());
    if (selectedImage==0) {
        imageUrl = '//c.thumbs.redditmedia.com/-oIzLQ0UPDfe1Swn.png'
    } else {
        imageUrl = bannerImages[selectedImage-1];
    }
    $('#header').css('background-image', 'url(' + imageUrl + ')')
})

$('#bannerPrev').click(function() {
    console.log("« Prev");
    var currentBanner = $('#bannerSelect').val();
    currentBanner--;
    if (currentBanner < 0) currentBanner = bannerImages.length;
    $('#bannerSelect').val(currentBanner);
    $('#bannerSelect').change();
})
$('#bannerNext').click(function() {
    console.log("Next »");
    var currentBanner = $('#bannerSelect').val();
    currentBanner++;
    if (currentBanner>bannerImages.length) currentBanner = 0;
    $('#bannerSelect').val(currentBanner);
    $('#bannerSelect').change();
})
<commit_msg>Now reads image from top level comments<commit_after>// ==UserScript==
// @name         Banner Carousel
// @namespace    http://terrasoft.gr/userscripts/
// @version      0.3.0
// @description  Banner Carousel
// @author       George Schizas
// @match        https://www.reddit.com/r/greece/comments/2zg5ou/*
// @downloadUrl  https://openuserjs.org/install/gschizas/Banner_Carousel.user.js
// @grant        unsafeWindow
// ==/UserScript==

var $ = unsafeWindow.jQuery;

var bannerImages = []
/*
    'https://i.imgur.com/ptC8pyl.jpg',
    'https://i.imgur.com/Ece3hYj.jpg',
    'https://i.imgur.com/T22nJc6.png',
    'https://i.imgur.com/EzEYiEC.png',
    'https://i.imgur.com/RVV7fVL.png',
    'https://i.imgur.com/oM4QXGP.png',
    'https://dl.dropboxusercontent.com/u/6166376/banner.png',
    'https://i.imgur.com/z6oul4p.jpg',
    'https://i.imgur.com/JzMaSvM.jpg',
    'https://i.imgur.com/DpLvIm8.jpg',
    'https://i.imgur.com/GwVgxvD.jpg',
    'https://i.imgur.com/oV3xsfC.jpg',
    'https://i.imgur.com/V2kYfgv.jpg',
    'https://i.imgur.com/7gRJxLy.png',
    'https://i.imgur.com/eFlc02U.jpg'
*/

var bannerControl = $("<select id='bannerSelect'><option value='0'>--Default Banner--</option></select><button id='bannerPrev'>« Prev</button><button id='bannerNext'>Next »</button>");

$('#siteTable').prepend(bannerControl);

$('#bannerSelect').change(function() {
    selectedImage = parseInt($(this).val());
    if (selectedImage===0) {
        imageUrl = '//c.thumbs.redditmedia.com/-oIzLQ0UPDfe1Swn.png';
        imageHeight = 117;
    } else {
        var imageData = bannerImages[selectedImage-1]
        imageUrl = imageData.url;
        imageHeight = imageData.height;
    }
    $('#header').css('background-image', 'url(' + imageUrl + ')')
    $('#header-img').css('height', imageHeight + 'px')
})

$('#bannerPrev').click(function() {
    console.log("« Prev");
    var currentBanner = $('#bannerSelect').val();
    currentBanner--;
    if (currentBanner < 0) currentBanner = bannerImages.length;
    $('#bannerSelect').val(currentBanner);
    $('#bannerSelect').change();
})
$('#bannerNext').click(function() {
    console.log("Next »");
    var currentBanner = $('#bannerSelect').val();
    currentBanner++;
    if (currentBanner>bannerImages.length) currentBanner = 0;
    $('#bannerSelect').val(currentBanner);
    $('#bannerSelect').change();
})

var jsonUrl = window.location.toString() + '.json'
var things;
$.getJSON(jsonUrl, function(data) {
    things=data;
    console.log(things);

    things[1]['data']['children'].forEach(function(e,i,a) {
        body = e['data']['body'];
        var re = /\[([^\]]+)\]\(([^\)]+)\)/;
        var re2 = /https?:\/\/(i\.)?imgur.com\/(\w+)(\.jpg|\.png|\/)/;
        var match = re.exec(body);
        if (match) {
            var imgName = match[1];
            var imgUrl = match[2];
            // console.log(imgName);
            // console.log(imgUrl);
            var urlMatch = re2.exec(imgUrl);
            if (urlMatch) {
                // console.log(urlMatch);
                var imgId = urlMatch[2];
                $.ajax({
                    beforeSend: function(request) {
                        request.setRequestHeader('Authorization', 'Client-ID 2f0d90280e84f75');
                    },
                    dataType: "json",
                    url: "https://api.imgur.com/3/image/" + imgId,
                    success: function(imageData) {
                        bannerImages.push({'url': imageData.data.link, 'height': imageData.data.height});
                        var i = bannerImages.length;
                        $('#bannerSelect').append("<option value='" + (i+1) + "'>" + imgId + "</option>");
                    }
                });
            };
        }
    })
})
<|endoftext|>


<commit_before>// Generic html generation
function generateRowContent(id,content) {

	var html = "
";
	html += content;
	html += "
";

	return html;
}

function generateColContent(id,colSize,content) {

	var html = "
";
	html += content;
	html += "
";

	return html;
}

function generateColWell(colSize,id,label,value) {

	var html = "
";

	html += "
";
	html += "
"+label+"
";
	html += "
"+value+"
";

	html += "

";

	return html;
}

function generateColWellWithOnClick(colSize,id,label,value,onclick) {

	var html = "
";

	html += "
";
	html += "
"+label+"
";
	html += "
"+value+"
";

	html += "

";

	return html;
}

// Player HTML Generation
function populatePlayerDetails(playerData) {

	console.log("Populate player fields");
	document.getElementById("player-details").innerHTML = playerData["player"];
	document.getElementById("player-add-character").innerHTML = generatePlayerAddCharacter(playerData["player"]);
}

function populatePlayerCharacters(characters) {

	console.log("Populate player fields");
	document.getElementById("player-characters").innerHTML = generatePlayerCharacterList(characters);
}

function generatePlayerCharacterList(characters) {

	var html = "";

	var characterCount = 1;
	for( var character in characters )
	{
		var characterData = characters[character];

		var onclick = "db.obtainCharacterDetails({";

		onclick += "'name':'"+characterData["name"]+"',";
		onclick += "'player':'"+characterData["player"] +"',";
		onclick += "'campaign':'"+characterData["campaign"]+"'";
		onclick += "},charPopulateCallback)";

		html += generateRowContent(null,generateColWellWithOnClick(12,"player-character-"+characterCount,characterData["name"],characterData["campaign"],onclick));
	}

	html = generateColContent("player-character-list",8,html);

	return html;
}

function generatePlayerAddCharacter(playerName) {

	var html = "";

	var onclick = "populate.populateCharacterAdd("+playerName+")"

	html += generateRowContent(null,generateColWellWithOnClick(12,"player-add-character-display","Create new character","",onclick));

	html = generateColContent(null,8,html);

	return html;
}

// Character HTML Generation
function populateCharacterDisplay(characterData) {

	console.log("Populating character fields");
	document.getElementById("character-display").innerHTML = generateCharacterInfo(characterData);
}

function generateCharacterInfo(characterData) {

	var html = "";

	html += generateCharacterHeader(characterData);
	html += generateCharacterAttributes(characterData);
	html += generateCharacterBattleInfo(characterData);
	html += generateCharacterTraits(characterData);

	return html;
}

function generateCharacterHeader(characterData) {

	var html = "";

	var name = generateColWell(4,"name","Character Name",characterData["name"]);
	html += generateRowContent(null,name);

	var level = generateColWell(3,"classAndLevel","Class & Level",characterData["classAndLevel"]);
	var player = generateColWell(3,"player","Player Name",characterData["player"]);
	var background = generateColWell(3,"background","Background",characterData["background"]);
	var faction = generateColWell(3,"faction","Faction",characterData["faction"]);
	html += generateRowContent(null,level+player+background+faction);

	var race = generateColWell(3,"race","Race",characterData["race"]);
	var alignment = generateColWell(3,"alignment","Alignment",characterData["alignment"]);
	var xp = generateColWell(3,"xp","Experience Points",characterData["xp"]);
	var dci = generateColWell(3,"xp","DCI Number",characterData["dci"]);
	html += generateRowContent(null,race+alignment+xp+dci);

	html = generateRowContent("character-header",generateColContent(null,12,html));

	return html;
}

function generateCharacterAttributes(characterData) {

	var html = "";

	var str = generateColWell(2,"str","Strength",characterData["strength"]);
	var dex = generateColWell(2,"dex","Dexterity",characterData["dexterity"]);
	var cons = generateColWell(2,"const","Constitution",characterData["constitution"]);
	var intel = generateColWell(2,"int","Intelligence",characterData["intelligence"]);
	var wis = generateColWell(2,"wis","Wisdom",characterData["wisdom"]);
	var cha = generateColWell(2,"cha","Charisma",characterData["charisma"]);
	html += generateRowContent(null,str+dex+cons+intel+wis+cha);

	html = generateRowContent("character-attributes",generateColContent(null,12,html));

	return html;
}

function generateCharacterBattleInfo(characterData) {

	var html = "";

	var ac = generateColWell(4,"armour","Armour Class",characterData["armourClass"]);
	var init = generateColWell(4,"init","Initiative",characterData["initiative"]);
	var spd = generateColWell(4,"speed","Speed",characterData["speed"]);
	html += generateRowContent(null,ac+init+spd);

	var max = generateColWell(4,"maxHP","Maximum HP",characterData["maxHP"]);
	var curr = generateColWell(4,"currHP","Current HP",characterData["currHP"]);
	var temp = generateColWell(4,"tempHP","Temporary HP",characterData["tempHP"]);
	html += generateRowContent(null,max+curr+temp);

	var hit = generateColWell(4,"hitDice","Hit Dice",characterData["hitDice"]);
	var ds = generateColWell(8,"deathSaves","Death Saves",characterData["deathSaves"]);
	html += generateRowContent(null,hit+ds);

	html = generateRowContent("character-battle-info",generateColContent(null,12,html));

	return html;
}

function generateCharacterTraits(characterData) {

	var html = "";

	var personal = generateColWell(3,"personalTraits","Personal Traits",characterData["personalTraits"]);
	var ideals = generateColWell(3,"ideals","Ideals",characterData["ideals"]);
	var bonds = generateColWell(3,"bonds","Bonds",characterData["bonds"]);
	var flaws = generateColWell(3,"flaws","Flaws",characterData["flaws"]);
	html += generateRowContent(null,personal+ideals+bonds+flaws);

	html = generateRowContent("character-traits",generateColContent(null,12,html));

	return html;
}

//dndObj Class w/ functions above
function dndObj() {
	this.populateCharacterDetails = populateCharacterDisplay;
	this.populateCharacterAdd = populateCharacterDisplay;
	this.populatePlayerDetails = populatePlayerDetails;
	this.populatePlayerCharacters = populatePlayerCharacters;
}

var dndPopulate = new dndObj();
<commit_msg>Refactor character display - same character population for add and display<commit_after>// Generic html generation
function generateRowContent(id,content) {

	var html = "
";
	html += content;
	html += "
";

	return html;
}

function generateColContent(id,colSize,content) {

	var html = "
";
	html += content;
	html += "
";

	return html;
}

function generateColWell(colSize,id,label,value,addValue) {

	var html = "
";

	if( value == null )
	{
		value = "";
	}

	if( addValue )
	{
		html += "
";
		html += "
"+label+"
";
		html += "<input class=\"col-xs-12\" type=\"text\" name=\"add-character-"+id+"\" value=\""+value+"\">";
	}
	else
	{
		html += "
";
		html += "
"+label+"
";
		html += "
"+value+"
";
	}

	html += "

";

	return html;
}

function generateColWellWithOnClick(colSize,id,label,value,onclick) {

	var html = "
";

	html += "
";
	html += "
"+label+"
";
	html += "
"+value+"
";

	html += "

";

	return html;
}

// Player HTML Generation
function populatePlayerDetails(playerData) {

	console.log("Populate player fields");
	document.getElementById("player-details").innerHTML = playerData["player"];
	document.getElementById("player-add-character").innerHTML = generatePlayerAddCharacter(playerData["player"]);
}

function populatePlayerCharacters(characters) {

	console.log("Populate player fields");
	document.getElementById("player-characters").innerHTML = generatePlayerCharacterList(characters);
}

function generatePlayerCharacterList(characters) {

	var html = "";

	var characterCount = 1;
	for( var character in characters )
	{
		var characterData = characters[character];

		var onclick = "db.obtainCharacterDetails({";

		onclick += "'name':'"+characterData["name"]+"',";
		onclick += "'player':'"+characterData["player"] +"',";
		onclick += "'campaign':'"+characterData["campaign"]+"'";
		onclick += "},charPopulateCallback)";

		html += generateRowContent(null,generateColWellWithOnClick(12,"player-character-"+characterCount,characterData["name"],characterData["campaign"],onclick));
	}

	html = generateColContent("player-character-list",8,html);

	return html;
}

function generatePlayerAddCharacter(playerName) {

	var html = "";

	var onclick = "populate.populateCharacterAdd({'player':'"+playerName+"'})";

	html += generateRowContent(null,generateColWellWithOnClick(12,"player-add-character-display","Create new character","",onclick));

	html = generateColContent(null,8,html);

	return html;
}

// Character HTML Generation
function populateCharacterDisplay(characterData) {

	console.log("Populating character fields");
	document.getElementById("character-display").innerHTML = generateCharacterInfo(characterData,false);
}

function populateCharacterAdd(characterData) {

	console.log("Populating add character fields");
	document.getElementById("character-display").innerHTML = generateCharacterInfo(characterData,true);
}

function generateCharacterInfo(characterData,addValue) {

	var html = "";

	html += generateCharacterHeader(characterData,addValue);
	html += generateCharacterAttributes(characterData,addValue);
	html += generateCharacterBattleInfo(characterData,addValue);
	html += generateCharacterTraits(characterData,addValue);

	return html;
}

function generateCharacterHeader(characterData,addValue) {

	var html = "";

	var name = generateColWell(4,"name","Character Name",characterData["name"],addValue);
	html += generateRowContent(null,name);

	var level = generateColWell(3,"classAndLevel","Class & Level",characterData["classAndLevel"],addValue);
	var player = generateColWell(3,"player","Player Name",characterData["player"],false);
	var background = generateColWell(3,"background","Background",characterData["background"],addValue);
	var faction = generateColWell(3,"faction","Faction",characterData["faction"],addValue);
	html += generateRowContent(null,level+player+background+faction);

	var race = generateColWell(3,"race","Race",characterData["race"],addValue);
	var alignment = generateColWell(3,"alignment","Alignment",characterData["alignment"],addValue);
	var xp = generateColWell(3,"xp","Experience Points",characterData["xp"],addValue);
	var dci = generateColWell(3,"dci","DCI Number",characterData["dci"],addValue);
	html += generateRowContent(null,race+alignment+xp+dci);

	html = generateRowContent("character-header",generateColContent(null,12,html));

	return html;
}

function generateCharacterAttributes(characterData,addValue) {

	var html = "";

	var str = generateColWell(2,"strength","Strength",characterData["strength"],addValue);
	var dex = generateColWell(2,"dexterity","Dexterity",characterData["dexterity"],addValue);
	var cons = generateColWell(2,"constitution","Constitution",characterData["constitution"],addValue);
	var intel = generateColWell(2,"intelligence","Intelligence",characterData["intelligence"],addValue);
	var wis = generateColWell(2,"wisdom","Wisdom",characterData["wisdom"],addValue);
	var cha = generateColWell(2,"charisma","Charisma",characterData["charisma"],addValue);
	html += generateRowContent(null,str+dex+cons+intel+wis+cha);

	html = generateRowContent("character-attributes",generateColContent(null,12,html));

	return html;
}

function generateCharacterBattleInfo(characterData,addValue) {

	var html = "";

	var ac = generateColWell(4,"armourClass","Armour Class",characterData["armourClass"],addValue);
	var init = generateColWell(4,"initiative","Initiative",characterData["initiative"],addValue);
	var spd = generateColWell(4,"speed","Speed",characterData["speed"],addValue);
	html += generateRowContent(null,ac+init+spd);

	var max = generateColWell(4,"maxHP","Maximum HP",characterData["maxHP"],addValue);
	var curr = generateColWell(4,"currHP","Current HP",characterData["currHP"],addValue);
	var temp = generateColWell(4,"tempHP","Temporary HP",characterData["tempHP"],addValue);
	html += generateRowContent(null,max+curr+temp);

	var hit = generateColWell(4,"hitDice","Hit Dice",characterData["hitDice"],addValue);
	var ds = generateColWell(8,"deathSaves","Death Saves",characterData["deathSaves"],addValue);
	html += generateRowContent(null,hit+ds);

	html = generateRowContent("character-battle-info",generateColContent(null,12,html));

	return html;
}

function generateCharacterTraits(characterData,addValue) {

	var html = "";

	var personal = generateColWell(3,"personalTraits","Personal Traits",characterData["personalTraits"],addValue);
	var ideals = generateColWell(3,"ideals","Ideals",characterData["ideals"],addValue);
	var bonds = generateColWell(3,"bonds","Bonds",characterData["bonds"],addValue);
	var flaws = generateColWell(3,"flaws","Flaws",characterData["flaws"],addValue);
	html += generateRowContent(null,personal+ideals+bonds+flaws);

	html = generateRowContent("character-traits",generateColContent(null,12,html));

	return html;
}

//dndObj Class w/ functions above
function dndObj() {
	this.populateCharacterDetails = populateCharacterDisplay;
	this.populateCharacterAdd = populateCharacterAdd;
	this.populatePlayerDetails = populatePlayerDetails;
	this.populatePlayerCharacters = populatePlayerCharacters;
}

var dndPopulate = new dndObj();
<|endoftext|>


<commit_before>(function() {
    'use strict';

    function Barchart(domContainer, data, width, height) {
        var  _barchart = this;
        _barchart._data = data || [];
        _barchart._width = width || 640;
        _barchart._height = height || 480;
        _barchart._containerSelection = d3.select(domContainer);
        _barchart._svg = _barchart._containerSelection
          .append('svg')
          .classed('barchart', true)
          .attr('width', _barchart._width)
          .attr('height', _barchart._height);

    }

    Barchart.prototype.render = function() {
        var _barchart = this,
            barWidth = 30,
            barMargin = 5;

        var newX1 = 0;

        _barchart._svg.selectAll('rect.bar')
          .data(_barchart._data)
          .enter()
          .append('rect')
          .classed('bar', true)
          .attr('x', function(d, i) {
            var x = newX1;
            newX1 = x + barWidth + barMargin;
            return x;
          })
          .attr('width', barWidth)
          .attr('height', function(d) {
            return d;
          })
          .attr('y', function(d) {
              return _barchart._height - d;
          })

    };

    Barchart.prototype.data = function(data) {
        var  _barchart = this;

        if (arguments.length === 1) {
            _barchart._data = data;
        }

        return _barchart._data;
    };

    function _generateData(numberOfDataPoints, minNumber, maxNumber) {
        var max = maxNumber || 400,
            min = minNumber || 0,
            data = [];

        for (var i = 0; i < numberOfDataPoints; i++) {
            data.push((Math.round(Math.random() * max)) + min);
        }

        return data;
    }

    function _init(id) {
        var data = _generateData(30),
            barchart = new Barchart(document.getElementById(id), data);

        barchart.render();
    }

    _init('d3-container');

})();<commit_msg>* Basic vanilla chart with labels and interpolated colours.<commit_after>(function() {
    'use strict';

    function Barchart(domContainer, data, width, height) {
        var  _barchart = this;
        _barchart._data = data || [];
        _barchart._width = width || 640;
        _barchart._height = height || 480;
        _barchart._containerSelection = d3.select(domContainer);
        _barchart._svg = _barchart._containerSelection
          .append('svg')
          .classed('barchart', true)
          .attr('width', _barchart._width)
          .attr('height', _barchart._height);

    }

    Barchart.prototype.render = function() {
        var _barchart = this,
            barWidth = 30,
            barMargin = 5;

        var newX1 = 0;

        var colourInterpolator = d3.scale.linear()
          .domain([0,_barchart._height])
          .interpolate(d3.interpolateRgb)
          .range(["#000000", "#0000ff"]);

        var groups = _barchart._svg.selectAll('g')
          .data(_barchart._data);

        groups.enter().append('g');

        groups.attr('transform', function(d) {
             var x = newX1;
             newX1 = x + barWidth + barMargin;

             return 'translate(' + newX1 + ', ' + (_barchart._height - d) + ')';
         })
        .html('').append('rect').classed('bar', true)
        .attr('x', 0)
        .attr('y', 0)
        .style('fill', function(d) { return colourInterpolator(d); })
        .attr('width', barWidth)
        .attr('height', function(d) {
            return d;
        });

        groups.append('text').attr('fill', '#ffffff').attr('x', 3).attr('y', 15).text(function(d) {return d;});

        groups.exit().remove();

    };

    Barchart.prototype.data = function(data) {
        var  _barchart = this;

        if (arguments.length === 1) {
            _barchart._data = data;
        }

        return _barchart._data;
    };

    function _generateData(numberOfDataPoints, minNumber, maxNumber) {
        var max = maxNumber || 400,
            min = minNumber || 0,
            data = [];

        for (var i = 0; i < numberOfDataPoints; i++) {
            data.push((Math.round(Math.random() * max)) + min);
        }

        return data;
    }

    function _init(id) {
        var data = _generateData(30),
            barchart = new Barchart(document.getElementById(id), data);

        _startAnimating(barchart);

    }

    function _startAnimating(barchart) {
        barchart.data(_generateData(30));
        barchart.render();

        setTimeout(function() {
            _startAnimating(barchart);
        }, 750);
    }

    _init('d3-container');

})();<|endoftext|>