<commit_before>const fs = require('../../core/fs.js');
const utils = require('../../utils/utils.js');
const namehash = require('eth-ens-namehash');
const async = require('async');
const embarkJsUtils = require('embarkjs').Utils;
const reverseAddrSuffix = '.addr.reverse';

class ENS {
  constructor(embark, _options) {
    this.env = embark.env;
    this.logger = embark.logger;
    this.events = embark.events;
    this.namesConfig = embark.config.namesystemConfig;
    this.registration = this.namesConfig.register || {};
    this.embark = embark;

    if (this.namesConfig === {} ||
      this.namesConfig.enabled !== true ||
      this.namesConfig.available_providers.indexOf('ens') < 0) {
      return;
    }
    this.doSetENSProvider = this.namesConfig.provider === 'ens';

    this.addENSToEmbarkJS();
    this.configureContracts();
    this.registerEvents();
  }

  registerEvents() {
    this.embark.registerActionForEvent("contracts:deploy:afterAll", this.setProviderAndRegisterDomains.bind(this));

    this.events.setCommandHandler("storage:ens:associate", this.associateStorageToEns.bind(this));
  }

  setProviderAndRegisterDomains(cb) {
    const self = this;
    async.parallel([
      function getENSRegistry(paraCb) {
        self.events.request('contracts:contract', "ENSRegistry", (contract) => {
          paraCb(null, contract);
        });
      },
      function getRegistrar(paraCb) {
        self.events.request('contracts:contract', "FIFSRegistrar", (contract) => {
          paraCb(null, contract);
        });
      },
      function getResolver(paraCb) {
        self.events.request('contracts:contract', "Resolver", (contract) => {
          paraCb(null, contract);
        });
      }
    ], (err, results) => {
      // result[0] => ENSRegistry; result[1] => FIFSRegistrar; result[2] => FIFSRegistrar
      let config = {
        env: self.env,
        registration: self.registration,
        registryAbi: results[0].abiDefinition,
        registryAddress: results[0].deployedAddress,
        registrarAbi: results[1].abiDefinition,
        registrarAddress: results[1].deployedAddress,
        resolverAbi: results[2].abiDefinition,
        resolverAddress: results[2].deployedAddress
      };

      if (self.doSetENSProvider) {
        self.addSetProvider(config);
      }

      if (!self.env === 'development' || !self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) {
        return cb();
      }
      self.registerConfigDomains(config, cb);
    });
  }

  associateStorageToEns(options, cb) {
    const self = this;
    // Code inspired by https://github.com/monkybrain/ipfs-to-ens
    const {name, storageHash} = options;

    if (!utils.isValidEthDomain(name)) {
      return cb('Invalid domain name ' + name);
    }

    let hashedName = namehash.hash(name);
    let contentHash;
    try {
      contentHash = utils.hashTo32ByteHexString(storageHash);
    } catch (e) {
      return cb('Invalid IPFS hash');
    }

    // Set content
    async.waterfall([
      function getRegistryABI(next) {
        self.events.request('contracts:contract', "ENSRegistry", (contract) => {
          next(null, contract);
        });
      },
      function createRegistryContract(contract, next) {
        self.events.request("blockchain:contract:create",
          {abi: contract.abiDefinition, address: contract.deployedAddress},
          (resolver) => {
            next(null, resolver);
          });
      },
      function getResolverForName(registry, next) {
        registry.methods.resolver(hashedName).call((err, resolverAddress) => {
          if (err) {
            return cb(err);
          }
          if (resolverAddress === '0x0000000000000000000000000000000000000000') {
            return cb('Name not yet registered');
          }
          next(null, resolverAddress);
        });
      },
      function getResolverABI(resolverAddress, next) {
        self.events.request('contracts:contract', "Resolver", (contract) => {
          next(null, resolverAddress, contract);
        });
      },
      function createResolverContract(resolverAddress, contract, next) {
        self.events.request("blockchain:contract:create",
          {abi: contract.abiDefinition, address: resolverAddress},
          (resolver) => {
            next(null, resolver);
          });
      },
      function getDefaultAccount(resolver, next) {
        self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
          next(null, resolver, defaultAccount);
        });
      },
      function setContent(resolver, defaultAccount, next) {
        resolver.methods.setContent(hashedName, contentHash).send({from: defaultAccount}).then((transaction) => {
          if (transaction.status !== "0x1" && transaction.status !== "0x01" && transaction.status !== true) {
            return next('Association failed. Status: ' + transaction.status);
          }
          next();
        }).catch(next);
      }
    ], cb);
  }

  registerConfigDomains(config, cb) {
    const self = this;
    const register = require('./register');
    const secureSend = embarkJsUtils.secureSend;
    self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
      async.parallel([
        function createRegistryContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.registryAbi, address: config.registryAddress},
            (registry) => {
              paraCb(null, registry);
            });
        },
        function createRegistrarContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.registrarAbi, address: config.registrarAddress},
            (registrar) => {
              paraCb(null, registrar);
            });
        },
        function createResolverContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.resolverAbi, address: config.resolverAddress},
            (resolver) => {
              paraCb(null, resolver);
            });
        }
      ], function (err, contracts) {
        if (err) {
          return cb(err);
        }
        const [ens, registrar, resolver] = contracts;

        async.each(Object.keys(self.registration.subdomains), (subDomainName, eachCb) => {
          const address = self.registration.subdomains[subDomainName];
          const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix);
          register(ens, registrar, resolver, defaultAccount, subDomainName, self.registration.rootDomain,
            reverseNode, address, self.logger, secureSend, eachCb);
        }, cb);

      });
    });
  }

  addENSToEmbarkJS() {
    const self = this;

    // get namehash, import it into file
    self.events.request("version:get:eth-ens-namehash", function (EnsNamehashVersion) {
      let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"];
      if (EnsNamehashVersion !== currentEnsNamehashVersion) {
        self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function (err, location) {
          self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location));
        });
      }
    });

    let code = fs.readFileSync(utils.joinPath(__dirname, 'register.js')).toString();
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  configureContracts() {
    const config = {
      "default": {
        "gas": "auto",
        "contracts": {
          "ENS": {
            "deploy": false,
            "silent": true
          }
        }
      },
      "development": {
        "contracts": {
          "ENSRegistry": {
            "deploy": true,
            "silent": true,
            "args": []
          },
          "Resolver": {
            "deploy": true,
            "silent": true,
            "args": ["$ENSRegistry"]
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "ropsten": {
        "contracts": {
          "ENSRegistry": {
            "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "rinkeby": {
        "contracts": {
          "ENSRegistry": {
            "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "livenet": {
        "contracts": {
          "ENSRegistry": {
            "address": "0x314159265dd8dbb310642f98f50c066173c1259b",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      }
    };

    if (this.registration && this.registration.rootDomain) {
      // Register root domain if it is defined
      const rootNode = namehash.hash(this.registration.rootDomain);
      config.development.contracts['FIFSRegistrar'] = {
        "deploy": true,
        "silent": true,
        "args": ["$ENSRegistry", rootNode],
        "onDeploy": [
          `ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
              ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
              var reverseNode = web3.utils.soliditySha3(web3.eth.defaultAccount.toLowerCase().substr(2) + '${reverseAddrSuffix}');
              ENSRegistry.methods.setResolver(reverseNode, "$Resolver").send();
              Resolver.methods.setAddr('${rootNode}', web3.eth.defaultAccount).send();
              Resolver.methods.setName(reverseNode, '${this.registration.rootDomain}').send();
              })`
        ]
      };
    }

    this.embark.registerContractConfiguration(config);

    this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/ENSRegistry.sol'));
    this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/FIFSRegistrar.sol'));
    this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/Resolver.sol'));
  }

  addSetProvider(config) {

    let code = "\nEmbarkJS.Names.setProvider('ens'," + JSON.stringify(config) + ");";

    let shouldInit = (namesConfig) => {
      return (namesConfig.provider === 'ens' && namesConfig.enabled === true);
    };

    this.embark.addProviderInit('names', code, shouldInit);
  }
}

module.exports = ENS;
<commit_msg>disable preregister in privatenet and fix conditions<commit_after>const fs = require('../../core/fs.js');
const utils = require('../../utils/utils.js');
const namehash = require('eth-ens-namehash');
const async = require('async');
const embarkJsUtils = require('embarkjs').Utils;
const reverseAddrSuffix = '.addr.reverse';

class ENS {
  constructor(embark, _options) {
    this.env = embark.env;
    this.isDev = embark.config.blockchainConfig.isDev;
    this.logger = embark.logger;
    this.events = embark.events;
    this.namesConfig = embark.config.namesystemConfig;
    this.registration = this.namesConfig.register || {};
    this.embark = embark;

    if (this.namesConfig === {} ||
      this.namesConfig.enabled !== true ||
      this.namesConfig.available_providers.indexOf('ens') < 0) {
      return;
    }
    this.doSetENSProvider = this.namesConfig.provider === 'ens';

    if (this.env === 'privatenet') {
      this.logger.warn(__('ENS is disabled in privatenet'));
      this.logger.info(__('To use ENS, use development, one of the testnets or mainnet'));
      return;
    }

    this.addENSToEmbarkJS();
    this.configureContracts();
    this.registerEvents();
  }

  registerEvents() {
    this.embark.registerActionForEvent("contracts:deploy:afterAll", this.setProviderAndRegisterDomains.bind(this));

    this.events.setCommandHandler("storage:ens:associate", this.associateStorageToEns.bind(this));
  }

  setProviderAndRegisterDomains(cb) {
    const self = this;
    async.parallel([
      function getENSRegistry(paraCb) {
        self.events.request('contracts:contract', "ENSRegistry", (contract) => {
          paraCb(null, contract);
        });
      },
      function getRegistrar(paraCb) {
        self.events.request('contracts:contract', "FIFSRegistrar", (contract) => {
          paraCb(null, contract);
        });
      },
      function getResolver(paraCb) {
        self.events.request('contracts:contract', "Resolver", (contract) => {
          paraCb(null, contract);
        });
      }
    ], (err, results) => {
      // result[0] => ENSRegistry; result[1] => FIFSRegistrar; result[2] => FIFSRegistrar
      let config = {
        env: self.env,
        registration: self.registration,
        registryAbi: results[0].abiDefinition,
        registryAddress: results[0].deployedAddress,
        registrarAbi: results[1].abiDefinition,
        registrarAddress: results[1].deployedAddress,
        resolverAbi: results[2].abiDefinition,
        resolverAddress: results[2].deployedAddress
      };

      if (self.doSetENSProvider) {
        self.addSetProvider(config);
      }

      if (!self.isDev || !self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) {
        return cb();
      }
      self.registerConfigDomains(config, cb);
    });
  }

  associateStorageToEns(options, cb) {
    const self = this;
    // Code inspired by https://github.com/monkybrain/ipfs-to-ens
    const {name, storageHash} = options;

    if (!utils.isValidEthDomain(name)) {
      return cb('Invalid domain name ' + name);
    }

    let hashedName = namehash.hash(name);
    let contentHash;
    try {
      contentHash = utils.hashTo32ByteHexString(storageHash);
    } catch (e) {
      return cb('Invalid IPFS hash');
    }

    // Set content
    async.waterfall([
      function getRegistryABI(next) {
        self.events.request('contracts:contract', "ENSRegistry", (contract) => {
          next(null, contract);
        });
      },
      function createRegistryContract(contract, next) {
        self.events.request("blockchain:contract:create",
          {abi: contract.abiDefinition, address: contract.deployedAddress},
          (resolver) => {
            next(null, resolver);
          });
      },
      function getResolverForName(registry, next) {
        registry.methods.resolver(hashedName).call((err, resolverAddress) => {
          if (err) {
            return cb(err);
          }
          if (resolverAddress === '0x0000000000000000000000000000000000000000') {
            return cb('Name not yet registered');
          }
          next(null, resolverAddress);
        });
      },
      function getResolverABI(resolverAddress, next) {
        self.events.request('contracts:contract', "Resolver", (contract) => {
          next(null, resolverAddress, contract);
        });
      },
      function createResolverContract(resolverAddress, contract, next) {
        self.events.request("blockchain:contract:create",
          {abi: contract.abiDefinition, address: resolverAddress},
          (resolver) => {
            next(null, resolver);
          });
      },
      function getDefaultAccount(resolver, next) {
        self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
          next(null, resolver, defaultAccount);
        });
      },
      function setContent(resolver, defaultAccount, next) {
        resolver.methods.setContent(hashedName, contentHash).send({from: defaultAccount}).then((transaction) => {
          if (transaction.status !== "0x1" && transaction.status !== "0x01" && transaction.status !== true) {
            return next('Association failed. Status: ' + transaction.status);
          }
          next();
        }).catch(next);
      }
    ], cb);
  }

  registerConfigDomains(config, cb) {
    const self = this;
    const register = require('./register');
    const secureSend = embarkJsUtils.secureSend;
    self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
      async.parallel([
        function createRegistryContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.registryAbi, address: config.registryAddress},
            (registry) => {
              paraCb(null, registry);
            });
        },
        function createRegistrarContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.registrarAbi, address: config.registrarAddress},
            (registrar) => {
              paraCb(null, registrar);
            });
        },
        function createResolverContract(paraCb) {
          self.events.request("blockchain:contract:create",
            {abi: config.resolverAbi, address: config.resolverAddress},
            (resolver) => {
              paraCb(null, resolver);
            });
        }
      ], function (err, contracts) {
        if (err) {
          return cb(err);
        }
        const [ens, registrar, resolver] = contracts;

        async.each(Object.keys(self.registration.subdomains), (subDomainName, eachCb) => {
          const address = self.registration.subdomains[subDomainName];
          const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix);
          register(ens, registrar, resolver, defaultAccount, subDomainName, self.registration.rootDomain,
            reverseNode, address, self.logger, secureSend, eachCb);
        }, cb);

      });
    });
  }

  addENSToEmbarkJS() {
    const self = this;

    // get namehash, import it into file
    self.events.request("version:get:eth-ens-namehash", function (EnsNamehashVersion) {
      let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"];
      if (EnsNamehashVersion !== currentEnsNamehashVersion) {
        self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function (err, location) {
          self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location));
        });
      }
    });

    let code = fs.readFileSync(utils.joinPath(__dirname, 'register.js')).toString();
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  configureContracts() {
    const config = {
      "default": {
        "gas": "auto",
        "contracts": {
          "ENS": {
            "deploy": false,
            "silent": true
          }
        }
      },
      "development": {
        "contracts": {
          "ENSRegistry": {
            "deploy": true,
            "silent": true,
            "args": []
          },
          "Resolver": {
            "deploy": true,
            "silent": true,
            "args": ["$ENSRegistry"]
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "ropsten": {
        "contracts": {
          "ENSRegistry": {
            "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "rinkeby": {
        "contracts": {
          "ENSRegistry": {
            "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      },
      "livenet": {
        "contracts": {
          "ENSRegistry": {
            "address": "0x314159265dd8dbb310642f98f50c066173c1259b",
            "silent": true
          },
          "Resolver": {
            "deploy": false
          },
          "FIFSRegistrar": {
            "deploy": false
          }
        }
      }
    };
    config.testnet  = config.ropsten;

    if (this.registration && this.registration.rootDomain) {
      // Register root domain if it is defined
      const rootNode = namehash.hash(this.registration.rootDomain);
      config.development.contracts['FIFSRegistrar'] = {
        "deploy": true,
        "silent": true,
        "args": ["$ENSRegistry", rootNode],
        "onDeploy": [
          `ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
              ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
              var reverseNode = web3.utils.soliditySha3(web3.eth.defaultAccount.toLowerCase().substr(2) + '${reverseAddrSuffix}');
              ENSRegistry.methods.setResolver(reverseNode, "$Resolver").send();
              Resolver.methods.setAddr('${rootNode}', web3.eth.defaultAccount).send();
              Resolver.methods.setName(reverseNode, '${this.registration.rootDomain}').send();
              })`
        ]
      };
    }
    this.embark.registerContractConfiguration(config);

    if (this.isDev) {
      this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/ENSRegistry.sol'));
      this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/FIFSRegistrar.sol'));
      this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/Resolver.sol'));
    }
  }

  addSetProvider(config) {

    let code = "\nEmbarkJS.Names.setProvider('ens'," + JSON.stringify(config) + ");";

    let shouldInit = (namesConfig) => {
      return (namesConfig.provider === 'ens' && namesConfig.enabled === true);
    };

    this.embark.addProviderInit('names', code, shouldInit);
  }
}

module.exports = ENS;
<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Chris Umbel

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 ambiguous = [
    'bison', 'bream', 'carp', 'chassis', 'cod', 'corps', 'debris', 'deer',
    'diabetes', 'equipment', 'elk', 'fish', 'flounder', 'gallows', 'graffiti',
    'headquarters', 'herpes', 'highjinks', 'homework', 'information',
    'mackerel', 'mews', 'money', 'news', 'rice', 'rabies', 'salmon', 'series',
    'sheep', 'shrimp', 'species', 'swine', 'trout', 'tuna', 'whiting', 'wildebeest'
];

function addForm(singularTable, pluralTable, singular, plural) {
    pluralTable[singular] = plural;
    singularTable[plural] = singular;
}

function FormSet() {
    this.regularForms = [];
    this.irregularForms = {};
}

function addIrregular(singular, plural) {
    addForm(singularForms.irregularForms, pluralForms.irregularForms, singular, plural);
}

(function() {
    this.singularForms = new FormSet();
    this.pluralForms = new FormSet();

    addIrregular("child", "children");
    addIrregular("man", "men");
    addIrregular("person", "people");
    addIrregular("sex", "sexes");
    addIrregular("mouse", "mice");

    // see if it is possible to unify the creation of both the singular and
    // plural regexes or maybe even just have one list. with a complete list
    // of rules it may only be possible for some regular forms, but worth a shot
    pluralForms.regularForms.push([/(octop|vir)us$/i, '$1i']);
    pluralForms.regularForms.push([/(buffal|tomat)o$/i, '$1oes']);
    pluralForms.regularForms.push([/(sis)$/i, 'ses']);
    pluralForms.regularForms.push([/(matr|vert|ind)(ix|ex)$/i, '$1ices']);
    pluralForms.regularForms.push([/(x|ch|ss|sh|s|z)$/i, '$1es']);
    pluralForms.regularForms.push([/(.*)/i, '$1s']);

    singularForms.regularForms.push([/(octop|vir)(i)$/i, '$1us']);
    singularForms.regularForms.push([/(buffal|tomat)(oes)$/i, '$1o']);
    singularForms.regularForms.push([/(analy|naly|synop|parenthe|diagno|the)ses$/i, '$1sis']);
    singularForms.regularForms.push([/(vert|ind)(ices)$/i, '$1ex']);
    // our pluralizer won''t cause this form of appendix (appendicies)
    // but we should handle it
    singularForms.regularForms.push([/(matr|append)(ices)$/i, '$1ix']);
    singularForms.regularForms.push([/(x|ch|ss|sh|s|z)es$/i, '$1']);
    singularForms.regularForms.push([/s$/i, '']);
})();

var Inflector = function() {
    this.ize = function(token, formSet) {
        if(ambiguous.indexOf(token) > -1)
            return token;

        if(formSet.irregularForms[token.toLowerCase()])
            return formSet.irregularForms[token];

        for(i = 0; i < formSet.regularForms.length; i++) {
            form = formSet.regularForms[i];

            if(token.match(form[0]))
                return token.replace(form[0], form[1]);
        }

        return token;
    }

    this.pluralize = function (token) {
        return this.ize(token, pluralForms);
    };

    this.singularize = function(token) {
        return this.ize(token, singularForms);
    };

    this.attach = function() {
        var inflector = this;

        String.prototype.singularize = function() {
            return inflector.singularize(this);
        }

        String.prototype.pluralize = function() {
            return inflector.pluralize(this);
        }
    };
};

module.exports = Inflector;
<commit_msg>extracted some inflector instance methods<commit_after>/*
Copyright (c) 2011, Chris Umbel

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 ambiguous = [
    'bison', 'bream', 'carp', 'chassis', 'cod', 'corps', 'debris', 'deer',
    'diabetes', 'equipment', 'elk', 'fish', 'flounder', 'gallows', 'graffiti',
    'headquarters', 'herpes', 'highjinks', 'homework', 'information',
    'mackerel', 'mews', 'money', 'news', 'rice', 'rabies', 'salmon', 'series',
    'sheep', 'shrimp', 'species', 'swine', 'trout', 'tuna', 'whiting', 'wildebeest'
];

function addForm(singularTable, pluralTable, singular, plural) {
    pluralTable[singular] = plural;
    singularTable[plural] = singular;
}

function FormSet() {
    this.regularForms = [];
    this.irregularForms = {};
}

function addIrregular(singular, plural) {
    addForm(singularForms.irregularForms, pluralForms.irregularForms, singular, plural);
}

(function() {
    this.singularForms = new FormSet();
    this.pluralForms = new FormSet();

    addIrregular("child", "children");
    addIrregular("man", "men");
    addIrregular("person", "people");
    addIrregular("sex", "sexes");
    addIrregular("mouse", "mice");

    // see if it is possible to unify the creation of both the singular and
    // plural regexes or maybe even just have one list. with a complete list
    // of rules it may only be possible for some regular forms, but worth a shot
    pluralForms.regularForms.push([/(octop|vir)us$/i, '$1i']);
    pluralForms.regularForms.push([/(buffal|tomat)o$/i, '$1oes']);
    pluralForms.regularForms.push([/(sis)$/i, 'ses']);
    pluralForms.regularForms.push([/(matr|vert|ind)(ix|ex)$/i, '$1ices']);
    pluralForms.regularForms.push([/(x|ch|ss|sh|s|z)$/i, '$1es']);
    pluralForms.regularForms.push([/(.*)/i, '$1s']);

    singularForms.regularForms.push([/(octop|vir)(i)$/i, '$1us']);
    singularForms.regularForms.push([/(buffal|tomat)(oes)$/i, '$1o']);
    singularForms.regularForms.push([/(analy|naly|synop|parenthe|diagno|the)ses$/i, '$1sis']);
    singularForms.regularForms.push([/(vert|ind)(ices)$/i, '$1ex']);
    // our pluralizer won''t cause this form of appendix (appendicies)
    // but we should handle it
    singularForms.regularForms.push([/(matr|append)(ices)$/i, '$1ix']);
    singularForms.regularForms.push([/(x|ch|ss|sh|s|z)es$/i, '$1']);
    singularForms.regularForms.push([/s$/i, '']);
})();

function ize(token, formSet) {
    if(ambiguous.indexOf(token) > -1)
        return token;

    if(formSet.irregularForms[token.toLowerCase()])
        return formSet.irregularForms[token];

    for(i = 0; i < formSet.regularForms.length; i++) {
        form = formSet.regularForms[i];

        if(token.match(form[0]))
            return token.replace(form[0], form[1]);
    }

    return token;
}

function attach() {
    var inflector = this;

    String.prototype.singularize = function() {
        return inflector.singularize(this);
    }

    String.prototype.pluralize = function() {
        return inflector.pluralize(this);
    }
}

var Inflector = function() {
    this.ize = ize;

    this.pluralize = function (token) {
        return this.ize(token, pluralForms);
    };

    this.singularize = function(token) {
        return this.ize(token, singularForms);
    };

    this.attach = attach;
};

module.exports = Inflector;
<|endoftext|>


<commit_before>const merge = require('webpack-merge');
const validateOptions = require('./options-validator');

module.exports = (pattern, options) => {
    // Make the first argument optional, just passing a configuration
    // object should result in the default pattern being used
    if ( typeof options === 'undefined' && (typeof pattern === 'object' && pattern !== null) ) {
        options = pattern;
        pattern = '**/*.svg'
    }

    // Validate input
    validateOptions(pattern, options);

    // Format output
    const output = merge({
        input: {
            options: {}
        },
        output: {
            filename: 'spritemap.svg',
            chunk: {
                name: 'spritemap',
                delete: true
            },
            svg4everybody: false,
            svgo: true
        },
        sprite: {
            prefix: 'sprite-',
            gutter: 2,
            generate: {
                // TODO: These options should accept a string which will be used as a prefix for the id of each specific element
                title: true,
                symbol: true,
                use: false,
                view: false
            }
        },
        styles: false
    }, options, {
        input: {
            patterns: typeof pattern === 'string' ? [pattern] : pattern
        }
    });

    // [output.svgo] If enabled by by passing `true`, set it to an empty object
    if ( output.output.svgo === true ) {
        output.output.svgo = {};
    }

    // [output.svgo] Always disable the SVGO cleanupIDs plugin
    if ( output.output.svgo ) {
        output.output.svgo = merge({
            plugins: [{
                cleanupIDs: false
            }]
        }, output.output.svgo);
    }

    // [output.svg4everybody] If enabled by by passing `true`, set it to an empty object
    if ( output.output.svg4everybody === true ) {
        output.output.svg4everybody = {};
    }

    // [sprite.prefix] If disabled by passing `false`, set it to an empty string
    if ( output.sprite.prefix === false ) {
        output.sprite.prefix = '';
    }

    // [sprite.gutter] Reformat `false` to 0
    if ( output.sprite.gutter === false ) {
        output.sprite.gutter = 0;
    }

    if ( output.styles ) {
        if ( typeof output.styles === 'string' ) {
            output.styles = {
                filename: output.styles
            }
        } else if ( output.styles === true ) {
            output.styles = {};
        }

        output.styles = merge({
            filename: '~sprites.css',
            format: 'data',
            variables: {
                sprites: 'sprites',
                sizes: 'sizes',
                variables: 'variables',
                mixin: 'sprite'
            }
        }, output.styles);
    }

    return output;
};
<commit_msg>Clean up<commit_after>const merge = require('webpack-merge');
const validateOptions = require('./options-validator');

module.exports = (pattern, options) => {
    // Make the first argument optional, just passing a configuration
    // object should result in the default pattern being used
    if ( typeof options === 'undefined' && (typeof pattern === 'object' && pattern !== null) ) {
        options = pattern;
        pattern = '**/*.svg'
    }

    // Validate input
    validateOptions(pattern, options);

    // Format output
    const output = merge({
        input: {
            options: {}
        },
        output: {
            filename: 'spritemap.svg',
            chunk: {
                name: 'spritemap',
                delete: true
            },
            svg4everybody: false,
            svgo: true
        },
        sprite: {
            prefix: 'sprite-',
            gutter: 2,
            generate: {
                title: true,
                symbol: true,
                use: false,
                view: false
            }
        },
        styles: false
    }, options, {
        input: {
            patterns: typeof pattern === 'string' ? [pattern] : pattern
        }
    });

    // [output.svgo] If enabled by by passing `true`, set it to an empty object
    if ( output.output.svgo === true ) {
        output.output.svgo = {};
    }

    // [output.svgo] Always disable the SVGO cleanupIDs plugin
    if ( output.output.svgo ) {
        output.output.svgo = merge({
            plugins: [{
                cleanupIDs: false
            }]
        }, output.output.svgo);
    }

    // [output.svg4everybody] If enabled by by passing `true`, set it to an empty object
    if ( output.output.svg4everybody === true ) {
        output.output.svg4everybody = {};
    }

    // [sprite.prefix] If disabled by passing `false`, set it to an empty string
    if ( output.sprite.prefix === false ) {
        output.sprite.prefix = '';
    }

    // [sprite.gutter] Reformat `false` to 0
    if ( output.sprite.gutter === false ) {
        output.sprite.gutter = 0;
    }

    if ( output.styles ) {
        if ( typeof output.styles === 'string' ) {
            output.styles = {
                filename: output.styles
            }
        } else if ( output.styles === true ) {
            output.styles = {};
        }

        output.styles = merge({
            filename: '~sprites.css',
            format: 'data',
            variables: {
                sprites: 'sprites',
                sizes: 'sizes',
                variables: 'variables',
                mixin: 'sprite'
            }
        }, output.styles);
    }

    return output;
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
var phantomas = require('./index'),
	child;

var url = 'http://example.com';

child = phantomas(url, {verbose: true}, function(err, res) {
	if (err) {
		console.log('err #' + err);
		process.exit(err);
	}

	console.log(res);
});

// emit --verbose messages
child.stderr.pipe(process.stderr);

child.on('results', function (res) {
	console.log(res);
});

/**
child.on('data', function (data) {
	console.log(data);
});

child.on('error', function (code) {
	console.log(code);
	process.exit(code);
});
/**/
<commit_msg>phantomas.js: remove changes<commit_after>#!/usr/bin/env node
var path = require('path'),
	spawn = require('child_process').spawn,
	phantomjs = require('phantomjs');

var phantomas = spawn(phantomjs.path, [path.resolve(__dirname, 'phantomjs/phantomas.js')].concat(process.argv.slice(2)));

phantomas.stdout.pipe(process.stdout);
phantomas.stderr.pipe(process.stderr);

phantomas.on('close', function (code) {
	process.exit(code);
});
<|endoftext|>


<commit_before>/*
   All emon_widgets code is released under the GNU General Public License v3.
   See COPYRIGHT.txt and LICENSE.txt.

    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

function addOption(widget, optionKey, optionType, optionName, optionHint, optionData)
{
  widget["options"    ].push(optionKey);
  widget["optionstype"].push(optionType);
  widget["optionsname"].push(optionName);
  widget["optionshint"].push(optionHint);
  widget["optionsdata"].push(optionData);
}

function feedvalue_widgetlist()
{
  var widgets =
  {
    "feedvalue":
    {
      "offsetx":-40,"offsety":-30,"width":80,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
         [-1,   "Automatic"],
	 [0,    "0"],
         [1,    "1"],
         [2,    "2"],
         [3,    "3"],
         [4,    "4"],
         [5,    "5"],
         [6,    "6"]
       ];

  addOption(widgets["feedvalue"], "feedname",   "feed",    _Tr("Feed"),     _Tr("Feed value"),                                                            []);
  addOption(widgets["feedvalue"], "units",      "value",   _Tr("Units"),    _Tr("Units to show"),                                                     []);
  addOption(widgets["feedvalue"], "decimals",   "dropbox", _Tr("Decimals"), _Tr("Decimals to show"),                                                          decimalsDropBoxOptions);

  return widgets;
}

function feedvalue_init()
{
  feedvalue_draw();
}

function feedvalue_draw()
{
  $('.feedvalue').each(function(index)
  {
    var feed = $(this).attr("feedname");
    if (feed==undefined) feed = $(this).attr("feed");

    var units = $(this).attr("units");
    var val = assoc[feed];
    var decimals = $(this).attr("decimals");

    if (feed==undefined) val = 0;
    if (units==undefined) units = '';
    if (val==undefined) val = 0;
    if (decimals==undefined) decimals = -1;

    if (isNaN(val))  val = 0;

    if (decimals<0)
    {

      if (val>=100)
          val = (val*1).toFixed(0);
      else if (val>=10)
          val = (val*1).toFixed(1);
      else if (val<=-100)
          val = (val*1).toFixed(0);
      else if (val<=-10)
          val = (val*1).toFixed(1);
      else
          val = (val*1).toFixed(2);
    }
    else
    {
      val = val.toFixed(decimals);
    }

    $(this).html(val+units);
  });
}

function feedvalue_slowupdate()
{
  feedvalue_draw();
}

function feedvalue_fastupdate()
{

}

<commit_msg>Update feedvalue_render.js<commit_after>/*
   All emon_widgets code is released under the GNU General Public License v3.
   See COPYRIGHT.txt and LICENSE.txt.

    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

function addOption(widget, optionKey, optionType, optionName, optionHint, optionData)
{
  widget["options"    ].push(optionKey);
  widget["optionstype"].push(optionType);
  widget["optionsname"].push(optionName);
  widget["optionshint"].push(optionHint);
  widget["optionsdata"].push(optionData);
}

function feedvalue_widgetlist()
{
  var widgets =
  {
    "feedvalue":
    {
      "offsetx":-40,"offsety":-30,"width":80,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
		[-1,   "Automatic"],
		[0,    "0"],
		[1,    "1"],
		[2,    "2"],
		[3,    "3"],
		[4,    "4"],
		[5,    "5"],
		[6,    "6"]
	];

  addOption(widgets["feedvalue"], "feedname",   "feed",    _Tr("Feed"),     _Tr("Feed value"),		[]);
  addOption(widgets["feedvalue"], "units",      "value",   _Tr("Units"),    _Tr("Units to show"),	[]);
  addOption(widgets["feedvalue"], "decimals",   "dropbox", _Tr("Decimals"), _Tr("Decimals to show"),	decimalsDropBoxOptions);

  return widgets;
}

function feedvalue_init()
{
  feedvalue_draw();
}

function feedvalue_draw()
{
  $('.feedvalue').each(function(index)
  {
    var feed = $(this).attr("feedname");
    if (feed==undefined) feed = $(this).attr("feed");

    var units = $(this).attr("units");
    var val = assoc[feed];
    var decimals = $(this).attr("decimals");

    if (feed==undefined) val = 0;
    if (units==undefined) units = '';
    if (val==undefined) val = 0;
    if (decimals==undefined) decimals = -1;

    if (isNaN(val))  val = 0;

    if (decimals<0)
    {

      if (val>=100)
          val = (val*1).toFixed(0);
      else if (val>=10)
          val = (val*1).toFixed(1);
      else if (val<=-100)
          val = (val*1).toFixed(0);
      else if (val<=-10)
          val = (val*1).toFixed(1);
      else
          val = (val*1).toFixed(2);
    }
    else
    {
      val = val.toFixed(decimals);
    }

    $(this).html(val+units);
  });
}

function feedvalue_slowupdate()
{
  feedvalue_draw();
}

function feedvalue_fastupdate()
{

}

<|endoftext|>


<commit_before>
screenshotPreview = function(filename){

    $("#linegraph").append("
<embed src=" + filename + " scale='tofit' type='application/pdf' width='25%' height='60%' class='pdf_image'>
");

};

<commit_msg>removed frame.js file, empty<commit_after><|endoftext|>


<commit_before>/**
 * @module src/DownloadTokens
 *
 * Component that display SourceDocument
 * Accepts the following properties:
 *  - language: Ethnologue code of the language
 *  - version: Version of the language
 *  - revision: Autogenerated for each updation of this same source
*/

import React, { Component } from 'react';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import { FormControl } from 'react-bootstrap';
import SourceLanguages from './SourceLanguages';
import $ from 'jquery';
import GlobalURL from './GlobalURL';

class DownloadTokens extends Component {
  constructor(props) {
    super(props);

    this.state = {
      language: 'tam',
      version: '',
      revision: '',
      uploaded:'uploadingStatus',
      message: ''
    }
      // Upload file specific callback handlers
      this.onSelect = this.onSelect.bind(this);
      this.downloadTokenWords = this.downloadTokenWords.bind(this);
      this.parseJSONToXLS = this.parseJSONToXLS.bind(this);
  }

  onSelect(e) {
    this.setState({
      [e.target.name]: e.target.value });
  }

// For Downloads Token words
  downloadTokenWords(e){
    e.preventDefault();
    var _this = this
    var data = {
        "language": this.state.language, "version": this.state.version, "revision": this.state.revision
    }
    let accessToken = JSON.parse(window.localStorage.getItem('access_token'))
    $.ajax({
      url: GlobalURL["hostURL"]+"/v1/autotokens",
      contentType: "application/json; charset=utf-8",
      data : JSON.stringify(data),
      method : "POST",
      headers: {
                "Authorization": "bearer " + JSON.stringify(accessToken['access_token']).slice(1,-1),
      },
      success: function (result) {
        if (result){
         _this.parseJSONToXLS(result);
        }
        _this.setState({message: result.message, uploaded: 'success'})
      },
      error: function (error) {
       _this.setState({message: error.message, uploaded: 'failure'})
      }
    });
  }

  // for parse JSON to XLS
  parseJSONToXLS(jsonData) {
      var jsonData1 = '';
       var dataUri1 = '';
      jsonData = JSON.parse(jsonData)
      $.each(jsonData, function(key, value) {
        var newLine = JSON.stringify(JSON.parse(JSON.stringify(jsonData[key]))).replace(/(?:\\[rn]|[\r\n]+)+/g, '\n');
        // var newLineLength = newLine.length;
        // var newLineBefore = '';
        // for( var i = 0; i < newLineLength; i++) {
        //   newLineBefore += newLine[i];
        // }
        jsonData1 = key + '\t \t' + newLine  + '\n'
        dataUri1 = jsonData1 + dataUri1;
      });
        let dataUri = 'data:text/csv;charset=utf-8,'+ encodeURIComponent(dataUri1);
        let exportFileDefaultName = this.state.language + this.state.version + 'Tokens.xls';
        let linkElement = document.createElement('a');
        linkElement.setAttribute('href', dataUri);
        linkElement.setAttribute('download', exportFileDefaultName);
        linkElement.click();
  }

  render() {
    return(

Download Tokens & Concordances

                {this.state.message}

                {this.state.message}

            <form className="col-lg-4 uploader" encType="multipart/form-data">

                <lable className="control-label">  Language Name  </lable>
                    <FormControl value={this.state.language} onChange={this.onSelect} name="language" componentClass="select" placeholder="select">
                      {SourceLanguages.map((language, i) => <option  key={i} value={language.code}>{language.value}</option>)}
                    </FormControl>

                <lable className="control-lable">  Version  </lable>
                    <input value={this.state.version} onChange={this.onSelect} name="version" type="text"  placeholder="version" className="form-control"/>

                <lable className="control-lable">  Revision  </lable>
                    <input value={this.state.revision} onChange={this.onSelect} name="revision" type="text" placeholder="revision" className="form-control"/>

                  <button id="button" type="button" className="btn btn-success" onClick={this.downloadTokenWords}> Download Token & Concordances</button>

            </form>

66 Books

Result of 66 book

      );
    }
}

export default DownloadTokens;<commit_msg>Error resolved<commit_after>/**
 * @module src/DownloadTokens
 *
 * Component that display SourceDocument
 * Accepts the following properties:
 *  - language: Ethnologue code of the language
 *  - version: Version of the language
 *  - revision: Autogenerated for each updation of this same source
*/

import React, { Component } from 'react';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import { FormControl } from 'react-bootstrap';
import SourceLanguages from './SourceLanguages';
import $ from 'jquery';
import GlobalURL from './GlobalURL';

class DownloadTokens extends Component {
  constructor(props) {
    super(props);

    this.state = {
      language: 'tam',
      version: '',
      revision: '',
      uploaded:'uploadingStatus',
      message: ''
    }
      // Upload file specific callback handlers
      this.onSelect = this.onSelect.bind(this);
      this.downloadTokenWords = this.downloadTokenWords.bind(this);
      this.parseJSONToXLS = this.parseJSONToXLS.bind(this);
  }

  onSelect(e) {
    this.setState({
      [e.target.name]: e.target.value });
  }

// For Downloads Token words
  downloadTokenWords(e){
    e.preventDefault();
    var _this = this
    var data = {
        "language": this.state.language, "version": this.state.version, "revision": this.state.revision
    }
    let accessToken = JSON.parse(window.localStorage.getItem('access_token'))
    $.ajax({
      url: GlobalURL["hostURL"]+"/v1/autotokens",
      contentType: "application/json; charset=utf-8",
      data : JSON.stringify(data),
      method : "POST",
      headers: {
                "Authorization": "bearer " + JSON.stringify(accessToken['access_token']).slice(1,-1),
      },
      success: function (result) {
        if (result){
         _this.parseJSONToXLS(result);
        }
        _this.setState({message: result.message, uploaded: 'success'})
      },
      error: function (error) {
       _this.setState({message: error.message, uploaded: 'failure'})
      }
    });
  }

  // for parse JSON to XLS
  parseJSONToXLS(jsonData) {
      var jsonData1 = '';
       var dataUri1 = '';
      jsonData = JSON.parse(jsonData)
      $.each(jsonData, function(key, value) {
        var newLine = JSON.stringify(JSON.parse(JSON.stringify(jsonData[key]))).replace(/(?:\\[rn]|[\r\n]+)+/g, '\n');
        jsonData1 = key + '\t \t' + newLine  + '\n'
        dataUri1 = jsonData1 + dataUri1;
      });
        let dataUri = 'data:text/csv;charset=utf-8,'+ encodeURIComponent(dataUri1);
        let exportFileDefaultName = this.state.language + this.state.version + 'Tokens.xls';
        let linkElement = document.createElement('a');
        linkElement.setAttribute('href', dataUri);
        linkElement.setAttribute('download', exportFileDefaultName);
        linkElement.click();
  }

  render() {
    return(

Download Tokens & Concordances

                {this.state.message}

                {this.state.message}

            <form className="col-lg-4 uploader" encType="multipart/form-data">

                <lable className="control-label">  Language Name  </lable>
                    <FormControl value={this.state.language} onChange={this.onSelect} name="language" componentClass="select" placeholder="select">
                      {SourceLanguages.map((language, i) => <option  key={i} value={language.code}>{language.value}</option>)}
                    </FormControl>

                <lable className="control-lable">  Version  </lable>
                    <input value={this.state.version} onChange={this.onSelect} name="version" type="text"  placeholder="version" className="form-control"/>

                <lable className="control-lable">  Revision  </lable>
                    <input value={this.state.revision} onChange={this.onSelect} name="revision" type="text" placeholder="revision" className="form-control"/>

                  <button id="button" type="button" className="btn btn-success" onClick={this.downloadTokenWords}> Download Token & Concordances</button>

            </form>

      );
    }
}

export default DownloadTokens;<|endoftext|>


<commit_before><commit_msg>change timeout<commit_after><|endoftext|>


<commit_before>var expect = window.weknowhow.expect;

describe('knockout.dragdrop', function () {
	it('attaches the binding handlers', function () {
		expect(ko.bindingHandlers, 'to have keys', ['dropZone', 'dragEvents', 'dragZone', 'scrollableOnDragOver']);
	});
});<commit_msg>Convert tabs to spaces<commit_after>var expect = window.weknowhow.expect;

describe('knockout.dragdrop', function () {
    it('attaches the binding handlers', function () {
        expect(ko.bindingHandlers, 'to have keys', ['dropZone', 'dragEvents', 'dragZone', 'scrollableOnDragOver']);
    });
});<|endoftext|>


<commit_before>export const postMessage = text => {
  return {
    type: 'POST_MESSAGE',
    message
    text
  }
}

export const setVisibilityFilter (message) => {
  return {
    type: 'SET_VISIBILITY_FILTER',
    filter
  }
}

export const toggleTodo = id => {
  return {
    type: 'TOGGLE_TODO',
    id
  }
}<commit_msg>create redux actions<commit_after>export const postMessage = (senderId, message, priority, isComment) => {
  return {
    type: 'POST_MESSAGE',
    message,
    priority,
    isComment,
    senderId,
  };
};

export const addUser = (email, groupId, adderId) => {
  return {
    type: 'ADD_MEMBER',
    email,
    groupId,
    adderId,
  };
};

export const deleteGroup = (ownerId, groupId) => {
  return {
    type: 'DELETE_GROUP',
    ownerId,
    groupId
  };
};

export const createGroup = (userId, title, description, initialMembers) => {
  return {
    type: 'CREATE_GROUP',
    userId,
    title,
    description,
    initialMembers
  };
};

export const getMessages = (groupId) => {
  return {
    type: 'GET_MESSAGES',
    groupId
  };
};

export const getGroupMembers = (groupId) => {
  return {
    type: 'GET_GROUP_MEMBERS',
    groupId
  };
};

export const getPostItMembers = () => {
  return {
    type: 'GET_POSTIT_MEMBERS',
  };
};

export const getAllGroups = () => {
  return {
    type: 'GET_ALL_GROUPS'
  };
};

export const deleteMember = (ownerId, email, groupId) => {
  return {
    type: 'DELETE_MEMBER',
    ownerId,
    email,
    groupId
  };
};
<|endoftext|>


<commit_before>'use strict';

/*global $, nodeca*/

var $container = $([]);

////////////////////////////////////////////////////////////////////////////////

module.exports = function notify(type, message, options) {
  var notice;

  if ('string' !== typeof message) {
    options = message;
    message = type;
    type    = 'error';
  }

  options = options || {};
  message = message || '';

  if (!$container.length) {
    $container = $('
').appendTo('body');
  }

  notice = $container.notify({
    type:       type,
    closable:   ( 'undefined' === typeof options.closable ) ? true : !!options.closable,
    fadeOut:    { enabled: !!options.autoclose, delay: +options.autoclose || 3000 },
    message:    { html: message }
  });

  notice.show();
  return notice;
};
<commit_msg>Small notify cleanup<commit_after>'use strict';

/*global $, nodeca*/

var $container;

////////////////////////////////////////////////////////////////////////////////

module.exports = function notify(type, message, options) {
  var notice;

  if ('string' !== typeof message) {
    options = message;
    message = type;
    type    = 'error';
  }

  options = options || {};
  message = message || '';

  if (!$container) {
    $container = $('
').appendTo('body');
  }

  notice = $container.notify({
    type:       type,
    closable:   ( 'undefined' === typeof options.closable ) ? true : !!options.closable,
    fadeOut:    { enabled: !!options.autoclose, delay: +options.autoclose || 3000 },
    message:    { html: message }
  });

  notice.show();
  return notice;
};
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import Helmet from 'react-helmet';
import { loadMonitor } from '../../redux/modules/monitor';
import { connect } from 'react-redux';
import { asyncConnect } from 'redux-connect';
import { Platform } from 'components';

@connect(
  state => ({
    platforms: state.monitor.platforms,
    loading: state.monitor.loading,
    loaded: state.monitor.loaded
  }),
  {}
)
@asyncConnect([{
  promise: ({store: {dispatch}}) => {
    return dispatch(loadMonitor());
  }
}])
export default class Monitor extends Component {
  static propTypes = {
    platforms: PropTypes.array,
    loaded: PropTypes.bool
  }

  render() {
    // const styles = require('./Monitor.scss');
    const { platforms, loaded } = this.props;
    let platformNodes;

    if (loaded) {
      platformNodes = platforms.map((platform) => {
        return (
          <Platform
            key={platform.id}
            name={platform.name}
            id={platform.id}
            pollInterval={platform.poll_interval}
          />
        );
      });
    } else {
      platformNodes = No platforms.;
    }

    return (

        <Helmet title="Monitor"/>

          {platformNodes}

    );
  }
}
<commit_msg>Added banner and footer to monitor.<commit_after>import React, { Component, PropTypes } from 'react';
import Helmet from 'react-helmet';
import { loadMonitor } from '../../redux/modules/monitor';
import { connect } from 'react-redux';
import { asyncConnect } from 'redux-connect';
import { Platform, Banner, Footer } from 'components';

@connect(
  state => ({
    platforms: state.monitor.platforms,
    loading: state.monitor.loading,
    loaded: state.monitor.loaded
  }),
  {}
)
@asyncConnect([{
  promise: ({store: {dispatch}}) => {
    return dispatch(loadMonitor());
  }
}])
export default class Monitor extends Component {
  static propTypes = {
    platforms: PropTypes.array,
    loaded: PropTypes.bool
  }

  render() {
    // const styles = require('./Monitor.scss');
    const { platforms, loaded } = this.props;
    let platformNodes;

    if (loaded) {
      platformNodes = platforms.map((platform) => {
        return (
          <Platform
            key={platform.id}
            name={platform.name}
            id={platform.id}
            pollInterval={platform.poll_interval}
          />
        );
      });
    } else {
      platformNodes = No platforms.;
    }

    return (

        <Helmet title="Monitor"/>
        <Banner title="Statistics monitor" image="error" />

          {platformNodes}

    );
  }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import shallowCompare from 'react-addons-shallow-compare'
import { isIOS, scrollTo } from '../lib/jello'
import Session from '../lib/session'
import { ADD_NEW_IDS_TO_RESULT, SET_LAYOUT_MODE } from '../constants/action_types'
import { SESSION_KEYS } from '../constants/application_types'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectCategoryTabs } from '../selectors/categories'
import {
  selectCurrentStream,
  selectDeviceSize,
  selectIsGridMode,
  selectIsLayoutToolHidden,
  selectIsNotificationsActive,
  selectIsNotificationsUnread,
  selectIsProfileMenuActive,
} from '../selectors/gui'
import { selectAvatar, selectUsername } from '../selectors/profile'
import { selectPage } from '../selectors/pages'
import { selectPathname, selectViewNameFromRoute } from '../selectors/routing'
import { logout } from '../actions/authentication'
import { setIsProfileMenuActive, toggleNotifications } from '../actions/gui'
import { checkForNewNotifications } from '../actions/notifications'
import { openOmnibar } from '../actions/omnibar'
import { updateRelationship } from '../actions/relationships'
import { loadFriends, loadNoise } from '../actions/stream'
import { NavbarLoggedIn, NavbarLoggedOut } from '../components/navbar/NavbarRenderables'
import { getDiscoverAction } from '../containers/DiscoverContainer'

function mapStateToProps(state) {
  const currentStream = selectCurrentStream(state)
  const isLoggedIn = selectIsLoggedIn(state)
  const pathname = selectPathname(state)
  const result = selectPage(state)
  const hasLoadMoreButton = !!(result && result.morePostIds)
  const viewName = selectViewNameFromRoute(state)
  const categoryTabs = viewName === 'discover' ? selectCategoryTabs(state) : null

  if (isLoggedIn) {
    return {
      avatar: selectAvatar(state),
      categoryTabs,
      deviceSize: selectDeviceSize(state),
      currentStream,
      hasLoadMoreButton,
      isGridMode: selectIsGridMode(state),
      isLayoutToolHidden: selectIsLayoutToolHidden(state),
      isLoggedIn,
      isNotificationsActive: selectIsNotificationsActive(state),
      isNotificationsUnread: selectIsNotificationsUnread(state),
      isProfileMenuActive: selectIsProfileMenuActive(state),
      pathname,
      username: selectUsername(state),
      viewName,
    }
  }
  return {
    categoryTabs,
    currentStream,
    hasLoadMoreButton,
    isLoggedIn,
    pathname,
    viewName,
  }
}

class NavbarContainer extends Component {

  static propTypes = {
    currentStream: PropTypes.string.isRequired,
    dispatch: PropTypes.func.isRequired,
    isGridMode: PropTypes.bool,
    isProfileMenuActive: PropTypes.bool,
    isLoggedIn: PropTypes.bool.isRequired,
    isNotificationsActive: PropTypes.bool,
    pathname: PropTypes.string.isRequired,
    params: PropTypes.object.isRequired,
    viewName: PropTypes.string.isRequired,
  }

  static contextTypes = {
    onClickScrollToContent: PropTypes.func,
  }

  componentWillMount() {
    this.checkForNotifications()
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState)
  }

  componentDidUpdate(prevProps) {
    if (typeof window === 'undefined' || !prevProps.pathname || !this.props.pathname) { return }
    if (prevProps.pathname !== this.props.pathname) {
      this.checkForNotifications()
    }
  }

  componentWillUnmount() {
    this.deactivateProfileMenu()
  }

  onClickAvatar = (e) => {
    e.preventDefault()
    e.stopPropagation()
    const { isProfileMenuActive } = this.props
    return isProfileMenuActive ? this.deactivateProfileMenu() : this.activateProfileMenu()
  }

  onClickDocument = () => {
    this.deactivateProfileMenu()
  }

  onClickNotification = (e) => {
    if (e) { e.preventDefault() }
    const { dispatch, isNotificationsActive } = this.props
    dispatch(toggleNotifications({ isActive: !isNotificationsActive }))
  }

  onClickLoadMorePosts = () => {
    const { dispatch, params } = this.props
    dispatch({ type: ADD_NEW_IDS_TO_RESULT })
    // if on user page and more content scroll to top of content
    if (params.username && !params.token) {
      const { onClickScrollToContent } = this.context
      onClickScrollToContent()
    } else {
      scrollTo(0, 0)
    }
  }

  onClickNavbarMark = () => {
    const { currentStream, dispatch, pathname, params, viewName } = this.props
    if (currentStream === pathname) {
      if (viewName === 'discover') {
        if (params.type) {
          dispatch(getDiscoverAction(params.type))
        }
      } else if (viewName === 'following') {
        dispatch(loadFriends())
      } else if (viewName === 'starred') {
        dispatch(loadNoise())
      }
      scrollTo(0, 0)
    }
  }

  onClickOmniButton = () => {
    const { dispatch } = this.props
    dispatch(openOmnibar())
    scrollTo(0, 0)
  }

  onClickToggleLayoutMode = () => {
    const { dispatch, isGridMode } = this.props
    const newMode = isGridMode ? 'list' : 'grid'
    dispatch({ type: SET_LAYOUT_MODE, payload: { mode: newMode } })
  }

  onDragOverOmniButton = (e) => {
    e.preventDefault()
    this.onClickOmniButton()
  }

  onDragOverStreamLink = (e) => {
    e.preventDefault()
    e.target.classList.add('hasDragOver')
  }

  onDragLeaveStreamLink = (e) => {
    e.target.classList.remove('hasDragOver')
  }

  onDropStreamLink = (e) => {
    e.preventDefault()
    e.stopPropagation()
    e.target.classList.remove('hasDragOver')
    if (e.dataTransfer.types.indexOf('application/json') > -1) {
      const data = JSON.parse(e.dataTransfer.getData('application/json'))
      if (data.userId && data.priority) {
        const newPriority = e.target.getAttribute('href') === '/starred' ? 'noise' : 'friend'
        this.props.dispatch(updateRelationship(data.userId, newPriority, data.priority))
      }
    }
  }

  onLogOut = () => {
    const { dispatch } = this.props
    this.deactivateProfileMenu()
    dispatch(logout())
  }

  // if we're viewing notifications, don't change the lightning-bolt link.
  // on any other page, we have the notifications link go back to whatever
  // category you were viewing last.
  getNotificationCategory() {
    const { viewName } = this.props
    if (viewName === 'notifications') { return '' }
    return (
      Session.getItem(SESSION_KEYS.NOTIFICATIONS_FILTER) ?
        `/${Session.getItem(SESSION_KEYS.NOTIFICATIONS_FILTER)}` : ''
    )
  }

  checkForNotifications() {
    const { dispatch, isLoggedIn } = this.props
    if (isLoggedIn) { dispatch(checkForNewNotifications()) }
  }

  activateProfileMenu() {
    const { dispatch, isProfileMenuActive } = this.props
    if (isProfileMenuActive) { return }
    dispatch(setIsProfileMenuActive({ isActive: true }))
    document.addEventListener('click', this.onClickDocument)
    if (isIOS()) {
      document.addEventListener('touchstart', this.onClickDocument)
    }
  }

  deactivateProfileMenu() {
    const { dispatch, isProfileMenuActive } = this.props
    if (!isProfileMenuActive) { return }
    dispatch(setIsProfileMenuActive({ isActive: false }))
    document.removeEventListener('click', this.onClickDocument)
    if (isIOS()) {
      document.removeEventListener('touchstart', this.onClickDocument)
    }
  }

  render() {
    const { isLoggedIn } = this.props
    if (isLoggedIn) {
      return (
        <NavbarLoggedIn
          {...this.props}
          notificationCategory={this.getNotificationCategory()}
          onClickAvatar={this.onClickAvatar}
          onClickDocument={this.onClickDocument}
          onClickLoadMorePosts={this.onClickLoadMorePosts}
          onClickNavbarMark={this.onClickNavbarMark}
          onClickNotification={this.onClickNotification}
          onClickOmniButton={this.onClickOmniButton}
          onClickToggleLayoutMode={this.onClickToggleLayoutMode}
          onDragLeaveStreamLink={this.onDragLeaveStreamLink}
          onDragOverOmniButton={this.onDragOverOmniButton}
          onDragOverStreamLink={this.onDragOverStreamLink}
          onDropStreamLink={this.onDropStreamLink}
          onLogOut={this.onLogOut}
        />
      )
    }
    return (
      <NavbarLoggedOut
        {...this.props}
        onClickLoadMorePosts={this.onClickLoadMorePosts}
        onClickNavbarMark={this.onClickNavbarMark}
      />
    )
  }
}

export default connect(mapStateToProps)(NavbarContainer)

<commit_msg>Check announcements the same time as notifications<commit_after>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import shallowCompare from 'react-addons-shallow-compare'
import { isIOS, scrollTo } from '../lib/jello'
import Session from '../lib/session'
import { ADD_NEW_IDS_TO_RESULT, SET_LAYOUT_MODE } from '../constants/action_types'
import { SESSION_KEYS } from '../constants/application_types'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectCategoryTabs } from '../selectors/categories'
import {
  selectCurrentStream,
  selectDeviceSize,
  selectIsGridMode,
  selectIsLayoutToolHidden,
  selectIsNotificationsActive,
  selectIsNotificationsUnread,
  selectIsProfileMenuActive,
} from '../selectors/gui'
import { selectAvatar, selectUsername } from '../selectors/profile'
import { selectPage } from '../selectors/pages'
import { selectPathname, selectViewNameFromRoute } from '../selectors/routing'
import { logout } from '../actions/authentication'
import { setIsProfileMenuActive, toggleNotifications } from '../actions/gui'
import { checkForNewNotifications, loadAnnouncements } from '../actions/notifications'
import { openOmnibar } from '../actions/omnibar'
import { updateRelationship } from '../actions/relationships'
import { loadFriends, loadNoise } from '../actions/stream'
import { NavbarLoggedIn, NavbarLoggedOut } from '../components/navbar/NavbarRenderables'
import { getDiscoverAction } from '../containers/DiscoverContainer'

function mapStateToProps(state) {
  const currentStream = selectCurrentStream(state)
  const isLoggedIn = selectIsLoggedIn(state)
  const pathname = selectPathname(state)
  const result = selectPage(state)
  const hasLoadMoreButton = !!(result && result.morePostIds)
  const viewName = selectViewNameFromRoute(state)
  const categoryTabs = viewName === 'discover' ? selectCategoryTabs(state) : null

  if (isLoggedIn) {
    return {
      avatar: selectAvatar(state),
      categoryTabs,
      deviceSize: selectDeviceSize(state),
      currentStream,
      hasLoadMoreButton,
      isGridMode: selectIsGridMode(state),
      isLayoutToolHidden: selectIsLayoutToolHidden(state),
      isLoggedIn,
      isNotificationsActive: selectIsNotificationsActive(state),
      isNotificationsUnread: selectIsNotificationsUnread(state),
      isProfileMenuActive: selectIsProfileMenuActive(state),
      pathname,
      username: selectUsername(state),
      viewName,
    }
  }
  return {
    categoryTabs,
    currentStream,
    hasLoadMoreButton,
    isLoggedIn,
    pathname,
    viewName,
  }
}

class NavbarContainer extends Component {

  static propTypes = {
    currentStream: PropTypes.string.isRequired,
    dispatch: PropTypes.func.isRequired,
    isGridMode: PropTypes.bool,
    isProfileMenuActive: PropTypes.bool,
    isLoggedIn: PropTypes.bool.isRequired,
    isNotificationsActive: PropTypes.bool,
    pathname: PropTypes.string.isRequired,
    params: PropTypes.object.isRequired,
    viewName: PropTypes.string.isRequired,
  }

  static contextTypes = {
    onClickScrollToContent: PropTypes.func,
  }

  componentWillMount() {
    this.checkForNotifications(true)
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState)
  }

  componentDidUpdate(prevProps) {
    if (typeof window === 'undefined' || !prevProps.pathname || !this.props.pathname) { return }
    if (prevProps.pathname !== this.props.pathname) {
      this.checkForNotifications()
    }
  }

  componentWillUnmount() {
    this.deactivateProfileMenu()
  }

  onClickAvatar = (e) => {
    e.preventDefault()
    e.stopPropagation()
    const { isProfileMenuActive } = this.props
    return isProfileMenuActive ? this.deactivateProfileMenu() : this.activateProfileMenu()
  }

  onClickDocument = () => {
    this.deactivateProfileMenu()
  }

  onClickNotification = (e) => {
    if (e) { e.preventDefault() }
    const { dispatch, isNotificationsActive } = this.props
    dispatch(toggleNotifications({ isActive: !isNotificationsActive }))
  }

  onClickLoadMorePosts = () => {
    const { dispatch, params } = this.props
    dispatch({ type: ADD_NEW_IDS_TO_RESULT })
    // if on user page and more content scroll to top of content
    if (params.username && !params.token) {
      const { onClickScrollToContent } = this.context
      onClickScrollToContent()
    } else {
      scrollTo(0, 0)
    }
  }

  onClickNavbarMark = () => {
    const { currentStream, dispatch, pathname, params, viewName } = this.props
    if (currentStream === pathname) {
      if (viewName === 'discover') {
        if (params.type) {
          dispatch(getDiscoverAction(params.type))
        }
      } else if (viewName === 'following') {
        dispatch(loadFriends())
      } else if (viewName === 'starred') {
        dispatch(loadNoise())
      }
      scrollTo(0, 0)
    }
  }

  onClickOmniButton = () => {
    const { dispatch } = this.props
    dispatch(openOmnibar())
    scrollTo(0, 0)
  }

  onClickToggleLayoutMode = () => {
    const { dispatch, isGridMode } = this.props
    const newMode = isGridMode ? 'list' : 'grid'
    dispatch({ type: SET_LAYOUT_MODE, payload: { mode: newMode } })
  }

  onDragOverOmniButton = (e) => {
    e.preventDefault()
    this.onClickOmniButton()
  }

  onDragOverStreamLink = (e) => {
    e.preventDefault()
    e.target.classList.add('hasDragOver')
  }

  onDragLeaveStreamLink = (e) => {
    e.target.classList.remove('hasDragOver')
  }

  onDropStreamLink = (e) => {
    e.preventDefault()
    e.stopPropagation()
    e.target.classList.remove('hasDragOver')
    if (e.dataTransfer.types.indexOf('application/json') > -1) {
      const data = JSON.parse(e.dataTransfer.getData('application/json'))
      if (data.userId && data.priority) {
        const newPriority = e.target.getAttribute('href') === '/starred' ? 'noise' : 'friend'
        this.props.dispatch(updateRelationship(data.userId, newPriority, data.priority))
      }
    }
  }

  onLogOut = () => {
    const { dispatch } = this.props
    this.deactivateProfileMenu()
    dispatch(logout())
  }

  // if we're viewing notifications, don't change the lightning-bolt link.
  // on any other page, we have the notifications link go back to whatever
  // category you were viewing last.
  getNotificationCategory() {
    const { viewName } = this.props
    if (viewName === 'notifications') { return '' }
    return (
      Session.getItem(SESSION_KEYS.NOTIFICATIONS_FILTER) ?
        `/${Session.getItem(SESSION_KEYS.NOTIFICATIONS_FILTER)}` : ''
    )
  }

  checkForNotifications(isMounting = false) {
    const { dispatch, isLoggedIn } = this.props
    if (isLoggedIn) {
      dispatch(checkForNewNotifications())
      if (!isMounting) { dispatch(loadAnnouncements()) }
    }
  }

  activateProfileMenu() {
    const { dispatch, isProfileMenuActive } = this.props
    if (isProfileMenuActive) { return }
    dispatch(setIsProfileMenuActive({ isActive: true }))
    document.addEventListener('click', this.onClickDocument)
    if (isIOS()) {
      document.addEventListener('touchstart', this.onClickDocument)
    }
  }

  deactivateProfileMenu() {
    const { dispatch, isProfileMenuActive } = this.props
    if (!isProfileMenuActive) { return }
    dispatch(setIsProfileMenuActive({ isActive: false }))
    document.removeEventListener('click', this.onClickDocument)
    if (isIOS()) {
      document.removeEventListener('touchstart', this.onClickDocument)
    }
  }

  render() {
    const { isLoggedIn } = this.props
    if (isLoggedIn) {
      return (
        <NavbarLoggedIn
          {...this.props}
          notificationCategory={this.getNotificationCategory()}
          onClickAvatar={this.onClickAvatar}
          onClickDocument={this.onClickDocument}
          onClickLoadMorePosts={this.onClickLoadMorePosts}
          onClickNavbarMark={this.onClickNavbarMark}
          onClickNotification={this.onClickNotification}
          onClickOmniButton={this.onClickOmniButton}
          onClickToggleLayoutMode={this.onClickToggleLayoutMode}
          onDragLeaveStreamLink={this.onDragLeaveStreamLink}
          onDragOverOmniButton={this.onDragOverOmniButton}
          onDragOverStreamLink={this.onDragOverStreamLink}
          onDropStreamLink={this.onDropStreamLink}
          onLogOut={this.onLogOut}
        />
      )
    }
    return (
      <NavbarLoggedOut
        {...this.props}
        onClickLoadMorePosts={this.onClickLoadMorePosts}
        onClickNavbarMark={this.onClickNavbarMark}
      />
    )
  }
}

export default connect(mapStateToProps)(NavbarContainer)

<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// 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.

import LayerManager from '../lib/layer-manager';
import EffectManager from '../experimental/lib/effect-manager';
import Effect from '../experimental/lib/effect';
import WebMercatorViewport from '../viewports/web-mercator-viewport';

import {EventManager} from 'mjolnir.js';
import {GL, AnimationLoop, createGLContext, setParameters} from 'luma.gl';

import PropTypes from 'prop-types';

/* global document */

function noop() {}

const propTypes = {
  id: PropTypes.string,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
  layers: PropTypes.array.isRequired, // Array can contain falsy values
  viewports: PropTypes.array, // Array can contain falsy values
  effects: PropTypes.arrayOf(PropTypes.instanceOf(Effect)),
  layerFilter: PropTypes.func,
  glOptions: PropTypes.object,
  gl: PropTypes.object,
  pickingRadius: PropTypes.number,
  initWebGLParameters: PropTypes.bool,
  onWebGLInitialized: PropTypes.func,
  onBeforeRender: PropTypes.func,
  onAfterRender: PropTypes.func,
  onLayerClick: PropTypes.func,
  onLayerHover: PropTypes.func,
  useDevicePixels: PropTypes.bool,

  // Debug settings
  debug: PropTypes.bool,
  drawPickingColors: PropTypes.bool
};

const defaultProps = {
  id: 'deckgl-overlay',
  pickingRadius: 0,
  layerFilter: null,
  glOptions: {},
  gl: null,
  effects: [],
  initWebGLParameters: false, // Will be set to true in next major release
  onWebGLInitialized: noop,
  onBeforeRender: noop,
  onAfterRender: noop,
  onLayerClick: null,
  onLayerHover: null,
  useDevicePixels: true,

  debug: false,
  drawPickingColors: false
};

// TODO - should this class be joined with `LayerManager`?
export default class DeckGLJS {

  constructor(props) {
    props = Object.assign({}, defaultProps, props);

    this.state = {};
    this.needsRedraw = true;
    this.layerManager = null;
    this.effectManager = null;
    this.viewports = [];

    // Bind methods
    this._onRendererInitialized = this._onRendererInitialized.bind(this);
    this._onRenderFrame = this._onRenderFrame.bind(this);

    this.canvas = this._createCanvas(props);

    const {width, height, gl, glOptions, debug, useDevicePixels} = props;

    this.animationLoop = new AnimationLoop({
      width,
      height,
      useDevicePixels,
      onCreateContext: opts =>
        gl || createGLContext(Object.assign({}, glOptions, {canvas: this.canvas, debug})),
      onInitialize: this._onRendererInitialized,
      onRender: this._onRenderFrame,
      onBeforeRender: props.onBeforeRender,
      onAfterRender: props.onAfterRender
    });

    this.animationLoop.start();

    this.setProps(props);
  }

  setProps(props) {
    props = Object.assign({}, this.props, props);
    this.props = props;

    if (!this.layerManager) {
      return;
    }

    const {
      layers,
      pickingRadius,
      onLayerClick,
      onLayerHover,
      useDevicePixels,
      drawPickingColors,
      layerFilter
    } = props;

    // Update viewports (creating one if not supplied)
    let viewports = props.viewports || props.viewport;
    if (!viewports) {
      const {width, height, latitude, longitude, zoom, pitch, bearing} = props;
      viewports = [
        new WebMercatorViewport({width, height, latitude, longitude, zoom, pitch, bearing})
      ];
    }

    // If more parameters need to be updated on layerManager add them to this method.
    this.layerManager.setParameters({
      layers,
      viewports,
      useDevicePixels,
      drawPickingColors,
      layerFilter,
      pickingRadius,
      onLayerClick,
      onLayerHover
    });

    // TODO - unify setParameters/setOptions/setProps etc naming.
    this.animationLoop.setViewParameters({useDevicePixels});
  }

  finalize() {
    this.animationLoop.stop();
    this.animationLoop = null;

    if (this.layerManager) {
      this.layerManager.finalize();
      this.layerManager = null;
    }
  }

  // Public API

  pickObject({x, y, radius = 0, layerIds = null}) {
    const selectedInfos = this.layerManager.pickObject({x, y, radius, layerIds, mode: 'query'});
    return selectedInfos.length ? selectedInfos[0] : null;
  }

  pickObjects({x, y, width = 1, height = 1, layerIds = null}) {
    return this.layerManager.pickObjects({x, y, width, height, layerIds});
  }

  getViewports() {
    return this.layerManager ? this.layerManager.getViewports() : [];
  }

  // Private Methods

  _createCanvas(props) {
    if (props.canvas) {
      return props.canvas;
    }

    const {id, width, height, style} = props;
    const canvas = document.createElement('canvas');
    canvas.id = id;
    canvas.width = width;
    canvas.height = height;
    canvas.style = style;

    const parent = props.parent || document.body;
    parent.appendChild(canvas);

    return canvas;
  }

  // Callbacks

  _onRendererInitialized({gl, canvas}) {
    setParameters(gl, {
      blend: true,
      blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA],
      polygonOffsetFill: true
    });

    // TODO - these should be set by default starting from next major release
    if (this.props.initWebGLParameters) {
      setParameters(gl, {
        depthTest: true,
        depthFunc: GL.LEQUAL
      });
    }

    this.props.onWebGLInitialized(gl);

    // Note: avoid React setState due GL animation loop / setState timing issue
    this.layerManager = new LayerManager(gl, {
      eventManager: new EventManager(canvas)
    });

    this.effectManager = new EffectManager({gl, layerManager: this.layerManager});

    for (const effect of this.props.effects) {
      this.effectManager.addEffect(effect);
    }

    this.setProps(this.props);
  }

  _onRenderFrame({gl}) {
    const redrawReason = this.layerManager.needsRedraw({clearRedrawFlags: true});
    if (!redrawReason) {
      return;
    }

    this.props.onBeforeRender({gl}); // TODO - should be called by AnimationLoop
    this.layerManager.drawLayers({
      pass: 'screen',
      redrawReason,
      // Helps debug layer picking, especially in framebuffer powered layers
      drawPickingColors: this.props.drawPickingColors
    });
    this.props.onAfterRender({gl}); // TODO - should be called by AnimationLoop
  }
}

DeckGLJS.propTypes = propTypes;
DeckGLJS.defaultProps = defaultProps;
<commit_msg>add new blend mode to initWebGLParameters (#1188)<commit_after>// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// 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.

import LayerManager from '../lib/layer-manager';
import EffectManager from '../experimental/lib/effect-manager';
import Effect from '../experimental/lib/effect';
import WebMercatorViewport from '../viewports/web-mercator-viewport';

import {EventManager} from 'mjolnir.js';
import {GL, AnimationLoop, createGLContext, setParameters} from 'luma.gl';

import PropTypes from 'prop-types';

/* global document */

function noop() {}

const propTypes = {
  id: PropTypes.string,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
  layers: PropTypes.array.isRequired, // Array can contain falsy values
  viewports: PropTypes.array, // Array can contain falsy values
  effects: PropTypes.arrayOf(PropTypes.instanceOf(Effect)),
  layerFilter: PropTypes.func,
  glOptions: PropTypes.object,
  gl: PropTypes.object,
  pickingRadius: PropTypes.number,
  initWebGLParameters: PropTypes.bool,
  onWebGLInitialized: PropTypes.func,
  onBeforeRender: PropTypes.func,
  onAfterRender: PropTypes.func,
  onLayerClick: PropTypes.func,
  onLayerHover: PropTypes.func,
  useDevicePixels: PropTypes.bool,

  // Debug settings
  debug: PropTypes.bool,
  drawPickingColors: PropTypes.bool
};

const defaultProps = {
  id: 'deckgl-overlay',
  pickingRadius: 0,
  layerFilter: null,
  glOptions: {},
  gl: null,
  effects: [],
  initWebGLParameters: false, // Will be set to true in next major release
  onWebGLInitialized: noop,
  onBeforeRender: noop,
  onAfterRender: noop,
  onLayerClick: null,
  onLayerHover: null,
  useDevicePixels: true,

  debug: false,
  drawPickingColors: false
};

// TODO - should this class be joined with `LayerManager`?
export default class DeckGLJS {

  constructor(props) {
    props = Object.assign({}, defaultProps, props);

    this.state = {};
    this.needsRedraw = true;
    this.layerManager = null;
    this.effectManager = null;
    this.viewports = [];

    // Bind methods
    this._onRendererInitialized = this._onRendererInitialized.bind(this);
    this._onRenderFrame = this._onRenderFrame.bind(this);

    this.canvas = this._createCanvas(props);

    const {width, height, gl, glOptions, debug, useDevicePixels} = props;

    this.animationLoop = new AnimationLoop({
      width,
      height,
      useDevicePixels,
      onCreateContext: opts =>
        gl || createGLContext(Object.assign({}, glOptions, {canvas: this.canvas, debug})),
      onInitialize: this._onRendererInitialized,
      onRender: this._onRenderFrame,
      onBeforeRender: props.onBeforeRender,
      onAfterRender: props.onAfterRender
    });

    this.animationLoop.start();

    this.setProps(props);
  }

  setProps(props) {
    props = Object.assign({}, this.props, props);
    this.props = props;

    if (!this.layerManager) {
      return;
    }

    const {
      layers,
      pickingRadius,
      onLayerClick,
      onLayerHover,
      useDevicePixels,
      drawPickingColors,
      layerFilter
    } = props;

    // Update viewports (creating one if not supplied)
    let viewports = props.viewports || props.viewport;
    if (!viewports) {
      const {width, height, latitude, longitude, zoom, pitch, bearing} = props;
      viewports = [
        new WebMercatorViewport({width, height, latitude, longitude, zoom, pitch, bearing})
      ];
    }

    // If more parameters need to be updated on layerManager add them to this method.
    this.layerManager.setParameters({
      layers,
      viewports,
      useDevicePixels,
      drawPickingColors,
      layerFilter,
      pickingRadius,
      onLayerClick,
      onLayerHover
    });

    // TODO - unify setParameters/setOptions/setProps etc naming.
    this.animationLoop.setViewParameters({useDevicePixels});
  }

  finalize() {
    this.animationLoop.stop();
    this.animationLoop = null;

    if (this.layerManager) {
      this.layerManager.finalize();
      this.layerManager = null;
    }
  }

  // Public API

  pickObject({x, y, radius = 0, layerIds = null}) {
    const selectedInfos = this.layerManager.pickObject({x, y, radius, layerIds, mode: 'query'});
    return selectedInfos.length ? selectedInfos[0] : null;
  }

  pickObjects({x, y, width = 1, height = 1, layerIds = null}) {
    return this.layerManager.pickObjects({x, y, width, height, layerIds});
  }

  getViewports() {
    return this.layerManager ? this.layerManager.getViewports() : [];
  }

  // Private Methods

  _createCanvas(props) {
    if (props.canvas) {
      return props.canvas;
    }

    const {id, width, height, style} = props;
    const canvas = document.createElement('canvas');
    canvas.id = id;
    canvas.width = width;
    canvas.height = height;
    canvas.style = style;

    const parent = props.parent || document.body;
    parent.appendChild(canvas);

    return canvas;
  }

  // Callbacks

  _onRendererInitialized({gl, canvas}) {
    setParameters(gl, {
      blend: true,
      blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA],
      polygonOffsetFill: true
    });

    // TODO - these should be set by default starting from next major release
    if (this.props.initWebGLParameters) {
      setParameters(gl, {
        blendFuncSeparate: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA],
        depthTest: true,
        depthFunc: GL.LEQUAL
      });
    }

    this.props.onWebGLInitialized(gl);

    // Note: avoid React setState due GL animation loop / setState timing issue
    this.layerManager = new LayerManager(gl, {
      eventManager: new EventManager(canvas)
    });

    this.effectManager = new EffectManager({gl, layerManager: this.layerManager});

    for (const effect of this.props.effects) {
      this.effectManager.addEffect(effect);
    }

    this.setProps(this.props);
  }

  _onRenderFrame({gl}) {
    const redrawReason = this.layerManager.needsRedraw({clearRedrawFlags: true});
    if (!redrawReason) {
      return;
    }

    this.props.onBeforeRender({gl}); // TODO - should be called by AnimationLoop
    this.layerManager.drawLayers({
      pass: 'screen',
      redrawReason,
      // Helps debug layer picking, especially in framebuffer powered layers
      drawPickingColors: this.props.drawPickingColors
    });
    this.props.onAfterRender({gl}); // TODO - should be called by AnimationLoop
  }
}

DeckGLJS.propTypes = propTypes;
DeckGLJS.defaultProps = defaultProps;
<|endoftext|>


<commit_before>import isObject from 'lodash/isObject';
import isFunction from 'lodash/isFunction';
import isArray from 'lodash/isArray';
import isString from 'lodash/isString';
import isBoolean from 'lodash/isBoolean';
import isNumber from 'lodash/isNumber';
import isDate from 'lodash/isDate';
import clone from 'lodash/clone';
import cloneDeep from 'lodash/cloneDeepWith';
import isUndefined from 'lodash/isUndefined';
import debounce from 'lodash/debounce';
import merge from 'lodash/merge';
import flatten from 'lodash/flatten';
import orderBy from 'lodash/orderBy';
import startCase from 'lodash/startCase';
import assignWith from 'lodash/assignWith';
import uniq from 'lodash/uniq';
import sumBy from 'lodash/sumBy';
import max from 'lodash/maxBy';
import min from 'lodash/minBy';
import zip from 'lodash/zip';

const noop = () => {
};
const yes = () => true;
const no = () => false;
const identity = arg => arg;

const toCamelCase = (...names) => {
	let i = 0,
		 length = names.length;

	for (; i < length; i++) {
		names[i] = names[i].toLowerCase();
	}

	if (length > 0) {
		return (names[0] +
		names.slice(1)
			.map(name =>
			name[0].toUpperCase() +
			name.substring(1, name.length))).replace(/,/g, '');
	}

	return '';
};

const isEmail = value => {
	if (value) {
		const re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
		return re.test(value);
	}

	return false;
};

export {
	isObject,
	isFunction,
	isArray,
	isString,
	isUndefined,
	isBoolean,
	isDate,
	isNumber,
	isEmail,
	clone,
	cloneDeep,
	debounce,
	merge,
	flatten,
	startCase,
	assignWith,
	uniq,
	identity,
	yes,
	no,
	toCamelCase,
	noop,
	orderBy,
	max,
	min,
	sumBy,
	zip
};<commit_msg>Utility test<commit_after>import isObject from 'lodash/isObject';
import isFunction from 'lodash/isFunction';
import isArray from 'lodash/isArray';
import isString from 'lodash/isString';
import isBoolean from 'lodash/isBoolean';
import isNumber from 'lodash/isNumber';
import isDate from 'lodash/isDate';
import clone from 'lodash/clone';
import cloneDeep from 'lodash/cloneDeepWith';
import isUndefined from 'lodash/isUndefined';
import debounce from 'lodash/debounce';
import merge from 'lodash/merge';
import flatten from 'lodash/flatten';
import orderBy from 'lodash/orderBy';
import startCase from 'lodash/startCase';
import assignWith from 'lodash/assignWith';
import uniq from 'lodash/uniq';
import sumBy from 'lodash/sumBy';
import max from 'lodash/maxBy';
import min from 'lodash/minBy';
import zip from 'lodash/zip';

const noop = () => {
};
const yes = () => true;
const no = () => false;
const identity = arg => arg;

const toCamelCase = (...names) => {
	let i = 0,
		length = names.length;

	for (; i < length; i++) {
		names[i] = names[i].toLowerCase();
	}

	if (length > 0) {
		return (names[0] +
		names.slice(1)
			.map(name => name[0].toUpperCase() + name.substring(1, name.length))
			.join(''));
	}

	return '';
};

const isEmail = value => {
	if (value) {
		const re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
		return re.test(value);
	}

	return false;
};

export {
	isObject,
	isFunction,
	isArray,
	isString,
	isUndefined,
	isBoolean,
	isDate,
	isNumber,
	isEmail,
	clone,
	cloneDeep,
	debounce,
	merge,
	flatten,
	startCase,
	assignWith,
	uniq,
	identity,
	yes,
	no,
	toCamelCase,
	noop,
	orderBy,
	max,
	min,
	sumBy,
	zip
};<|endoftext|>