<commit_before>const async = require('async');
const AccountParser = require('../../utils/accountParser');
const EmbarkJS = require('embarkjs');
const utils = require('../../utils/utils');
const constants = require('../../constants');

const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';

class Test {
  constructor(options) {
    this.options = options || {};
    this.simOptions = {};
    this.events = options.events;
    this.plugins = options.config.plugins;
    this.logger = options.logger;
    this.ipc = options.ipc;
    this.configObj = options.config;
    this.ready = true;
    this.firstRunConfig = true;
    this.error = false;
    this.contracts = {};
    this.firstDeployment = true;
    this.needConfig = true;
    this.provider = null;
    this.accounts = [];
  }

  init(callback) {
    this.gasLimit = constants.tests.gasLimit;
    this.events.request('deploy:setGasLimit', this.gasLimit);
    if (this.options.node !== 'embark') {
      this.showNodeHttpWarning();
      return callback();
    }
    if (!this.ipc.connected) {
      this.engine.logger.error("Could not connect to Embark's IPC. Is embark running?");
      if(!this.options.inProcess) process.exit(1);
    }
    return this.connectToIpcNode(callback);
  }

  connectToIpcNode(cb) {
    this.ipc.request('blockchain:node', {}, (err, node) => {
      if (err) {
        this.logger.error(err.message || err);
        return cb();
      }
      this.options.node = node;
      this.showNodeHttpWarning();
      cb();
    });
  }

  initWeb3Provider(callback) {
    if (this.simOptions.accounts) {
      this.simOptions.accounts = this.simOptions.accounts.map((account) => {
        if (!account.hexBalance) {
          account.hexBalance = BALANCE_10_ETHER_IN_HEX;
        }
        return {balance: account.hexBalance, secretKey: account.privateKey};
      });
    }

    if (!this.simOptions.host && (this.options.node && this.options.node === 'vm')) {
      this.simOptions.type = 'vm';
    } else if (this.simOptions.host || (this.options.node && this.options.node !== 'vm')) {
      let options = this.simOptions;
      if (this.options.node && this.options.node !== 'vm') {
        options = utils.deconstructUrl(this.options.node);
      }

      if (!options.protocol) {
        options.protocol = (options.type === "rpc") ? 'http' : 'ws';
      }
      Object.assign(this.simOptions, options);
    }

    this.configObj.contractsConfig.deployment = this.simOptions;
    this.configObj.contractsConfig.deployment.coverage = this.options.coverage;
    this.events.request("config:contractsConfig:set", this.configObj.contractsConfig, () => {
      this.events.request('blockchain:reset', (err) => {
        if (err) {
          this.logger.error('Error restarting the blockchain connection');
        }
        callback(err);
      });
    });

  }

  showNodeHttpWarning() {
    if (this.options.node.startsWith('http')) {
      this.logger.warn("You are using http to connect to the node, as a result the gas details won't be correct." +
        " For correct gas details reporting, please use a websockets connection to your node.");
    }
  }

  onReady(callback) {
    const self = this;
    if (this.ready) {
      return callback();
    }
    if (this.error) {
      return callback(this.error);
    }

    let errorCallback, readyCallback;

    errorCallback = (err) => {
      self.events.removeListener('tests:ready', readyCallback);
      callback(err);
    };

    readyCallback = () => {
      self.events.removeListener('tests:deployError', errorCallback);
      callback();
    };

    this.events.once('tests:ready', readyCallback);
    this.events.once('tests:deployError', errorCallback);
  }

  checkDeploymentOptions(options, callback) {
    const self = this;
    let resetServices = false;
    const {host, port, type, accounts} = options.deployment || {};

    if (host && port && !['rpc', 'ws'].includes(type)) {
      return callback(__("contracts config error: unknown deployment type %s", type));
    }

    if (accounts || (port && port !== this.simOptions.port) || (type && type !== this.simOptions.type) ||
      (host && host !== this.simOptions.host)) {
      resetServices = true;
    }

    this.events.request("blockchain:get", (web3) => {
      if (accounts) {
        self.simOptions.accounts = AccountParser.parseAccountsConfig(accounts, web3);
      } else {
        self.simOptions.accounts = null;
      }

      Object.assign(self.simOptions, {
        host,
        port,
        type
      });

      if (!resetServices && !self.firstRunConfig) {
        return callback();
      }

      self.initWeb3Provider((err) => {
        if (err) {
          return callback(err);
        }
        self.firstRunConfig = false;
        callback();
      });
    });
  }

  config(options, callback) {
    const self = this;
    self.needConfig = false;
    if (typeof (options) === 'function') {
      callback = options;
      options = {};
    }
    if (!callback) {
      callback = function() {
      };
    }
    if (!options.contracts) {
      options.contracts = {};
    }
    self.ready = false;

    async.waterfall([
      function checkDeploymentOpts(next) {
        self.checkDeploymentOptions(options, next);
      },
      function compileContracts(next) {
        if (!self.firstDeployment) {
          return next();
        }
        console.info('Compiling contracts'.cyan);
        self.events.request("contracts:build", false, (err) => {
          self.firstDeployment = false;
          next(err);
        });
      },
      function resetContracts(next) {
        self.events.request("contracts:reset:dependencies", next);
      },
      function deploy(next) {
        self._deploy(options, (err, accounts) => {
          if (err) {
            self.events.emit('tests:deployError', err);
            self.error = err;
            return next(err);
          }
          self.ready = true;
          self.error = false;
          self.events.emit('tests:ready');
          next(null, accounts);
        });
      },
      function changeGlobalWeb3(accounts, next) {
        self.events.request('blockchain:get', (web3) => {
          global.web3 = web3;
          next(null, accounts);
        });
      }
    ], (err, accounts) => {
      if (err) {
        // TODO Do not exit in case of not a normal run (eg after a change)
        if(!self.options.inProcess) process.exit(1);
      }
      callback(null, accounts);
    });
  }

  _deploy(config, callback) {
    const self = this;
    async.waterfall([
      function getConfig(next) {
        self.events.request('config:contractsConfig:set',
          {contracts: config.contracts, versions: self.versions_default}, next);
      },
      function getAccounts(next) {
        self.events.request('blockchain:getAccounts', (err, accounts) => {
          if (err) {
            return next(err);
          }
          self.accounts = accounts;
          self.events.request('blockchain:defaultAccount:set', accounts[0], () => {
            next(null, accounts);
          });
        });
      },
      function getBalance(accounts, next) {
        self.events.request('blockchain:getBalance', self.accounts[0], (err, balance) => {
          if (err) {
            return next(err);
          }
          if (parseInt(balance, 10) === 0) {
            self.logger.warn("Warning: default account has no funds");
          }
          next(null, accounts);
        });
      },
      function deploy(accounts, next) {
        self.events.request('deploy:contracts:test', () => {
          next(null, accounts);
        });
      },
      function getWeb3Object(accounts, next) {
        self.events.request('blockchain:get', (web3) => {
          next(null, accounts, web3);
        });
      },
      function waitForProvidersReady(accounts, web3, next) {
        self.events.request('console:provider:ready', () => {
          next(null, accounts, web3);
        });
      },
      function createContractObject(accounts, web3, next) {
        self.events.request('contracts:all', (err, contracts) => {

          async.each(contracts, (contract, eachCb) => {
            if (!self.contracts[contract.className]) {
              self.contracts[contract.className] = {};
            }

            const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0];

            const newContract = testContractFactoryPlugin ? testContractFactoryPlugin.testContractFactory(contract, web3) : Test.getWeb3Contract(contract, web3);
            Object.setPrototypeOf(self.contracts[contract.className], newContract);

            eachCb();
          }, (err) => {
            next(err, accounts);
          });

        });
      }
    ], function(err, accounts) {
      if (err) {
        self.logger.error(__('terminating due to error'));
        self.logger.error(err.message || err);
        return callback(err);
      }
      callback(null, accounts);
    });
  }

  static getWeb3Contract(contract, web3) {
    const newContract = new EmbarkJS.Blockchain.Contract({
      abi: contract.abiDefinition,
      address: contract.deployedAddress,
      from: contract.deploymentAccount || web3.eth.defaultAccount,
      gas: constants.tests.gasLimit,
      web3: web3
    });

    newContract.filename = contract.filename;
    if (newContract.options) {
      newContract.options.from = contract.deploymentAccount || web3.eth.defaultAccount;
      newContract.options.data = contract.code;
      if (!newContract.options.data.startsWith('0x')) {
        newContract.options.data = '0x' + newContract.options.data;
      }
      newContract.options.gas = constants.tests.gasLimit;
    }

    return newContract;
  }

  require(path) {
    const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS'];

    // Contract require
    if (path.startsWith(contractsPrefix)) {
      const contractName = path.replace(contractsPrefix, "");
      const contract = this.contracts[contractName];
      if (contract) {
        return contract;
      }

      const newContract = {};
      this.contracts[contractName] = newContract;
      return newContract;
    }

    // EmbarkJS require
    if (path.startsWith(embarkJSPrefix)) {
      return EmbarkJS;
    }

    throw new Error(__('Unknown module %s', path));
  }
}

module.exports = Test;
<commit_msg>chore(test/coverage): warn when using RPC and coverage in tests<commit_after>const async = require('async');
const AccountParser = require('../../utils/accountParser');
const EmbarkJS = require('embarkjs');
const utils = require('../../utils/utils');
const constants = require('../../constants');

const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';

class Test {
  constructor(options) {
    this.options = options || {};
    this.simOptions = {};
    this.events = options.events;
    this.plugins = options.config.plugins;
    this.logger = options.logger;
    this.ipc = options.ipc;
    this.configObj = options.config;
    this.ready = true;
    this.firstRunConfig = true;
    this.error = false;
    this.contracts = {};
    this.firstDeployment = true;
    this.needConfig = true;
    this.provider = null;
    this.accounts = [];
  }

  init(callback) {
    this.gasLimit = constants.tests.gasLimit;
    this.events.request('deploy:setGasLimit', this.gasLimit);
    if (this.options.node !== 'embark') {
      this.showNodeHttpWarning();
      return callback();
    }
    if (!this.ipc.connected) {
      this.engine.logger.error("Could not connect to Embark's IPC. Is embark running?");
      if(!this.options.inProcess) process.exit(1);
    }
    return this.connectToIpcNode(callback);
  }

  connectToIpcNode(cb) {
    this.ipc.request('blockchain:node', {}, (err, node) => {
      if (err) {
        this.logger.error(err.message || err);
        return cb();
      }
      this.options.node = node;
      this.showNodeHttpWarning();
      cb();
    });
  }

  initWeb3Provider(callback) {
    if (this.simOptions.accounts) {
      this.simOptions.accounts = this.simOptions.accounts.map((account) => {
        if (!account.hexBalance) {
          account.hexBalance = BALANCE_10_ETHER_IN_HEX;
        }
        return {balance: account.hexBalance, secretKey: account.privateKey};
      });
    }

    if (!this.simOptions.host && (this.options.node && this.options.node === 'vm')) {
      this.simOptions.type = 'vm';
    } else if (this.simOptions.host || (this.options.node && this.options.node !== 'vm')) {
      let options = this.simOptions;
      if (this.options.node && this.options.node !== 'vm') {
        options = utils.deconstructUrl(this.options.node);
      }

      if (!options.protocol) {
        options.protocol = (options.type === "rpc") ? 'http' : 'ws';
      }
      Object.assign(this.simOptions, options);
    }

    this.configObj.contractsConfig.deployment = this.simOptions;
    this.configObj.contractsConfig.deployment.coverage = this.options.coverage;
    this.events.request("config:contractsConfig:set", this.configObj.contractsConfig, () => {
      this.events.request('blockchain:reset', (err) => {
        if (err) {
          this.logger.error('Error restarting the blockchain connection');
        }
        callback(err);
      });
    });

  }

  showNodeHttpWarning() {
    if (this.options.node.startsWith('http')) {
      this.logger.warn("You are using http to connect to the node, as a result the gas details won't be correct." +
        " For correct gas details reporting, please use a websockets connection to your node.");
    }
  }

  onReady(callback) {
    const self = this;
    if (this.ready) {
      return callback();
    }
    if (this.error) {
      return callback(this.error);
    }

    let errorCallback, readyCallback;

    errorCallback = (err) => {
      self.events.removeListener('tests:ready', readyCallback);
      callback(err);
    };

    readyCallback = () => {
      self.events.removeListener('tests:deployError', errorCallback);
      callback();
    };

    this.events.once('tests:ready', readyCallback);
    this.events.once('tests:deployError', errorCallback);
  }

  checkDeploymentOptions(options, callback) {
    const self = this;
    let resetServices = false;
    const {host, port, type, accounts} = options.deployment || {};

    if (host && port && !['rpc', 'ws'].includes(type)) {
      return callback(__("contracts config error: unknown deployment type %s", type));
    }

    if (this.options.coverage && type === 'rpc') {
      this.logger.warn(__('Coverage does not work with an RPC node'));
      this.logger.warn(__('You can change to a WS node (`"type": "ws"`) or use the simulator (no node or `"type": "vm"`)'));
    }

    if (accounts || (port && port !== this.simOptions.port) || (type && type !== this.simOptions.type) ||
      (host && host !== this.simOptions.host)) {
      resetServices = true;
    }

    this.events.request("blockchain:get", (web3) => {
      if (accounts) {
        self.simOptions.accounts = AccountParser.parseAccountsConfig(accounts, web3);
      } else {
        self.simOptions.accounts = null;
      }

      Object.assign(self.simOptions, {
        host,
        port,
        type
      });

      if (!resetServices && !self.firstRunConfig) {
        return callback();
      }

      self.initWeb3Provider((err) => {
        if (err) {
          return callback(err);
        }
        self.firstRunConfig = false;
        callback();
      });
    });
  }

  config(options, callback) {
    const self = this;
    self.needConfig = false;
    if (typeof (options) === 'function') {
      callback = options;
      options = {};
    }
    if (!callback) {
      callback = function() {
      };
    }
    if (!options.contracts) {
      options.contracts = {};
    }
    self.ready = false;

    async.waterfall([
      function checkDeploymentOpts(next) {
        self.checkDeploymentOptions(options, next);
      },
      function compileContracts(next) {
        if (!self.firstDeployment) {
          return next();
        }
        console.info('Compiling contracts'.cyan);
        self.events.request("contracts:build", false, (err) => {
          self.firstDeployment = false;
          next(err);
        });
      },
      function resetContracts(next) {
        self.events.request("contracts:reset:dependencies", next);
      },
      function deploy(next) {
        self._deploy(options, (err, accounts) => {
          if (err) {
            self.events.emit('tests:deployError', err);
            self.error = err;
            return next(err);
          }
          self.ready = true;
          self.error = false;
          self.events.emit('tests:ready');
          next(null, accounts);
        });
      },
      function changeGlobalWeb3(accounts, next) {
        self.events.request('blockchain:get', (web3) => {
          global.web3 = web3;
          next(null, accounts);
        });
      }
    ], (err, accounts) => {
      if (err) {
        // TODO Do not exit in case of not a normal run (eg after a change)
        if(!self.options.inProcess) process.exit(1);
      }
      callback(null, accounts);
    });
  }

  _deploy(config, callback) {
    const self = this;
    async.waterfall([
      function getConfig(next) {
        self.events.request('config:contractsConfig:set',
          {contracts: config.contracts, versions: self.versions_default}, next);
      },
      function getAccounts(next) {
        self.events.request('blockchain:getAccounts', (err, accounts) => {
          if (err) {
            return next(err);
          }
          self.accounts = accounts;
          self.events.request('blockchain:defaultAccount:set', accounts[0], () => {
            next(null, accounts);
          });
        });
      },
      function getBalance(accounts, next) {
        self.events.request('blockchain:getBalance', self.accounts[0], (err, balance) => {
          if (err) {
            return next(err);
          }
          if (parseInt(balance, 10) === 0) {
            self.logger.warn("Warning: default account has no funds");
          }
          next(null, accounts);
        });
      },
      function deploy(accounts, next) {
        self.events.request('deploy:contracts:test', () => {
          next(null, accounts);
        });
      },
      function getWeb3Object(accounts, next) {
        self.events.request('blockchain:get', (web3) => {
          next(null, accounts, web3);
        });
      },
      function waitForProvidersReady(accounts, web3, next) {
        self.events.request('console:provider:ready', () => {
          next(null, accounts, web3);
        });
      },
      function createContractObject(accounts, web3, next) {
        self.events.request('contracts:all', (err, contracts) => {

          async.each(contracts, (contract, eachCb) => {
            if (!self.contracts[contract.className]) {
              self.contracts[contract.className] = {};
            }

            const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0];

            const newContract = testContractFactoryPlugin ? testContractFactoryPlugin.testContractFactory(contract, web3) : Test.getWeb3Contract(contract, web3);
            Object.setPrototypeOf(self.contracts[contract.className], newContract);

            eachCb();
          }, (err) => {
            next(err, accounts);
          });

        });
      }
    ], function(err, accounts) {
      if (err) {
        self.logger.error(__('terminating due to error'));
        self.logger.error(err.message || err);
        return callback(err);
      }
      callback(null, accounts);
    });
  }

  static getWeb3Contract(contract, web3) {
    const newContract = new EmbarkJS.Blockchain.Contract({
      abi: contract.abiDefinition,
      address: contract.deployedAddress,
      from: contract.deploymentAccount || web3.eth.defaultAccount,
      gas: constants.tests.gasLimit,
      web3: web3
    });

    newContract.filename = contract.filename;
    if (newContract.options) {
      newContract.options.from = contract.deploymentAccount || web3.eth.defaultAccount;
      newContract.options.data = contract.code;
      if (!newContract.options.data.startsWith('0x')) {
        newContract.options.data = '0x' + newContract.options.data;
      }
      newContract.options.gas = constants.tests.gasLimit;
    }

    return newContract;
  }

  require(path) {
    const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS'];

    // Contract require
    if (path.startsWith(contractsPrefix)) {
      const contractName = path.replace(contractsPrefix, "");
      const contract = this.contracts[contractName];
      if (contract) {
        return contract;
      }

      const newContract = {};
      this.contracts[contractName] = newContract;
      return newContract;
    }

    // EmbarkJS require
    if (path.startsWith(embarkJSPrefix)) {
      return EmbarkJS;
    }

    throw new Error(__('Unknown module %s', path));
  }
}

module.exports = Test;
<|endoftext|>


<commit_before>var settings = require('../helpers/settings')

var fs = require('fs')
var path = require('path')
var moment = require('moment')

const FILTERS_FOLDER = settings.getFiltersDirectory()

function saveFilter (req, res, next) {
  var name = moment().format('YYYYMMDDHHmmss')
  var json = req.body
  fs.writeFile(path.join(FILTERS_FOLDER, name), JSON.stringify(json), function (err) {
    if (err) {
      res.json({error: true, code: 'save_failed', message: 'File did not save'})
    } else {
      res.json({error: false, message: 'Save successful'})
    }
  })
}

function listFilters (req, res, next) {
  fs.readdir(FILTERS_FOLDER, function (err, files) {
    var names = []
    for (var index in files) {
      names.push({id: files[index], name: JSON.parse(fs.readFileSync(path.join(FILTERS_FOLDER, files[index]), 'utf8')).name})
    }
    res.json({filters: names})
  })
}

function config (req, res, next) {
  var data = {
    canSaveFilters: true,
    saveFilterTargets: [
      { name: 'Local', path: '/mapfilter/filters/local', value: 'local' }
    ],
    bingProxy: '/bing-proxy',
    bingMetadata: '/bing-metadata',
    tiles: {
      url: '/tileLayers',
      tilesPath: '/monitoring-files/Maps/Tiles'
    }
  };
  data['tracks'] = {
    url: '/tracks',
    soundsPath: '/sounds',
    iconPath: '/mapfilter'
  }
  if (process.env.mapLayer)
    data['baseLayer'] = process.env.mapLayer
  var mapFilterSettings = settings.getMapFilterSettings();
  if (mapFilterSettings.mapZoom) {
    try {
      data['mapZoom'] = parseInt(mapFilterSettings.mapZoom, 10)
    } catch (e) {}
  }
  if (mapFilterSettings.mapCenterLat) {
    try {
      data['mapCenterLat'] = parseFloat(mapFilterSettings.mapCenterLat)
    } catch (e) {}
  }
  if (mapFilterSettings.mapCenterLong) {
    try {
      data['mapCenterLong'] = parseFloat(mapFilterSettings.mapCenterLong)
    } catch (e) {}
  }
  var filter = req.query.filter
  if (filter) {
    var file = path.join(settings.getFiltersDirectory(), filter)
    fs.access(file, fs.F_OK | fs.R_OK, function (err) {
      if (err) {
        res.json(data)
      } else {
        fs.readFile(file, 'utf8', function (err, contents) {
          var filterJson = JSON.parse(contents)
          data['filters'] = filterJson.value
          if (filterJson.baseLayer)
            data['baseLayer'] = filterJson.baseLayer
          res.json(data)
        })
      }
    })
  } else {
    res.json(data)
  }
}

function exists(path) {
  try {
    fs.accessSync(path, fs.F_OK | fs.R_OK);
  } catch (err) {
    return false;
  }
  return true;
}

module.exports = {
  listFilters: listFilters,
  saveFilter: saveFilter,
  config: config

}
<commit_msg>Support zoom/lat/long params from saved maps.<commit_after>var settings = require('../helpers/settings')

var fs = require('fs')
var path = require('path')
var moment = require('moment')

const FILTERS_FOLDER = settings.getFiltersDirectory()

function saveFilter (req, res, next) {
  var name = moment().format('YYYYMMDDHHmmss')
  var json = req.body
  fs.writeFile(path.join(FILTERS_FOLDER, name), JSON.stringify(json), function (err) {
    if (err) {
      res.json({error: true, code: 'save_failed', message: 'File did not save'})
    } else {
      res.json({error: false, message: 'Save successful'})
    }
  })
}

function listFilters (req, res, next) {
  fs.readdir(FILTERS_FOLDER, function (err, files) {
    var names = []
    for (var index in files) {
      names.push({id: files[index], name: JSON.parse(fs.readFileSync(path.join(FILTERS_FOLDER, files[index]), 'utf8')).name})
    }
    res.json({filters: names})
  })
}

function config (req, res, next) {
  var data = {
    canSaveFilters: true,
    saveFilterTargets: [
      { name: 'Local', path: '/mapfilter/filters/local', value: 'local' }
    ],
    bingProxy: '/bing-proxy',
    bingMetadata: '/bing-metadata',
    tiles: {
      url: '/tileLayers',
      tilesPath: '/monitoring-files/Maps/Tiles'
    }
  };
  data['tracks'] = {
    url: '/tracks',
    soundsPath: '/sounds',
    iconPath: '/mapfilter'
  }
  if (process.env.mapLayer)
    data['baseLayer'] = process.env.mapLayer
  var mapFilterSettings = settings.getMapFilterSettings();
  if (mapFilterSettings.mapZoom) {
    try {
      data['mapZoom'] = parseInt(mapFilterSettings.mapZoom, 10)
    } catch (e) {}
  }
  if (mapFilterSettings.mapCenterLat) {
    try {
      data['mapCenterLat'] = parseFloat(mapFilterSettings.mapCenterLat)
    } catch (e) {}
  }
  if (mapFilterSettings.mapCenterLong) {
    try {
      data['mapCenterLong'] = parseFloat(mapFilterSettings.mapCenterLong)
    } catch (e) {}
  }
  var filter = req.query.filter
  if (filter) {
    var file = path.join(settings.getFiltersDirectory(), filter)
    fs.access(file, fs.F_OK | fs.R_OK, function (err) {
      if (err) {
        res.json(data)
      } else {
        fs.readFile(file, 'utf8', function (err, contents) {
          var filterJson = JSON.parse(contents)
          data['filters'] = filterJson.value
          if (filterJson.baseLayer)
            data['baseLayer'] = filterJson.baseLayer
          if (filterJson.zoom)
            data['mapZoom'] = filterJson.zoom
          if (filterJson.latitude)
            data['mapCenterLat'] = filterJson.latitude
          if (filterJson.longitude)
            data['mapCenterLong'] = filterJson.longitude
          res.json(data)
        })
      }
    })
  } else {
    res.json(data)
  }
}

function exists(path) {
  try {
    fs.accessSync(path, fs.F_OK | fs.R_OK);
  } catch (err) {
    return false;
  }
  return true;
}

module.exports = {
  listFilters: listFilters,
  saveFilter: saveFilter,
  config: config

}
<|endoftext|>


<commit_before>/**
 * Add groups on assignment.
 */
Ext.define('devilry_subjectadmin.controller.AddGroups', {
    extend: 'Ext.app.Controller',
    mixins: [
        'devilry_subjectadmin.utils.LoadAssignmentMixin',
        'devilry_subjectadmin.utils.BasenodeBreadcrumbMixin'
    ],

    requires: [
        'Ext.tip.ToolTip',
        'devilry_subjectadmin.utils.UrlLookup'
    ],

    views: [
        'addgroups.Overview',
        'addgroups.AddGroups',
        'addgroups.AllIgnoredHelp',
        'addgroups.AllowDuplicatesCheckbox'
    ],

    models: [
        'Assignment'
    ],
    stores: [
        'RelatedStudentsRo',
        'RelatedExaminersRo',
        'Groups'
    ],

    refs: [{
        ref: 'overview',
        selector: 'addgroupsoverview'
    }, {
        ref: 'selectedStudentsGrid',
        selector: 'addgroupsoverview grid'
    }, {
        ref: 'allIgnoredHelp',
        selector: 'addgroupsoverview addgroupsallignored'
    }, {
        ref: 'automapExaminersCheckbox',
        selector: 'addgroupsoverview #automapExaminersCheckbox'
    }, {
        ref: 'includeTagsCheckbox',
        selector: 'addgroupsoverview #includeTagsCheckbox'
    }, {
        ref: 'tagsColumn',
        selector: 'addgroupsoverview #tagsColumn'
    }, {
        ref: 'tagsAndExaminersColumn',
        selector: 'addgroupsoverview #tagsAndExaminersColumn'
    }],

    init: function() {
        this.control({
            'addgroupsoverview': {
                render: this._onRender
            },

            'addgroupsoverview #saveButton': {
                click: this._onSave
            },
            'addgroupsoverview #selectAll': {
                click: this._onSelectAll
            },
            'addgroupsoverview #deselectAll': {
                click: this._onDeselectAll
            },
            'addgroupsoverview addgroupsallowduplicatescheckbox': {
                change: this._onAllowDuplicatesChange,
                render: this._setTooltip
            },
            'addgroupsoverview #includeTagsCheckbox': {
                change: this._onIncludeTagsChange,
                render: this._setTooltip
            },
            'addgroupsoverview #automapExaminersCheckbox': {
                change: this._onAutomapExaminersChange,
                render: this._setTooltip
            }
        });
    },

    _setTooltip: function(item) {
        var tip = Ext.create('Ext.tip.ToolTip', {
            target: item.el,
            constrainPosition: true,
            anchor: 'top',
            dismissDelay: 30000, // NOTE: Setting this high (30sec) instead of to 0 (no autodismiss) so that it disappears eventually even when the framework do not catch the event that should hide it.
            html: item.tooltip
        });
    },

    _onRender: function() {
        var assignment_id = this.getOverview().assignment_id;
        this.on_save_success_url = this.getOverview().on_save_success_url;
        this.getOverview().setLoading(true);
        this.setLoadingBreadcrumb();
        this.loadAssignment(assignment_id);
    },

    //
    //
    // Load stores
    //
    //

    onLoadAssignmentSuccess: function(record) {
        this.assignmentRecord = record;
        this.getGroupsStore().setAssignment(this.assignmentRecord.get('id'));
        this._setBreadcrumb();

        this.getRelatedExaminersRoStore().setAssignment(this.assignmentRecord.get('id'));
        this.getRelatedStudentsRoStore().setAssignment(this.assignmentRecord.get('id'));

        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        relatedStudentsStore.loadWithAutomaticErrorHandling({
            scope: this,
            success: this._onLoadRelatedStudentsStoreSuccess,
            errortitle: gettext('Failed to load students from the period')
        });
    },

    _handleLoadError: function(operation, title) {
        var error = Ext.create('devilry_extjsextras.DjangoRestframeworkProxyErrorHandler', operation);
        error.addErrors(null, operation);
        var errormessage = error.asHtmlList();
        Ext.widget('htmlerrordialog', {
            title: title,
            bodyHtml: errormessage
        }).show();
    },
    onLoadAssignmentFailure: function(operation) {
        this.getOverview().setLoading(false);
        this._handleLoadError(operation, gettext('Failed to load assignment'));
    },

    _onLoadRelatedStudentsStoreSuccess: function(records) {
        var relatedExaminersStore = this.getRelatedExaminersRoStore();
        relatedExaminersStore.loadWithAutomaticErrorHandling({
            scope: this,
            success: this._onLoadRelatedExaminersStoreSuccess,
            errortitle: gettext('Failed to load examiners from the period')
        });
    },

    _onLoadRelatedExaminersStoreSuccess: function() {
        this.getGroupsStore().loadWithAutomaticErrorHandling({
            scope: this,
            success: this._onLoad,
            errortitle: gettext('Failed to load groups')
        });
    },

    _onLoad: function() {
        this.getOverview().setLoading(false);
        this.relatedExaminersMappedByTag = this.getRelatedExaminersRoStore().getMappedByTags();

        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        relatedStudentsStore.clearFilter();
        this._filterOutRelatedStudentsAlreadyInGroup();
        relatedStudentsStore.sortBySpecialSorter('full_name');

        this._setBody();
    },

    _filterOutRelatedStudentsAlreadyInGroup: function() {
        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        var currentUsers = this.getGroupsStore().getGroupsMappedByUserId();
        relatedStudentsStore.filterBy(function(relatedStudentRecord) {
            var userid = relatedStudentRecord.get('user').id;
            return typeof currentUsers[userid] == 'undefined';
        });
    },

    _setBreadcrumb: function() {
        var breadcrumbtype = this.getOverview().breadcrumbtype;
        if(breadcrumbtype == 'managestudents') {
            this.setSubviewBreadcrumb(this.assignmentRecord, 'Assignment', [{
                text: gettext('Manage students'),
                url: devilry_subjectadmin.utils.UrlLookup.manageStudents(this.assignmentRecord.get('id'))
            }], gettext('Add students'));
        }
    },

    //
    //
    // Checkbox/button handlers
    //
    //

    _onSelectAll: function() {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        selModel.selectAll();
    },
    _onDeselectAll: function() {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        selModel.deselectAll();
    },

    _onAllowDuplicatesChange: function(field, allowDuplicates) {
        if(allowDuplicates) {
            this.getRelatedStudentsRoStore().clearFilter();
        } else {
            this._filterOutRelatedStudentsAlreadyInGroup();
        }
        this._checkAllIgnored();
    },
    _onIncludeTagsChange: function(field, includeTags) {
        if(includeTags) {
            this.getTagsColumn().show();
            this.getAutomapExaminersCheckbox().enable();
        } else {
            if(this.getAutomapExaminersCheckbox().getValue() == true) {
                this.getAutomapExaminersCheckbox().setValue(false);
                // NOTE: we do nothing more because changing automapExaminersCheckbox will trigger _onAutomapExaminersChange
            } else {
                this.getTagsColumn().hide();
            }
            this.getAutomapExaminersCheckbox().disable();
        }
    },
    _onAutomapExaminersChange: function(field, automapExaminers) {
        if(automapExaminers) {
            this.getTagsColumn().hide();
            this.getTagsAndExaminersColumn().show();
        } else {
            //this.getTagsColumn().show();
            this.getTagsAndExaminersColumn().hide();
            if(this.getIncludeTagsCheckbox().getValue() == true) {
                this.getTagsColumn().show();
            }
        }
    },

    _setBody: function() {
        var ignoredcount = this._getIgnoredCount();
        this.getOverview().setBody({
            xtype: 'addgroupspanel',
            ignoredcount: ignoredcount,
            relatedExaminersMappedByTag: this.relatedExaminersMappedByTag,
            periodinfo: this.assignmentRecord.getPeriodInfoFromBreadcrumb()
        });
        this._checkAllIgnored();
    },

    _getIgnoredCount: function() {
        var ignoredcount = this.getRelatedStudentsRoStore().getTotalCount() - this.getRelatedStudentsRoStore().getCount()
        return ignoredcount;
    },

    _checkAllIgnored: function() {
        var ignoredcount = this._getIgnoredCount();
        var allIgnored = this.getRelatedStudentsRoStore().getTotalCount() == ignoredcount;
        if(allIgnored) {
            var periodinfo = this.assignmentRecord.getPeriodInfoFromBreadcrumb()
            this.getAllIgnoredHelp().setBody(periodinfo);
            this.getOverview().getLayout().setActiveItem(1);
        } else {
            this.getOverview().getLayout().setActiveItem(0);
        }
    },

    //
    //
    // Save
    //
    //

    _onSave: function(button) {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        var selectedRelatedStudents = selModel.getSelection();
        var groupsStore = this.getGroupsStore();
        var includeTags = this.getIncludeTagsCheckbox().getValue();
        var automapExaminers = this.getAutomapExaminersCheckbox().getValue();

        Ext.Array.each(selectedRelatedStudents, function(relatedStudentRecord) {
            var groupRecord = groupsStore.addFromRelatedStudentRecord({
                relatedStudentRecord: relatedStudentRecord,
                includeTags: includeTags
            });
            if(automapExaminers) {
                groupRecord.setExaminersFromMapOfRelatedExaminers(this.relatedExaminersMappedByTag);
            }
        }, this);
        this._syncGroupsStore();
    },

    _syncGroupsStore: function() {
        console.log('sync started');
        this.getOverview().setLoading(gettext('Saving ...'));
        this.getGroupsStore().sync({
            scope: this,
            success: this._onSyncGroupsStoreSuccess,
            failure: this._onSyncGroupsStoreFailure
        });
    },

    _onSyncGroupsStoreSuccess: function(batch, options) {
        this.getOverview().setLoading(false);
        console.log('sync success', batch);
        var affectedRecords = [];
        var operations = batch.operations;
        Ext.Array.each(operations, function(operation) {
            if(operation.action == 'create') {
                Ext.Array.each(operation.records, function(record) {
                    affectedRecords.push(record);
                }, this);
            }
        }, this);

        this.application.route.navigate(this.on_save_success_url);
    },

    _onSyncGroupsStoreFailure: function(batch, options) {
        this.getOverview().setLoading(false);
        this._unmaskListOfGroups();
        console.log('failure', batch, options);
    }
});
<commit_msg>devilry_subjectadmin...AddGroups: Cleanup error handling.<commit_after>/**
 * Add groups on assignment.
 */
Ext.define('devilry_subjectadmin.controller.AddGroups', {
    extend: 'Ext.app.Controller',
    mixins: [
        'devilry_subjectadmin.utils.LoadAssignmentMixin',
        'devilry_subjectadmin.utils.BasenodeBreadcrumbMixin',
        'devilry_subjectadmin.utils.DjangoRestframeworkProxyErrorMixin'
    ],

    requires: [
        'Ext.tip.ToolTip',
        'devilry_subjectadmin.utils.UrlLookup'
    ],

    views: [
        'addgroups.Overview',
        'addgroups.AddGroups',
        'addgroups.AllIgnoredHelp',
        'addgroups.AllowDuplicatesCheckbox'
    ],

    models: [
        'Assignment'
    ],
    stores: [
        'RelatedStudentsRo',
        'RelatedExaminersRo',
        'Groups'
    ],

    refs: [{
        ref: 'overview',
        selector: 'addgroupsoverview'
    }, {
        ref: 'selectedStudentsGrid',
        selector: 'addgroupsoverview grid'
    }, {
        ref: 'allIgnoredHelp',
        selector: 'addgroupsoverview addgroupsallignored'
    }, {
        ref: 'automapExaminersCheckbox',
        selector: 'addgroupsoverview #automapExaminersCheckbox'
    }, {
        ref: 'includeTagsCheckbox',
        selector: 'addgroupsoverview #includeTagsCheckbox'
    }, {
        ref: 'tagsColumn',
        selector: 'addgroupsoverview #tagsColumn'
    }, {
        ref: 'tagsAndExaminersColumn',
        selector: 'addgroupsoverview #tagsAndExaminersColumn'
    }],

    init: function() {
        this.control({
            'addgroupsoverview': {
                render: this._onRender
            },

            'addgroupsoverview #saveButton': {
                click: this._onSave
            },
            'addgroupsoverview #selectAll': {
                click: this._onSelectAll
            },
            'addgroupsoverview #deselectAll': {
                click: this._onDeselectAll
            },
            'addgroupsoverview addgroupsallowduplicatescheckbox': {
                change: this._onAllowDuplicatesChange,
                render: this._setTooltip
            },
            'addgroupsoverview #includeTagsCheckbox': {
                change: this._onIncludeTagsChange,
                render: this._setTooltip
            },
            'addgroupsoverview #automapExaminersCheckbox': {
                change: this._onAutomapExaminersChange,
                render: this._setTooltip
            }
        });
        this.mon(this.getAssignmentModel().proxy, {
            scope: this,
            exception: this._onAssignmentProxyError
        });
        this.mon(this.getGroupsStore().proxy, {
            scope: this,
            exception: this._onGroupsProxyError
        });
        this.mon(this.getAssignmentModel().proxy, {
            scope: this,
            exception: this._onAssignmentProxyError
        });
        this.mon(this.getRelatedStudentsRoStore().proxy, {
            scope: this,
            exception: this._onRelatedStudentsProxyError
        });
        this.mon(this.getRelatedExaminersRoStore().proxy, {
            scope: this,
            exception: this._onRelatedExaminersProxyError
        });
    },

    _setTooltip: function(item) {
        var tip = Ext.create('Ext.tip.ToolTip', {
            target: item.el,
            constrainPosition: true,
            anchor: 'top',
            dismissDelay: 30000, // NOTE: Setting this high (30sec) instead of to 0 (no autodismiss) so that it disappears eventually even when the framework do not catch the event that should hide it.
            html: item.tooltip
        });
    },

    _onRender: function() {
        var assignment_id = this.getOverview().assignment_id;
        this.on_save_success_url = this.getOverview().on_save_success_url;
        this.getOverview().setLoading(true);
        this.setLoadingBreadcrumb();
        this.getAssignmentModel().load(assignment_id, {
            scope: this,
            callback: function(record, operation) {
                if(operation.success) {
                    this.onLoadAssignmentSuccess(record);
                } // NOTE: Errors are handled in _onAssignmentProxyError
            }
        });
    },

    _onProxyError: function(response, operation) {
        this.getOverview().setLoading(false);
        this.handleProxyErrorNoForm(this.application.getAlertmessagelist(), response, operation);
    },
    _onAssignmentProxyError: function(proxy, response, operation) {
        this._onProxyError(response, operation);
    },
    _onGroupsProxyError: function(proxy, response, operation) {
        this._onProxyError(response, operation);
    },
    _onAssignmentProxyError: function(proxy, response, operation) {
        this._onProxyError(response, operation);
    },
    _onRelatedStudentsProxyError: function(proxy, response, operation) {
        this._onProxyError(response, operation);
    },
    _onRelatedExaminersProxyError: function(proxy, response, operation) {
        this._onProxyError(response, operation);
    },

    //
    //
    // Load stores
    //
    //

    onLoadAssignmentSuccess: function(record) {
        this.assignmentRecord = record;
        this._setBreadcrumb();

        this.getRelatedStudentsRoStore().setAssignment(this.assignmentRecord.get('id'));
        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        relatedStudentsStore.load({
            scope: this,
            callback: function(records, operation) {
                if(operation.success) {
                    this._onLoadRelatedStudentsStoreSuccess();
                } // NOTE: Failure handled in _onRelatedStudentsProxyError
            }
        });
    },

    onLoadAssignmentFailure: function(operation) {
        this.getOverview().setLoading(false);
    },

    _onLoadRelatedStudentsStoreSuccess: function(records) {
        this.getRelatedExaminersRoStore().setAssignment(this.assignmentRecord.get('id'));
        var relatedExaminersStore = this.getRelatedExaminersRoStore();
        relatedExaminersStore.load({
            scope: this,
            callback: function(records, operation) {
                if(operation.success) {
                    this._onLoadRelatedExaminersStoreSuccess();
                } // NOTE: Failure handled in _onRelatedStudentsProxyError
            }
        });
    },

    _onLoadRelatedExaminersStoreSuccess: function() {
        this.getGroupsStore().setAssignment(this.assignmentRecord.get('id'));
        this.getGroupsStore().load({
            scope: this,
            callback: function(records, operation) {
                if(operation.success) {
                    this._onAllLoaded();
                } // NOTE: Failure handled in _onRelatedStudentsProxyError
            }
        });
    },

    _onAllLoaded: function() {
        this.getOverview().setLoading(false);
        this.relatedExaminersMappedByTag = this.getRelatedExaminersRoStore().getMappedByTags();

        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        relatedStudentsStore.clearFilter();
        this._filterOutRelatedStudentsAlreadyInGroup();
        relatedStudentsStore.sortBySpecialSorter('full_name');

        this._setBody();
    },

    _filterOutRelatedStudentsAlreadyInGroup: function() {
        var relatedStudentsStore = this.getRelatedStudentsRoStore();
        var currentUsers = this.getGroupsStore().getGroupsMappedByUserId();
        relatedStudentsStore.filterBy(function(relatedStudentRecord) {
            var userid = relatedStudentRecord.get('user').id;
            return typeof currentUsers[userid] == 'undefined';
        });
    },

    _setBreadcrumb: function() {
        var breadcrumbtype = this.getOverview().breadcrumbtype;
        if(breadcrumbtype == 'managestudents') {
            this.setSubviewBreadcrumb(this.assignmentRecord, 'Assignment', [{
                text: gettext('Manage students'),
                url: devilry_subjectadmin.utils.UrlLookup.manageStudents(this.assignmentRecord.get('id'))
            }], gettext('Add students'));
        }
    },

    //
    //
    // Checkbox/button handlers
    //
    //

    _onSelectAll: function() {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        selModel.selectAll();
    },
    _onDeselectAll: function() {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        selModel.deselectAll();
    },

    _onAllowDuplicatesChange: function(field, allowDuplicates) {
        if(allowDuplicates) {
            this.getRelatedStudentsRoStore().clearFilter();
        } else {
            this._filterOutRelatedStudentsAlreadyInGroup();
        }
        this._checkAllIgnored();
    },
    _onIncludeTagsChange: function(field, includeTags) {
        if(includeTags) {
            this.getTagsColumn().show();
            this.getAutomapExaminersCheckbox().enable();
        } else {
            if(this.getAutomapExaminersCheckbox().getValue() == true) {
                this.getAutomapExaminersCheckbox().setValue(false);
                // NOTE: we do nothing more because changing automapExaminersCheckbox will trigger _onAutomapExaminersChange
            } else {
                this.getTagsColumn().hide();
            }
            this.getAutomapExaminersCheckbox().disable();
        }
    },
    _onAutomapExaminersChange: function(field, automapExaminers) {
        if(automapExaminers) {
            this.getTagsColumn().hide();
            this.getTagsAndExaminersColumn().show();
        } else {
            //this.getTagsColumn().show();
            this.getTagsAndExaminersColumn().hide();
            if(this.getIncludeTagsCheckbox().getValue() == true) {
                this.getTagsColumn().show();
            }
        }
    },

    _setBody: function() {
        var ignoredcount = this._getIgnoredCount();
        this.getOverview().setBody({
            xtype: 'addgroupspanel',
            ignoredcount: ignoredcount,
            relatedExaminersMappedByTag: this.relatedExaminersMappedByTag,
            periodinfo: this.assignmentRecord.getPeriodInfoFromBreadcrumb()
        });
        this._checkAllIgnored();
    },

    _getIgnoredCount: function() {
        var ignoredcount = this.getRelatedStudentsRoStore().getTotalCount() - this.getRelatedStudentsRoStore().getCount()
        return ignoredcount;
    },

    _checkAllIgnored: function() {
        var ignoredcount = this._getIgnoredCount();
        var allIgnored = this.getRelatedStudentsRoStore().getTotalCount() == ignoredcount;
        if(allIgnored) {
            var periodinfo = this.assignmentRecord.getPeriodInfoFromBreadcrumb()
            this.getAllIgnoredHelp().setBody(periodinfo);
            this.getOverview().getLayout().setActiveItem(1);
        } else {
            this.getOverview().getLayout().setActiveItem(0);
        }
    },

    //
    //
    // Save
    //
    //

    _onSave: function(button) {
        var selModel = this.getSelectedStudentsGrid().getSelectionModel();
        var selectedRelatedStudents = selModel.getSelection();
        var groupsStore = this.getGroupsStore();
        var includeTags = this.getIncludeTagsCheckbox().getValue();
        var automapExaminers = this.getAutomapExaminersCheckbox().getValue();

        Ext.Array.each(selectedRelatedStudents, function(relatedStudentRecord) {
            var groupRecord = groupsStore.addFromRelatedStudentRecord({
                relatedStudentRecord: relatedStudentRecord,
                includeTags: includeTags
            });
            if(automapExaminers) {
                groupRecord.setExaminersFromMapOfRelatedExaminers(this.relatedExaminersMappedByTag);
            }
        }, this);
        this._syncGroupsStore();
    },

    _syncGroupsStore: function() {
        this.getOverview().setLoading(gettext('Saving ...'));
        this.getGroupsStore().sync({
            scope: this,
            success: this._onSyncGroupsStoreSuccess,
            failure: this._onSyncGroupsStoreFailure
        });
    },

    _onSyncGroupsStoreSuccess: function(batch, options) {
        this.getOverview().setLoading(false);
        console.log('sync success', batch);
        var affectedRecords = [];
        var operations = batch.operations;
        Ext.Array.each(operations, function(operation) {
            if(operation.action == 'create') {
                Ext.Array.each(operation.records, function(record) {
                    affectedRecords.push(record);
                }, this);
            }
        }, this);

        this.application.route.navigate(this.on_save_success_url);
    },

    _onSyncGroupsStoreFailure: function(batch, options) {
        this.getOverview().setLoading(false);
        console.log('failure', batch, options);
    }
});
<|endoftext|>


<commit_before>// Copyright 2016 Joseph W. May. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * An object for assisting with the storage of strings and arrays in the
 * user properties of a Google Apps Script.
 *
 * @constructor
 */
var PropertyStore = function() {
  this.store = PropertiesService.getUserProperties();
};

/**
 * Set a property with the given key and value. An optional flag for storing
 * an array is available, which converts the array into a JSON string.
 *
 * @param {string} key The key that labels the stored data.
 * @param {string|array} value The value to be stored.
 * @param {boolean=} isArray Set to true if storing an array.
 */
PropertyStore.prototype.setProperty = function(key, value, isArray) {
  value = isArray === true ? JSON.stringify(value) : value;
  this.store.setProperty(key, value);
};

/**
 * Get a property with the given key. An optional flag for retrieving an array
 * is available, which converts the JSON string into an array object.
 *
 * @param {string} key The key that labels the stored data.
 * @param {boolean=} isArray Set to true if retrieving a stored array.
 * @return A string if isArray set to false, otherwise, an array object.
 */
PropertyStore.prototype.getProperty = function(key, isArray) {
  var property = this.store.getProperty(key);
  property = isArray === true ? JSON.parse(property) : property;
  return property;
};

/**
 * Deletes all properties in the current properties store.
 */
PropertyStore.prototype.clean = function() {
  this.store.deleteAllProperties();
};<commit_msg>use the DocumentProperties for storage<commit_after>// Copyright 2016 Joseph W. May. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * An object for assisting with the storage of strings and arrays in the
 * document properties of a Google Apps Script.
 *
 * @constructor
 */
var PropertyStore = function() {
  this.store = PropertiesService.getDocumentProperties();
};

/**
 * Set a property with the given key and value. An optional flag for storing
 * an array is available, which converts the array into a JSON string.
 *
 * @param {string} key The key that labels the stored data.
 * @param {string|array} value The value to be stored.
 * @param {boolean=} isArray Set to true if storing an array.
 */
PropertyStore.prototype.setProperty = function(key, value, isArray) {
  value = isArray === true ? JSON.stringify(value) : value;
  this.store.setProperty(key, value);
};

/**
 * Get a property with the given key. An optional flag for retrieving an array
 * is available, which converts the JSON string into an array object.
 *
 * @param {string} key The key that labels the stored data.
 * @param {boolean=} isArray Set to true if retrieving a stored array.
 * @return A string if isArray set to false, otherwise, an array object.
 */
PropertyStore.prototype.getProperty = function(key, isArray) {
  var property = this.store.getProperty(key);
  property = isArray === true ? JSON.parse(property) : property;
  return property;
};

/**
 * Deletes all properties in the current properties store.
 */
PropertyStore.prototype.clean = function() {
  this.store.deleteAllProperties();
};<|endoftext|>


<commit_before>(function () {
    /* global L */
    'use strict';
    L.GeoJSON.MSI = L.GeoJSON.extend({
        options: {
            language: 'en',
            soap: {
                url: 'http://api.fcoo.dk/msi/ws/warning',
                appendMethodToURL: false,
                soap12: false,
                SOAPAction: "",
                noPrefix: true,
                data: {
                    arg0: 'DK'
                },
                namespaceQualifier: 'mes',
                namespaceURL: 'http://message.webservice.core.msiedit.frv.dk/',
            }
        },

        initialize: function (options) {
            L.setOptions(this, options);
            this._layers = {};
        },

        onAdd: function (map) {
            var that = this;
            var success = function (soapResponse) {
                var jsonResponse = soapResponse.toJSON();
                var method = 'getActiveWarningCountryResponse';
                if (that.options.language == 'da') {
                    method = 'getActiveWarningResponse';
                }
                var activeWarnings = jsonResponse.Body[method].return.item;
                if (! activeWarnings.constructor === Array) {
                    activeWarnings = [activeWarnings];
                }
                var geojson = {};
                geojson.type = 'FeatureCollection';
                geojson.features = [];
                for (var k in activeWarnings) {
                    var item = activeWarnings[k];
                    if (that.options.language == 'da') {
                        var lat = parseFloat(item.latitude);
                        var lng = parseFloat(item.longitude);
                        var coords = [lng, lat];
                        var locationType = 'Point';
                        var mainArea = item.mainArea;
                        var subArea = item.subArea;
                        var encText = item.ENCtext;
                        var validFrom = item.created;
                        var navWarning = item.text.join('');
                    } else {
                        var coords;
                        var locationType;
                        if (item.points.point.constructor === Array) {
                            coords = [];
                            locationType = 'LineString';
                            for (var kk in item.points.point) {
                                var lat = item.points.point[kk].latitude;
                                var lng = item.points.point[kk].longitude;
                                var coord = [parseFloat(lng), parseFloat(lat)]
                                coords.push(coord);
                            }
                        } else {
                            var lat = item.points.point.latitude;
                            var lng = item.points.point.longitude;
                            coords = [parseFloat(lng), parseFloat(lat)]
                            locationType = item.locationType;
                        }
                        var mainArea = item.areaEnglish;
                        var subArea = item.subarea;
                        var encText = item.encText;
                        var validFrom = item.validFrom;
                        var navWarning = item.navWarning;
                    }
                    var newFeature = {
                        "type": "Feature",
                        "geometry": {
                            "type": locationType,
                            "coordinates": coords
                        },
                        "properties": {
                            "mainarea": mainArea,
                            "created": item.created,
                            "encText": encText,
                            "navWarning": navWarning,
                            "subarea": subArea,
                            "updated": item.updated,
                            "validFrom": validFrom
                        }
                    };
                    geojson.features.push(newFeature);
                }
                if (that.options.language == 'da') {
                    var popup_template = '

Aktuelle advarsler

{body}

Lavet: {created}

Opdateret: {updated}

Gyldig fra: {validFrom}

Hovedområde: {mainarea}

Underområde: {subarea}

Længdegrad: {longitude}

Breddegrad: {latitude}

';
                } else {
                    var popup_template = '

Maritime Safety Information

{body}

Created: {created}

Updated: {updated}

Valid from: {validFrom}

Main area: {mainarea}

Subarea: {subarea}

Longitude: {longitude}

Latitude: {latitude}

';
                }
                var lgeojson = L.geoJson(geojson, {
                    onEachFeature: function (feature, layer) {
                        var innerhtml = popup_template.replace('{title}', feature.properties.encText);
                        innerhtml = innerhtml.replace('{body}', feature.properties.navWarning);
                        innerhtml = innerhtml.replace('{created}', feature.properties.created);
                        innerhtml = innerhtml.replace('{updated}', feature.properties.updated);
                        innerhtml = innerhtml.replace('{validFrom}', feature.properties.validFrom);
                        innerhtml = innerhtml.replace('{mainarea}', feature.properties.mainarea);
                        innerhtml = innerhtml.replace('{subarea}', feature.properties.subarea);
                        innerhtml = innerhtml.replace('{longitude}', feature.geometry.coordinates[0]);
                        innerhtml = innerhtml.replace('{latitude}', feature.geometry.coordinates[1]);
                        layer.bindPopup(innerhtml, {maxWidth: 350, maxHeight: 600});
                    },
                    /*jshint unused: true*/
                    pointToLayer: function (feature, latlng) {
                        return L.circleMarker(latlng, {
                                   radius: 8,
                                   weight: 1,
                                   color: "#e2007a",
                                   opacity: 1,
                                   fillColor: "#e2007a",
                                   fillOpacity: 0.2
                        });
                    },
                    /*jshint unused: false*/
                    style: function (feature) {
                        var weight = 1;
                        if (feature.geometry.type == 'LineString') {
                            var weight = 4;
                        };
                        return {
                            weight: weight,
                            color: "#e2007a",
                            opacity: 1,
                            fillColor: "#e2007a",
                            fillOpacity: 0.2
                        };
                    }
                });
                that.addLayer(lgeojson);
                L.GeoJSON.prototype.onAdd.call(that, map);
            };

            // Make SOAP request
            var soapOptions = this.options.soap;
            if (this.options.language == 'da') {
                soapOptions.method = 'mes:getActiveWarning';
            } else {
                soapOptions.method =  'mes:getActiveWarningCountry';
            }
            soapOptions.success = success;
            soapOptions.error = function (soapResponse) {
                // show error
                console.log(soapResponse.toJSON());
            };
            $.soap(soapOptions);

        },

  });

  return L.GeoJSON.MSI;

}());

<commit_msg>fixed multipoint features printout<commit_after>(function () {
    /* global L */
    'use strict';
    L.GeoJSON.MSI = L.GeoJSON.extend({
        options: {
            language: 'en',
            soap: {
                url: 'http://api.fcoo.dk/msi/ws/warning',
                appendMethodToURL: false,
                soap12: false,
                SOAPAction: "",
                noPrefix: true,
                data: {
                    arg0: 'DK'
                },
                namespaceQualifier: 'mes',
                namespaceURL: 'http://message.webservice.core.msiedit.frv.dk/',
            }
        },

        initialize: function (options) {
            L.setOptions(this, options);
            this._layers = {};
        },

        onAdd: function (map) {
            var that = this;
            var success = function (soapResponse) {
                var jsonResponse = soapResponse.toJSON();
                var method = 'getActiveWarningCountryResponse';
                if (that.options.language == 'da') {
                    method = 'getActiveWarningResponse';
                }
                var activeWarnings = jsonResponse.Body[method].return.item;
                if (! activeWarnings.constructor === Array) {
                    activeWarnings = [activeWarnings];
                }
                var geojson = {};
                geojson.type = 'FeatureCollection';
                geojson.features = [];
                for (var k in activeWarnings) {
                    var item = activeWarnings[k];
                    if (that.options.language == 'da') {
                        var lat = parseFloat(item.latitude);
                        var lng = parseFloat(item.longitude);
                        var coords = [lng, lat];
                        var locationType = 'Point';
                        var mainArea = item.mainArea;
                        var subArea = item.subArea;
                        var encText = item.ENCtext;
                        var validFrom = item.created;
                        var navWarning = item.text.join('');
                    } else {
                        var coords;
                        var locationType;
                        if (item.points.point.constructor === Array) {
                            coords = [];
                            locationType = 'LineString';
                            for (var kk in item.points.point) {
                                var lat = item.points.point[kk].latitude;
                                var lng = item.points.point[kk].longitude;
                                var coord = [parseFloat(lng), parseFloat(lat)]
                                coords.push(coord);
                            }
                        } else {
                            var lat = item.points.point.latitude;
                            var lng = item.points.point.longitude;
                            coords = [parseFloat(lng), parseFloat(lat)]
                            locationType = item.locationType;
                        }
                        var mainArea = item.areaEnglish;
                        var subArea = item.subarea;
                        var encText = item.encText;
                        var validFrom = item.validFrom;
                        var navWarning = item.navWarning;
                    }
                    var newFeature = {
                        "type": "Feature",
                        "geometry": {
                            "type": locationType,
                            "coordinates": coords
                        },
                        "properties": {
                            "mainarea": mainArea,
                            "created": item.created,
                            "encText": encText,
                            "navWarning": navWarning,
                            "subarea": subArea,
                            "updated": item.updated,
                            "validFrom": validFrom
                        }
                    };
                    geojson.features.push(newFeature);
                }
                if (that.options.language == 'da') {
                    var popup_template = '

Aktuelle advarsler

{body}

Lavet: {created}

Opdateret: {updated}

Gyldig fra: {validFrom}

Hovedområde: {mainarea}

Underområde: {subarea}

Længdegrad: {longitude}

Breddegrad: {latitude}

';
                } else {
                    var popup_template = '

Maritime Safety Information

{body}

Created: {created}

Updated: {updated}

Valid from: {validFrom}

Main area: {mainarea}

Subarea: {subarea}

{points}
';
                }
                var lgeojson = L.geoJson(geojson, {
                    onEachFeature: function (feature, layer) {
                        var innerhtml = popup_template.replace('{title}', feature.properties.encText);
                        innerhtml = innerhtml.replace('{body}', feature.properties.navWarning);
                        innerhtml = innerhtml.replace('{created}', feature.properties.created);
                        innerhtml = innerhtml.replace('{updated}', feature.properties.updated);
                        innerhtml = innerhtml.replace('{validFrom}', feature.properties.validFrom);
                        innerhtml = innerhtml.replace('{mainarea}', feature.properties.mainarea);
                        innerhtml = innerhtml.replace('{subarea}', feature.properties.subarea);
                        var point_template = '
Longitude: {longitude}

Latitude: {latitude}
';
                        var points = '';
                        if (feature.geometry.type !== 'Point') {
                            for (var kk in feature.geometry.coordinates) {
                                var point = feature.geometry.coordinates[kk];
                                points += point_template;
                                points = points.replace('{longitude}', point[0]);
                                points = points.replace('{latitude}', point[1]);
                            }
                        } else {
                            points = point_template.replace('{longitude}', feature.geometry.coordinates[0]);
                            points = points.replace('{latitude}', feature.geometry.coordinates[1]);
                        };
                        innerhtml = innerhtml.replace('{points}', points);
                        layer.bindPopup(innerhtml, {maxWidth: 350, maxHeight: 600});
                    },
                    /*jshint unused: true*/
                    pointToLayer: function (feature, latlng) {
                        return L.circleMarker(latlng, {
                                   radius: 8,
                                   weight: 1,
                                   color: "#e2007a",
                                   opacity: 1,
                                   fillColor: "#e2007a",
                                   fillOpacity: 0.2
                        });
                    },
                    /*jshint unused: false*/
                    style: function (feature) {
                        var weight = 1;
                        if (feature.geometry.type == 'LineString') {
                            var weight = 4;
                        };
                        return {
                            weight: weight,
                            color: "#e2007a",
                            opacity: 1,
                            fillColor: "#e2007a",
                            fillOpacity: 0.2
                        };
                    }
                });
                that.addLayer(lgeojson);
                L.GeoJSON.prototype.onAdd.call(that, map);
            };

            // Make SOAP request
            var soapOptions = this.options.soap;
            if (this.options.language == 'da') {
                soapOptions.method = 'mes:getActiveWarning';
            } else {
                soapOptions.method =  'mes:getActiveWarningCountry';
            }
            soapOptions.success = success;
            soapOptions.error = function (soapResponse) {
                // show error
                console.log(soapResponse.toJSON());
            };
            $.soap(soapOptions);

        },

  });

  return L.GeoJSON.MSI;

}());

<|endoftext|>


<commit_before>import { LightShadow } from './LightShadow.js';
import { _Math } from '../math/Math.js';
import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';

/**
 * @author mrdoob / http://mrdoob.com/
 */

function SpotLightShadow() {

	LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );

}

SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {

	constructor: SpotLightShadow,

	isSpotLightShadow: true,

	update: function ( light ) {

		var camera = this.camera;

		var fov = _Math.RAD2DEG * 2 * light.angle;
		var aspect = this.mapSize.width / this.mapSize.height;
		var far = light.distance || camera.far;

		if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {

			camera.fov = fov;
			camera.aspect = aspect;
			camera.far = far;
			camera.updateProjectionMatrix();

		}

	}

} );

export { SpotLightShadow };
<commit_msg>Move matrix calcs from webglshadows<commit_after>import { LightShadow } from './LightShadow.js';
import { _Math } from '../math/Math.js';
import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';

/**
 * @author mrdoob / http://mrdoob.com/
 */

function SpotLightShadow() {

	LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );

}

SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {

	constructor: SpotLightShadow,

	isSpotLightShadow: true,

  updateMatrices: function ( light, viewCamera, viewportIndex ) {

		var camera = this.camera,
      lookTarget = this._lookTarget,
      lightPositionWorld = this._lightPositionWorld;

		var fov = _Math.RAD2DEG * 2 * light.angle;
		var aspect = this.mapSize.width / this.mapSize.height;
		var far = light.distance || camera.far;

		if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {

			camera.fov = fov;
			camera.aspect = aspect;
			camera.far = far;
			camera.updateProjectionMatrix();

		}

    lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
		camera.position.copy( lightPositionWorld );

    lookTarget.setFromMatrixPosition( light.target.matrixWorld );
		camera.lookAt( lookTarget );
		camera.updateMatrixWorld();

    LightShadow.prototype.updateMatrices.call( this, light, viewCamera, viewportIndex );

  }

} );

export { SpotLightShadow };
<|endoftext|>


<commit_before>'use strict';

module.exports = function (aplazame) {

  var _ = aplazame._,
      $live = require('live-dom'),
      _amountGetter = require('./data-simulator-amount')(aplazame),
      Widget = require('./data-simulator-widget')(aplazame);

  $live('[data-aplazame-simulator]', function (widget_el) {

    var simulator_options = { view: widget_el.getAttribute('data-view') || 'product' },
        widget = new Widget(widget_el, {
          currency:  widget_el.getAttribute('data-currency') || 'EUR',
          country:  widget_el.getAttribute('data-country') || 'ES',
        }),
        amountGetter = _amountGetter(widget_el),
        current_amount = amountGetter() || widget_el.getAttribute('data-amount') && Number( widget_el.getAttribute('data-amount') ),
        current_qty = amountGetter.qtySelector ? ( amountGetter.getQty(amountGetter.qtySelector) || 1 ) : 1,
        qty_interval,
        updateAmount = function (amount, qty) {
          // console.log('updateAmount', amount, qty);
          current_amount = amount;
          if( qty !== undefined ) current_qty = qty;
          widget_el.style.opacity = 0.5;
          aplazame.simulator( amount*( qty === undefined ? current_qty : qty ), simulator_options, function (_choices, _options) {
            if( qty !== undefined && qty !== current_qty ) return;
            if( _options.widget.disabled ) {
              if(qty_interval) clearInterval(qty_interval);
              // _removeListener(onDomChanges);
              $live.off(onDomChanges);
              return;
            }
            widget.render(_choices, _options);
            widget_el.style.opacity = null;
          });
        },
        onDomChanges = _.debounce(function () {
          // if( !document.body.contains(widget_el) ) return _removeListener(onDomChanges);
          if( !document.body.contains(widget_el) ) return $live.off(onDomChanges);

          var amount = amountGetter();

          if( amount !== current_amount ) updateAmount(amount);
        });

    if( amountGetter.qtySelector ) qty_interval = setInterval(function () {
      var qty = amountGetter.getQty(amountGetter.qtySelector) || 1;

      if( qty === current_qty ) return;
      updateAmount(current_amount, qty);
    }, 120);

    // dom_listeners.push(onDomChanges);
    $live(onDomChanges);

    updateAmount(current_amount);

  });

};
<commit_msg>instalment simulator empty amount fix<commit_after>'use strict';

module.exports = function (aplazame) {

  var $live = require('live-dom'),
      _amountGetter = require('./data-simulator-amount')(aplazame),
      Widget = require('./data-simulator-widget')(aplazame);

  $live('[data-aplazame-simulator]', function (widget_el) {

    var simulator_options = { view: widget_el.getAttribute('data-view') || 'product' },
        widget = new Widget(widget_el, {
          currency:  widget_el.getAttribute('data-currency') || 'EUR',
          country:  widget_el.getAttribute('data-country') || 'ES',
        }),
        amountGetter = _amountGetter(widget_el),
        current_amount = amountGetter() || widget_el.getAttribute('data-amount') && Number( widget_el.getAttribute('data-amount') ),
        current_qty = amountGetter.qtySelector ? ( amountGetter.getQty(amountGetter.qtySelector) || 1 ) : 1,
        qty_interval,
        updateAmount = function (amount, qty) {
          // console.log('updateAmount', amount, qty);
          current_amount = amount;
          if( qty !== undefined ) current_qty = qty;
          widget_el.style.opacity = 0.5;
          aplazame.simulator( amount*( qty === undefined ? current_qty : qty ), simulator_options, function (_choices, _options) {
            if( qty !== undefined && qty !== current_qty ) return;
            if( _options.widget.disabled ) {
              if(qty_interval) clearInterval(qty_interval);
              // _removeListener(onDomChanges);
              $live.off(onDomChanges);
              return;
            }
            widget.render(_choices, _options);
            widget_el.style.opacity = null;
          });
        },
        onDomChanges = function () {
          // if( !document.body.contains(widget_el) ) return _removeListener(onDomChanges);
          if( !document.body.contains(widget_el) ) return $live.off(onDomChanges);

          var amount = amountGetter();

          if( amount && amount !== current_amount ) updateAmount(amount);
        };

    if( amountGetter.qtySelector ) qty_interval = setInterval(function () {
      var qty = amountGetter.getQty(amountGetter.qtySelector) || 1;

      if( qty === current_qty ) return;
      updateAmount(current_amount, qty);
    }, 120);

    // dom_listeners.push(onDomChanges);
    $live(onDomChanges);

    updateAmount(current_amount);

  });

};
<|endoftext|>


<commit_before>    /** @jsx React.DOM */

var React = require('react/addons');
var ReactApp = React.createFactory(require('./components/ReactApp').ReactApp);

var mountNode = document.getElementById("react-main-mount");

React.renderComponent(new ReactApp({}), mountNode);
<commit_msg>remove factory call in browser entry point<commit_after>    /** @jsx React.DOM */

var React = require('react/addons');
var ReactApp = require('./components/ReactApp');

var mountNode = document.getElementById("react-main-mount");

React.render(new ReactApp({}), mountNode);
<|endoftext|>


<commit_before>/*jslint indent:2, browser:true, devel:true, maxlen:80 nomen:false */
/*global $ require __dirname process */
/* Copyright (c) 2010 Jeremiah Dodds <jeremiah.dodds@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var sys = require('sys'),
url = require('url'),
fs = require('fs'),
http = require('http'),
path = require('path'),
events = require('events'),
child_process = require('child_process'),
makefile_templ = [
  '#### Change these settings to modify how this ISO is built.',
  '#  The directory that you\'ll be using for the actual build process.',
  'WORKDIR=work',
  '#  A list of packages to install, either space separated in a string or line separated in a file. Can include groups.',
  'PACKAGES="$(shell cat packages.list) syslinux"',
  '# The name of our ISO. Does not specify the architecture!',
  'NAME=myarch',
  '# Version will be appended to the ISO.',
  'VER=1.00',
  '# Kernel version. You\'ll need this. Don\'t change it.',
  'kver_FILE=$(WORKDIR)/root-image/etc/mkinitcpio.d/kernel26.kver',
  '# Architecture will also be appended to the ISO name.',
  'ARCH?=x86_64',
  '# Current working directory',
  'PWD:=$(shell pwd)',
  '# This is going to be the full name the final iso/img will carry',
  'FULLNAME="$(PWD)"/$(NAME)-$(VER)-$(ARCH)',
  '# Default make instruction to build everything.',
  'all: myarch',
  '# The following will first run the base-fs routine before creating the final iso image.',
  'myarch: base-fs',
  '	mkarchiso -v -p syslinux iso "$(WORKDIR)" "$(FULLNAME)".iso',
  '# This is the main rule for make the working filesystem. It will run routines from left to right. ',
  '# Thus, root-image is called first and syslinux is called last.',
  'base-fs: root-image boot-files initcpio overlay iso-mounts syslinux',
  '# The root-image routine is always executed first. ',
  '# It only downloads and installs all packages into the $WORKDIR, giving you a basic system to use as a base.',
  'root-image: "$(WORKDIR)"/root-image/.arch-chroot',
  '"$(WORKDIR)"/root-image/.arch-chroot:',
  'root-image:',
  '	mkarchiso -v -p $(PACKAGES) create "$(WORKDIR)"',
  '# Rule for make /boot',
  'boot-files: root-image',
  '	cp -r "$(WORKDIR)"/root-image/boot "$(WORKDIR)"/iso/',
  '	cp -r boot-files/* "$(WORKDIR)"/iso/boot/',
  '# Rules for initcpio images',
  'initcpio: "$(WORKDIR)"/iso/boot/myarch.img',
  '"$(WORKDIR)"/iso/boot/myarch.img: mkinitcpio.conf "$(WORKDIR)"/root-image/.arch-chroot',
  '	mkdir -p "$(WORKDIR)"/iso/boot',
  '	mkinitcpio -c ./mkinitcpio.conf -b "$(WORKDIR)"/root-image -k $(shell grep ^ALL_kver $(kver_FILE) | cut -d= -f2) -g $@',
  '# See: Overlay',
  'overlay:',
  '	mkdir -p "$(WORKDIR)"/overlay/etc/pacman.d',
  '	cp -r overlay "$(WORKDIR)"/',
  '	wget -O "$(WORKDIR)"/overlay/etc/pacman.d/mirrorlist http://www.archlinux.org/mirrorlist/all/',
  '	sed -i "s/#Server/Server/g" "$(WORKDIR)"/overlay/etc/pacman.d/mirrorlist',
  '# Rule to process isomounts file.',
  'iso-mounts: "$(WORKDIR)"/isomounts',
  '"$(WORKDIR)"/isomounts: isomounts root-image',
  '	sed "s|@ARCH@|$(ARCH)|g" isomounts > $@',
  '# This routine is always executed just before generating the actual image. ',
  'syslinux: root-image',
  '	mkdir -p $(WORKDIR)/iso/boot/syslinux',
  '	cp $(WORKDIR)/root-image/usr/lib/syslinux/*.c32 $(WORKDIR)/iso/boot/syslinux/',
  '	cp $(WORKDIR)/root-image/usr/lib/syslinux/isolinux.bin $(WORKDIR)/iso/boot/syslinux/',
  '# In case "make clean" is called, the following routine gets rid of all files created by this Makefile.',
  'clean:',
  '	rm -rf "$(WORKDIR)" "$(FULLNAME)".img "$(FULLNAME)".iso',
  '.PHONY: all myarch',
  '.PHONY: base-fs',
  '.PHONY: root-image boot-files initcpio overlay iso-mounts',
  '.PHONY: syslinux',
  '.PHONY: clean'
].join("\n"),
isomounts_tmpl = [
  'overlay.sqfs @ARCH@ / squashfs',
  'root-image.sqfs @ARCH@ / squashfs',
  '' // this is needed to avoid a kernel panic!
].join("\n"),
syslinux_cfg_tmpl = [
  'prompt 1',
  'timeout 0',
  'display myarch.msg',
  'DEFAULT myarch',
  '',
  'LABEL myarch',
  'KERNEL /boot/vmlinuz26',
  'APPEND initrd=/boot/myarch.img archisolabel=XXX locale=en_US.UTF-8',
  ''
].join("\n"),
message_tmpl = [
  'vousssoir (plural voussoirs)',
  '  1. (architecture) One of a series of wedge-shaped bricks forming an arch',
  '      or a vault.',
  ''
].join("\n"),
fstab_tmpl = [
  'aufs                   /             aufs      noauto              0      0',
  'none                   /dev/pts      devpts    defaults            0      0',
  'none                   /dev/shm      tmpfs     defaults            0      0',
  ''
].join("\n"),
mkinitcpio_tmpl = [
  'HOOKS="base udev archiso pata scsi sata usb fw filesystems usbinput"',
  ''
].join("\n"),
packages_tmpl = [
  'aufs2',
  'aufs2-util',
  'base',
  'bash',
  'coreutils',
  'cpio',
  'dhcpcd',
  'dnsutils',
  'file',
  'fuse',
  'kernel26',
  'syslinux',
  'nano',
  ''
].join("\n"),
dir_perms = parseInt('755', 8),
server = http.createServer(function (request, response) {
  if (request.method !== 'POST') {
    response.writeHead(405, {
      Allow: 'POST',
      'Content-Type': 'text/plain'
    });
    response.end([
      "You don't seem to get it. You're the deliveryman. Deliverymen POST",
      "things, they don't", request.method, "them!\n"
    ].join(' '));
  } else {
    var post_data = "";
    request.on('data', function (chunk) {
      post_data += chunk;
    });
    request.on('end', function () {
      var user_data = JSON.parse(post_data),
      date = new Date(),
      working_dir = [user_data.name, '-', date.getTime()].join('');

      response.writeHead(202);
      sys.puts(JSON.stringify(user_data));
      response.end();
      fs.mkdir(working_dir, dir_perms, function (err) {
        var makefile = path.join(working_dir, 'Makefile');
        fs.writeFile(makefile, makefile_templ, function (err) {
          var mkinitcpio = path.join(working_dir, 'mkinitcpio.conf');
          fs.writeFile(mkinitcpio, mkinitcpio_tmpl, function (err) {
            var packages = path.join(working_dir, 'packages.list');
            fs.writeFile(packages, packages_tmpl, function (err) {
              var isomounts = path.join(working_dir, 'isomounts');
              fs.writeFile(isomounts, isomounts_tmpl, function (err) {
                var bootfiles = path.join(working_dir, 'boot-files');
                fs.mkdir(bootfiles, dir_perms, function (err) {
                  var syslinux = path.join(bootfiles, 'syslinux');
                  fs.mkdir(syslinux, dir_perms, function (err) {
                    var syslinux_cfg = path.join(syslinux, 'syslinux.cfg');
                    fs.writeFile(syslinux_cfg, syslinux_cfg_tmpl, function (err) {
                      var message = path.join(syslinux, 'myarch.msg');
                      fs.writeFile(message, message_tmpl, function (err) {
                        var overlay = path.join(working_dir, 'overlay');
                        fs.mkdir(overlay, dir_perms, function (err) {
                          var etc = path.join(overlay, 'etc');
                          fs.mkdir(etc, dir_perms, function (err) {
                            var fstab = path.join(etc, 'fstab');
                            fs.writeFile(fstab, fstab_tmpl, function (err) {
                              var env = process.env, maker, i;
                              for (i in env) {
                                if (env.hasOwnProperty(i)) {
                                  sys.puts('env[' + i + ']: ' + env[i]);
                                }
                              }
                              env.cwd = fs.realpathSync(working_dir);
                              env.SHELL = '/bin/bash';
                              env['_'] = '/usr/bin/env';
                              maker = child_process.spawn(
                                'make', ['all'], env
                              );
                              maker.on('exit', function (code) {
                                sys.puts(user_data.name + ' finished with code: ' + code);
                              });
                              maker.stdout.on('data', function (data) {
                                sys.puts(user_data.name + ' ' + data);
                              });
                              maker.stderr.on('data', function (data) {
                                sys.puts(user_data.name + ' ERROR:: ' + data);
                              });
                            });
                          });
                        });
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  }
});

server.listen('8080');<commit_msg>take package list from the user<commit_after>/*jslint indent:2, browser:true, devel:true, maxlen:80 nomen:false */
/*global $ require __dirname process */
/* Copyright (c) 2010 Jeremiah Dodds <jeremiah.dodds@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var sys = require('sys'),
url = require('url'),
fs = require('fs'),
http = require('http'),
path = require('path'),
events = require('events'),
child_process = require('child_process'),
makefile_templ = [
  '#### Change these settings to modify how this ISO is built.',
  '#  The directory that you\'ll be using for the actual build process.',
  'WORKDIR=work',
  '#  A list of packages to install, either space separated in a string or line separated in a file. Can include groups.',
  'PACKAGES="$(shell cat packages.list) syslinux"',
  '# The name of our ISO. Does not specify the architecture!',
  'NAME=myarch',
  '# Version will be appended to the ISO.',
  'VER=1.00',
  '# Kernel version. You\'ll need this. Don\'t change it.',
  'kver_FILE=$(WORKDIR)/root-image/etc/mkinitcpio.d/kernel26.kver',
  '# Architecture will also be appended to the ISO name.',
  'ARCH?=x86_64',
  '# Current working directory',
  'PWD:=$(shell pwd)',
  '# This is going to be the full name the final iso/img will carry',
  'FULLNAME="$(PWD)"/$(NAME)-$(VER)-$(ARCH)',
  '# Default make instruction to build everything.',
  'all: myarch',
  '# The following will first run the base-fs routine before creating the final iso image.',
  'myarch: base-fs',
  '	mkarchiso -v -p syslinux iso "$(WORKDIR)" "$(FULLNAME)".iso',
  '# This is the main rule for make the working filesystem. It will run routines from left to right. ',
  '# Thus, root-image is called first and syslinux is called last.',
  'base-fs: root-image boot-files initcpio overlay iso-mounts syslinux',
  '# The root-image routine is always executed first. ',
  '# It only downloads and installs all packages into the $WORKDIR, giving you a basic system to use as a base.',
  'root-image: "$(WORKDIR)"/root-image/.arch-chroot',
  '"$(WORKDIR)"/root-image/.arch-chroot:',
  'root-image:',
  '	mkarchiso -v -p $(PACKAGES) create "$(WORKDIR)"',
  '# Rule for make /boot',
  'boot-files: root-image',
  '	cp -r "$(WORKDIR)"/root-image/boot "$(WORKDIR)"/iso/',
  '	cp -r boot-files/* "$(WORKDIR)"/iso/boot/',
  '# Rules for initcpio images',
  'initcpio: "$(WORKDIR)"/iso/boot/myarch.img',
  '"$(WORKDIR)"/iso/boot/myarch.img: mkinitcpio.conf "$(WORKDIR)"/root-image/.arch-chroot',
  '	mkdir -p "$(WORKDIR)"/iso/boot',
  '	mkinitcpio -c ./mkinitcpio.conf -b "$(WORKDIR)"/root-image -k $(shell grep ^ALL_kver $(kver_FILE) | cut -d= -f2) -g $@',
  '# See: Overlay',
  'overlay:',
  '	mkdir -p "$(WORKDIR)"/overlay/etc/pacman.d',
  '	cp -r overlay "$(WORKDIR)"/',
  '	wget -O "$(WORKDIR)"/overlay/etc/pacman.d/mirrorlist http://www.archlinux.org/mirrorlist/all/',
  '	sed -i "s/#Server/Server/g" "$(WORKDIR)"/overlay/etc/pacman.d/mirrorlist',
  '# Rule to process isomounts file.',
  'iso-mounts: "$(WORKDIR)"/isomounts',
  '"$(WORKDIR)"/isomounts: isomounts root-image',
  '	sed "s|@ARCH@|$(ARCH)|g" isomounts > $@',
  '# This routine is always executed just before generating the actual image. ',
  'syslinux: root-image',
  '	mkdir -p $(WORKDIR)/iso/boot/syslinux',
  '	cp $(WORKDIR)/root-image/usr/lib/syslinux/*.c32 $(WORKDIR)/iso/boot/syslinux/',
  '	cp $(WORKDIR)/root-image/usr/lib/syslinux/isolinux.bin $(WORKDIR)/iso/boot/syslinux/',
  '# In case "make clean" is called, the following routine gets rid of all files created by this Makefile.',
  'clean:',
  '	rm -rf "$(WORKDIR)" "$(FULLNAME)".img "$(FULLNAME)".iso',
  '.PHONY: all myarch',
  '.PHONY: base-fs',
  '.PHONY: root-image boot-files initcpio overlay iso-mounts',
  '.PHONY: syslinux',
  '.PHONY: clean'
].join("\n"),
isomounts_tmpl = [
  'overlay.sqfs @ARCH@ / squashfs',
  'root-image.sqfs @ARCH@ / squashfs',
  '' // this is needed to avoid a kernel panic!
].join("\n"),
syslinux_cfg_tmpl = [
  'prompt 1',
  'timeout 0',
  'display myarch.msg',
  'DEFAULT myarch',
  '',
  'LABEL myarch',
  'KERNEL /boot/vmlinuz26',
  'APPEND initrd=/boot/myarch.img archisolabel=XXX locale=en_US.UTF-8',
  ''
].join("\n"),
message_tmpl = [
  'vousssoir (plural voussoirs)',
  '  1. (architecture) One of a series of wedge-shaped bricks forming an arch',
  '      or a vault.',
  ''
].join("\n"),
fstab_tmpl = [
  'aufs                   /             aufs      noauto              0      0',
  'none                   /dev/pts      devpts    defaults            0      0',
  'none                   /dev/shm      tmpfs     defaults            0      0',
  ''
].join("\n"),
mkinitcpio_tmpl = [
  'HOOKS="base udev archiso pata scsi sata usb fw filesystems usbinput"',
  ''
].join("\n"),
dir_perms = parseInt('755', 8),
server = http.createServer(function (request, response) {
  if (request.method !== 'POST') {
    response.writeHead(405, {
      Allow: 'POST',
      'Content-Type': 'text/plain'
    });
    response.end([
      "You don't seem to get it. You're the deliveryman. Deliverymen POST",
      "things, they don't", request.method, "them!\n"
    ].join(' '));
  } else {
    var post_data = "";
    request.on('data', function (chunk) {
      post_data += chunk;
    });
    request.on('end', function () {
      var user_data = JSON.parse(post_data),
      date = new Date(),
      working_dir = [user_data.name, '-', date.getTime()].join('');
      response.writeHead(202);
      sys.puts(JSON.stringify(user_data));
      response.end();
      fs.mkdir(working_dir, dir_perms, function (err) {
        var makefile = path.join(working_dir, 'Makefile');
        fs.writeFile(makefile, makefile_templ, function (err) {
          var mkinitcpio = path.join(working_dir, 'mkinitcpio.conf');
          fs.writeFile(mkinitcpio, mkinitcpio_tmpl, function (err) {
            var packages = path.join(working_dir, 'packages.list');
            fs.writeFile(packages, user_data.packages.join("\n"), function (err) {
              var isomounts = path.join(working_dir, 'isomounts');
              fs.writeFile(isomounts, isomounts_tmpl, function (err) {
                var bootfiles = path.join(working_dir, 'boot-files');
                fs.mkdir(bootfiles, dir_perms, function (err) {
                  var syslinux = path.join(bootfiles, 'syslinux');
                  fs.mkdir(syslinux, dir_perms, function (err) {
                    var syslinux_cfg = path.join(syslinux, 'syslinux.cfg');
                    fs.writeFile(syslinux_cfg, syslinux_cfg_tmpl, function (err) {
                      var message = path.join(syslinux, 'myarch.msg');
                      fs.writeFile(message, message_tmpl, function (err) {
                        var overlay = path.join(working_dir, 'overlay');
                        fs.mkdir(overlay, dir_perms, function (err) {
                          var etc = path.join(overlay, 'etc');
                          fs.mkdir(etc, dir_perms, function (err) {
                            var fstab = path.join(etc, 'fstab');
                            fs.writeFile(fstab, fstab_tmpl, function (err) {
                              var env = process.env, maker, i;
                              for (i in env) {
                                if (env.hasOwnProperty(i)) {
                                  sys.puts('env[' + i + ']: ' + env[i]);
                                }
                              }
                              env.cwd = fs.realpathSync(working_dir);
                              env.SHELL = '/bin/bash';
                              env['_'] = '/usr/bin/env';
                              maker = child_process.spawn(
                                'make', ['all'], env
                              );
                              maker.on('exit', function (code) {
                                sys.puts(user_data.name + ' finished with code: ' + code);
                              });
                              maker.stdout.on('data', function (data) {
                                sys.puts(user_data.name + ' ' + data);
                              });
                              maker.stderr.on('data', function (data) {
                                sys.puts(user_data.name + ' ERROR:: ' + data);
                              });
                            });
                          });
                        });
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  }
});

server.listen('8080');<|endoftext|>