<commit_before>'use strict';

var should = require('chai').should();
var bitcore = require('../..');
var Interpreter = bitcore.Script.Interpreter;
var Transaction = bitcore.Transaction;
var PrivateKey = bitcore.PrivateKey;
var Script = bitcore.Script;
var BN = bitcore.crypto.BN;
var BufferWriter = bitcore.encoding.BufferWriter;
var Opcode = bitcore.Opcode;
var _ = require('lodash');

var script_valid = require('../data/bitcoind/script_valid');
var script_invalid = require('../data/bitcoind/script_invalid');
var tx_valid = require('../data/bitcoind/tx_valid');
var tx_invalid = require('../data/bitcoind/tx_invalid');

//the script string format used in bitcoind data tests
Script.fromBitcoindString = function(str) {
  var bw = new BufferWriter();
  var tokens = str.split(' ');
  for (var i = 0; i < tokens.length; i++) {
    var token = tokens[i];
    if (token === '') {
      continue;
    }

    var opstr;
    var opcodenum;
    var tbuf;
    if (token[0] === '0' && token[1] === 'x') {
      var hex = token.slice(2);
      bw.write(new Buffer(hex, 'hex'));
    } else if (token[0] === '\'') {
      var tstr = token.slice(1, token.length - 1);
      var cbuf = new Buffer(tstr);
      tbuf = Script().add(cbuf).toBuffer();
      //bw.writeUInt8(tstr.length);
      bw.write(tbuf);
    } else if (typeof Opcode['OP_' + token] !== 'undefined') {
      opstr = 'OP_' + token;
      opcodenum = Opcode[opstr];
      bw.writeUInt8(opcodenum);
    } else if (typeof Opcode[token] === 'number') {
      opstr = token;
      opcodenum = Opcode[opstr];
      bw.writeUInt8(opcodenum);
    } else if (!isNaN(parseInt(token))) {
      var script = Script().add(new BN(token).toScriptNumBuffer());
      tbuf = script.toBuffer();
      bw.write(tbuf);
    } else {
      throw new Error('Could not determine type of script value');
    }
  }
  var buf = bw.concat();
  return this.fromBuffer(buf);
};

describe('Interpreter', function() {

  it('should make a new interp', function() {
    var interp = new Interpreter();
    (interp instanceof Interpreter).should.equal(true);
    interp.stack.length.should.equal(0);
    interp.altstack.length.should.equal(0);
    interp.pc.should.equal(0);
    interp.pbegincodehash.should.equal(0);
    interp.nOpCount.should.equal(0);
    interp.vfExec.length.should.equal(0);
    interp.errstr.should.equal('');
    interp.flags.should.equal(0);
  });

  describe('@castToBool', function() {

    it('should cast these bufs to bool correctly', function() {
      Interpreter.castToBool(new BN(0).toSM({
        endian: 'little'
      })).should.equal(false);
      Interpreter.castToBool(new Buffer('0080', 'hex')).should.equal(false); //negative 0
      Interpreter.castToBool(new BN(1).toSM({
        endian: 'little'
      })).should.equal(true);
      Interpreter.castToBool(new BN(-1).toSM({
        endian: 'little'
      })).should.equal(true);

      var buf = new Buffer('00', 'hex');
      var bool = BN.fromSM(buf, {
        endian: 'little'
      }).cmp(BN.Zero) !== 0;
      Interpreter.castToBool(buf).should.equal(bool);
    });

  });

  describe('#verify', function() {

    it('should verify these trivial scripts', function() {
      var verified;
      var si = Interpreter();
      verified = si.verify(Script('OP_1'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1'), Script('OP_0'));
      verified.should.equal(false);
      verified = Interpreter().verify(Script('OP_0'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('9 0x000000000000000010'), Script(''));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF'));
      verified.should.equal(true);
    });

    it('should verify these simple transaction', function() {
      // first we create a transaction
      var privateKey = new PrivateKey('cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY');
      var publicKey = privateKey.publicKey;
      var fromAddress = publicKey.toAddress();
      var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
      var scriptPubkey = Script.buildPublicKeyHashOut(fromAddress);
      var utxo = {
        address: fromAddress,
        txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
        outputIndex: 0,
        script: scriptPubkey,
        satoshis: 100000
      };
      var tx = new Transaction()
        .from(utxo)
        .to(toAddress, 100000)
        .sign(privateKey);

      // we then extract the signature from the first input
      var inputIndex = 0;
      var signature = tx.getSignatures(privateKey)[inputIndex].signature;

      var scriptSig = Script.buildPublicKeyHashIn(publicKey, signature);
      var flags = Interpreter.SCRIPT_VERIFY_P2SH | Interpreter.SCRIPT_VERIFY_STRICTENC;
      var verified = Interpreter().verify(scriptSig, scriptPubkey, tx, inputIndex, flags);
      verified.should.equal(true);
    });
  });

  var getFlags = function getFlags(flagstr) {
    var flags = 0;
    if (flagstr.indexOf('NONE') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_NONE;
    }
    if (flagstr.indexOf('P2SH') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_P2SH;
    }
    if (flagstr.indexOf('STRICTENC') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_STRICTENC;
    }
    if (flagstr.indexOf('DERSIG') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_DERSIG;
    }
    if (flagstr.indexOf('LOW_S') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_LOW_S;
    }
    if (flagstr.indexOf('NULLDUMMY') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_NULLDUMMY;
    }
    if (flagstr.indexOf('SIGPUSHONLY') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_SIGPUSHONLY;
    }
    if (flagstr.indexOf('MINIMALDATA') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_MINIMALDATA;
    }
    if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
    }
    return flags;
  };

  var testToFromString = function(script) {
    var s = script.toString();
    Script.fromString(s).toString().should.equal(s);
  };

  var testFixture = function(vector, expected) {
    var scriptSig = Script.fromBitcoindString(vector[0]);
    var scriptPubkey = Script.fromBitcoindString(vector[1]);
    var flags = getFlags(vector[2]);

    var hashbuf = new Buffer(32);
    hashbuf.fill(0);
    var credtx = new Transaction();
    credtx.uncheckedAddInput(new Transaction.Input({
      prevTxId: '0000000000000000000000000000000000000000000000000000000000000000',
      outputIndex: 0xffffffff,
      sequenceNumber: 0xffffffff,
      script: Script('OP_0 OP_0')
    }));
    credtx.addOutput(new Transaction.Output({
      script: scriptPubkey,
      satoshis: 0
    }));
    var idbuf = credtx.id;

    var spendtx = new Transaction();
    spendtx.uncheckedAddInput(new Transaction.Input({
      prevTxId: idbuf.toString('hex'),
      outputIndex: 0,
      sequenceNumber: 0xffffffff,
      script: scriptSig
    }));
    spendtx.addOutput(new Transaction.Output({
      script: new Script(),
      satoshis: 0
    }));

    var interp = new Interpreter();
    var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags);
    verified.should.equal(expected);
  };
  describe('bitcoind script evaluation fixtures', function() {
    var testAllFixtures = function(set, expected) {
      var c = 0;
      set.forEach(function(vector) {
        if (vector.length === 1) {
          return;
        }
        c++;
        var descstr = vector[3];
        var fullScriptString = vector[0] + ' ' + vector[1];
        var comment = descstr ? (' (' + descstr + ')') : '';
        it('should pass script_' + (expected ? '' : 'in') + 'valid ' +
          'vector #' + c + ': ' + fullScriptString + comment,
          function() {
            testFixture(vector, expected);
          });
      });
    };
    testAllFixtures(script_valid, true);
    testAllFixtures(script_invalid, false);

  });
  describe('bitcoind transaction evaluation fixtures', function() {
    var test_txs = function(set, expected) {
      var c = 0;
      set.forEach(function(vector) {
        if (vector.length === 1) {
          return;
        }
        c++;
        var cc = c; //copy to local
        it('should pass tx_' + (expected ? '' : 'in') + 'valid vector ' + cc, function() {
          var inputs = vector[0];
          var txhex = vector[1];
          var flags = getFlags(vector[2]);

          var map = {};
          inputs.forEach(function(input) {
            var txid = input[0];
            var txoutnum = input[1];
            var scriptPubKeyStr = input[2];
            if (txoutnum === -1) {
              txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
            }
            map[txid + ':' + txoutnum] = Script.fromBitcoindString(scriptPubKeyStr);
          });

          var tx = new Transaction(txhex);
          var allInputsVerified = true;
          tx.inputs.forEach(function(txin, j) {
            if (txin.isNull()) {
              return;
            }
            var scriptSig = txin.script;
            var txidhex = txin.prevTxId.toString('hex');
            var txoutnum = txin.outputIndex;
            var scriptPubkey = map[txidhex + ':' + txoutnum];
            should.exist(scriptPubkey);
            (scriptSig !== undefined).should.equal(true);
            var interp = new Interpreter();
            var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
            if (!verified) {
              allInputsVerified = false;
            }
          });
          var txVerified = tx.verify();
          txVerified = (txVerified === true) ? true : false;
          allInputsVerified = allInputsVerified && txVerified;
          allInputsVerified.should.equal(expected);

        });
      });
    };
    test_txs(tx_valid, true);
    test_txs(tx_invalid, false);

  });

});
<commit_msg>remove comment<commit_after>'use strict';

var should = require('chai').should();
var bitcore = require('../..');
var Interpreter = bitcore.Script.Interpreter;
var Transaction = bitcore.Transaction;
var PrivateKey = bitcore.PrivateKey;
var Script = bitcore.Script;
var BN = bitcore.crypto.BN;
var BufferWriter = bitcore.encoding.BufferWriter;
var Opcode = bitcore.Opcode;
var _ = require('lodash');

var script_valid = require('../data/bitcoind/script_valid');
var script_invalid = require('../data/bitcoind/script_invalid');
var tx_valid = require('../data/bitcoind/tx_valid');
var tx_invalid = require('../data/bitcoind/tx_invalid');

//the script string format used in bitcoind data tests
Script.fromBitcoindString = function(str) {
  var bw = new BufferWriter();
  var tokens = str.split(' ');
  for (var i = 0; i < tokens.length; i++) {
    var token = tokens[i];
    if (token === '') {
      continue;
    }

    var opstr;
    var opcodenum;
    var tbuf;
    if (token[0] === '0' && token[1] === 'x') {
      var hex = token.slice(2);
      bw.write(new Buffer(hex, 'hex'));
    } else if (token[0] === '\'') {
      var tstr = token.slice(1, token.length - 1);
      var cbuf = new Buffer(tstr);
      tbuf = Script().add(cbuf).toBuffer();
      bw.write(tbuf);
    } else if (typeof Opcode['OP_' + token] !== 'undefined') {
      opstr = 'OP_' + token;
      opcodenum = Opcode[opstr];
      bw.writeUInt8(opcodenum);
    } else if (typeof Opcode[token] === 'number') {
      opstr = token;
      opcodenum = Opcode[opstr];
      bw.writeUInt8(opcodenum);
    } else if (!isNaN(parseInt(token))) {
      var script = Script().add(new BN(token).toScriptNumBuffer());
      tbuf = script.toBuffer();
      bw.write(tbuf);
    } else {
      throw new Error('Could not determine type of script value');
    }
  }
  var buf = bw.concat();
  return this.fromBuffer(buf);
};

describe('Interpreter', function() {

  it('should make a new interp', function() {
    var interp = new Interpreter();
    (interp instanceof Interpreter).should.equal(true);
    interp.stack.length.should.equal(0);
    interp.altstack.length.should.equal(0);
    interp.pc.should.equal(0);
    interp.pbegincodehash.should.equal(0);
    interp.nOpCount.should.equal(0);
    interp.vfExec.length.should.equal(0);
    interp.errstr.should.equal('');
    interp.flags.should.equal(0);
  });

  describe('@castToBool', function() {

    it('should cast these bufs to bool correctly', function() {
      Interpreter.castToBool(new BN(0).toSM({
        endian: 'little'
      })).should.equal(false);
      Interpreter.castToBool(new Buffer('0080', 'hex')).should.equal(false); //negative 0
      Interpreter.castToBool(new BN(1).toSM({
        endian: 'little'
      })).should.equal(true);
      Interpreter.castToBool(new BN(-1).toSM({
        endian: 'little'
      })).should.equal(true);

      var buf = new Buffer('00', 'hex');
      var bool = BN.fromSM(buf, {
        endian: 'little'
      }).cmp(BN.Zero) !== 0;
      Interpreter.castToBool(buf).should.equal(bool);
    });

  });

  describe('#verify', function() {

    it('should verify these trivial scripts', function() {
      var verified;
      var si = Interpreter();
      verified = si.verify(Script('OP_1'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1'), Script('OP_0'));
      verified.should.equal(false);
      verified = Interpreter().verify(Script('OP_0'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_CODESEPARATOR'), Script('OP_1'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script(''), Script('OP_DEPTH OP_0 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('9 0x000000000000000010'), Script(''));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'));
      verified.should.equal(true);
      verified = Interpreter().verify(Script('OP_0'), Script('OP_IF OP_VER OP_ELSE OP_1 OP_ENDIF'));
      verified.should.equal(true);
    });

    it('should verify these simple transaction', function() {
      // first we create a transaction
      var privateKey = new PrivateKey('cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY');
      var publicKey = privateKey.publicKey;
      var fromAddress = publicKey.toAddress();
      var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
      var scriptPubkey = Script.buildPublicKeyHashOut(fromAddress);
      var utxo = {
        address: fromAddress,
        txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
        outputIndex: 0,
        script: scriptPubkey,
        satoshis: 100000
      };
      var tx = new Transaction()
        .from(utxo)
        .to(toAddress, 100000)
        .sign(privateKey);

      // we then extract the signature from the first input
      var inputIndex = 0;
      var signature = tx.getSignatures(privateKey)[inputIndex].signature;

      var scriptSig = Script.buildPublicKeyHashIn(publicKey, signature);
      var flags = Interpreter.SCRIPT_VERIFY_P2SH | Interpreter.SCRIPT_VERIFY_STRICTENC;
      var verified = Interpreter().verify(scriptSig, scriptPubkey, tx, inputIndex, flags);
      verified.should.equal(true);
    });
  });

  var getFlags = function getFlags(flagstr) {
    var flags = 0;
    if (flagstr.indexOf('NONE') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_NONE;
    }
    if (flagstr.indexOf('P2SH') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_P2SH;
    }
    if (flagstr.indexOf('STRICTENC') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_STRICTENC;
    }
    if (flagstr.indexOf('DERSIG') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_DERSIG;
    }
    if (flagstr.indexOf('LOW_S') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_LOW_S;
    }
    if (flagstr.indexOf('NULLDUMMY') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_NULLDUMMY;
    }
    if (flagstr.indexOf('SIGPUSHONLY') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_SIGPUSHONLY;
    }
    if (flagstr.indexOf('MINIMALDATA') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_MINIMALDATA;
    }
    if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) {
      flags = flags | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
    }
    return flags;
  };

  var testToFromString = function(script) {
    var s = script.toString();
    Script.fromString(s).toString().should.equal(s);
  };

  var testFixture = function(vector, expected) {
    var scriptSig = Script.fromBitcoindString(vector[0]);
    var scriptPubkey = Script.fromBitcoindString(vector[1]);
    var flags = getFlags(vector[2]);

    var hashbuf = new Buffer(32);
    hashbuf.fill(0);
    var credtx = new Transaction();
    credtx.uncheckedAddInput(new Transaction.Input({
      prevTxId: '0000000000000000000000000000000000000000000000000000000000000000',
      outputIndex: 0xffffffff,
      sequenceNumber: 0xffffffff,
      script: Script('OP_0 OP_0')
    }));
    credtx.addOutput(new Transaction.Output({
      script: scriptPubkey,
      satoshis: 0
    }));
    var idbuf = credtx.id;

    var spendtx = new Transaction();
    spendtx.uncheckedAddInput(new Transaction.Input({
      prevTxId: idbuf.toString('hex'),
      outputIndex: 0,
      sequenceNumber: 0xffffffff,
      script: scriptSig
    }));
    spendtx.addOutput(new Transaction.Output({
      script: new Script(),
      satoshis: 0
    }));

    var interp = new Interpreter();
    var verified = interp.verify(scriptSig, scriptPubkey, spendtx, 0, flags);
    verified.should.equal(expected);
  };
  describe('bitcoind script evaluation fixtures', function() {
    var testAllFixtures = function(set, expected) {
      var c = 0;
      set.forEach(function(vector) {
        if (vector.length === 1) {
          return;
        }
        c++;
        var descstr = vector[3];
        var fullScriptString = vector[0] + ' ' + vector[1];
        var comment = descstr ? (' (' + descstr + ')') : '';
        it('should pass script_' + (expected ? '' : 'in') + 'valid ' +
          'vector #' + c + ': ' + fullScriptString + comment,
          function() {
            testFixture(vector, expected);
          });
      });
    };
    testAllFixtures(script_valid, true);
    testAllFixtures(script_invalid, false);

  });
  describe('bitcoind transaction evaluation fixtures', function() {
    var test_txs = function(set, expected) {
      var c = 0;
      set.forEach(function(vector) {
        if (vector.length === 1) {
          return;
        }
        c++;
        var cc = c; //copy to local
        it('should pass tx_' + (expected ? '' : 'in') + 'valid vector ' + cc, function() {
          var inputs = vector[0];
          var txhex = vector[1];
          var flags = getFlags(vector[2]);

          var map = {};
          inputs.forEach(function(input) {
            var txid = input[0];
            var txoutnum = input[1];
            var scriptPubKeyStr = input[2];
            if (txoutnum === -1) {
              txoutnum = 0xffffffff; //bitcoind casts -1 to an unsigned int
            }
            map[txid + ':' + txoutnum] = Script.fromBitcoindString(scriptPubKeyStr);
          });

          var tx = new Transaction(txhex);
          var allInputsVerified = true;
          tx.inputs.forEach(function(txin, j) {
            if (txin.isNull()) {
              return;
            }
            var scriptSig = txin.script;
            var txidhex = txin.prevTxId.toString('hex');
            var txoutnum = txin.outputIndex;
            var scriptPubkey = map[txidhex + ':' + txoutnum];
            should.exist(scriptPubkey);
            (scriptSig !== undefined).should.equal(true);
            var interp = new Interpreter();
            var verified = interp.verify(scriptSig, scriptPubkey, tx, j, flags);
            if (!verified) {
              allInputsVerified = false;
            }
          });
          var txVerified = tx.verify();
          txVerified = (txVerified === true) ? true : false;
          allInputsVerified = allInputsVerified && txVerified;
          allInputsVerified.should.equal(expected);

        });
      });
    };
    test_txs(tx_valid, true);
    test_txs(tx_invalid, false);

  });

});
<|endoftext|>


<commit_before>// Special thanks to oscar-g (https://github.com/oscar-g) for starting this at https://github.com/oscar-g/patternlab-node/tree/dev-gulp

var pkg = require('./package.json'),
    gulp = require('gulp'),
    path = require('path'),
    eol = require('os').EOL,
    del = require('del'),
    strip_banner = require('gulp-strip-banner'),
    header = require('gulp-header'),
    nodeunit = require('gulp-nodeunit'),
    browserSync = require('browser-sync').create();

require('gulp-load')(gulp);
var banner = [ '/** ',
  ' * <%= pkg.name %> - v<%= pkg.version %> - <%= today %>',
  ' * ',
  ' * <%= pkg.author %>, and the web community.',
  ' * Licensed under the <%= pkg.license %> license.',
  ' * ',
  ' * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.',
  ' * ', ' **/'].join(eol);

function paths () {
  return require('./config.json').paths;
}

//load patternlab-node tasks
gulp.loadTasks(__dirname+'/builder/patternlab_gulp.js');

//clean patterns dir
gulp.task('clean', function(cb){
  del.sync([path.resolve(paths().public.patterns, '*')], {force: true});
  cb();
});

//build the banner
gulp.task('banner', function(){
  return gulp.src([
    './builder/patternlab.js',
    './builder/object_factory.js',
    './builder/lineage_hunter.js',
    './builder/media_hunter.js',
    './builder/patternlab_grunt.js',
    './builder/patternlab_gulp.js',
    './builder/parameter_hunter.js',
    './builder/pattern_exporter.js',
    './builder/pattern_assembler.js',
    './builder/pseudopattern_hunter.js',
    './builder/list_item_hunter.js',
    './builder/style_modifier_hunter.js'
  ])
    .pipe(strip_banner())
    .pipe(header( banner, {
      pkg : pkg,
      today : new Date().getFullYear() }
    ))
    .pipe(gulp.dest('./builder'));
});

// COPY TASKS

// JS copy
gulp.task('cp:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)} )
    .pipe(gulp.dest(path.resolve(paths().public.js)));
});

// Images copy
gulp.task('cp:img', function(){
  return gulp.src(
    [ '**/*.gif', '**/*.png', '**/*.jpg', '**/*.jpeg'  ],
    {cwd: path.resolve(paths().source.images)} )
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Fonts copy
gulp.task('cp:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().source.fonts)})
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Data copy
gulp.task('cp:data', function(){
  return gulp.src('annotations.js', {cwd: path.resolve(paths().source.data)})
    .pipe(gulp.dest(path.resolve(paths().public.data)));
});

// CSS Copy
gulp.task('cp:css', function(){
  return gulp.src(path.resolve(paths().source.css, 'style.css'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream());
});

// Styleguide Copy
gulp.task('cp:styleguide', function(){
  return gulp.src(
      ['**/*'],
      {cwd: path.resolve(paths().source.styleguide)})
      .pipe(gulp.dest(path.resolve(paths().public.styleguide)))
      .pipe(browserSync.stream());
});

// server and watch tasks
gulp.task('connect', ['lab'], function () {
  browserSync.init({
    server: {
      baseDir: path.resolve(paths().public.root)
    },
    snippetOptions: {
      // Ignore all HTML files within the templates folder
      blacklist: ['/index.html', '/']
    },
    notify: {
      styles: [
        'display: none',
        'padding: 15px',
        'font-family: sans-serif',
        'position: fixed',
        'font-size: 1em',
        'z-index: 9999',
        'bottom: 0px',
        'right: 0px',
        'border-top-left-radius: 5px',
        'background-color: #1B2032',
        'opacity: 0.4',
        'margin: 0',
        'color: white',
        'text-align: center'
      ]
    }
  });
  gulp.watch(path.resolve(paths().source.css, '**/*.css'), ['cp:css']);

  gulp.watch(path.resolve(paths().source.styleguide, '**/*.*'), ['cp:styleguide']);

  gulp.watch(
    [
      path.resolve(paths().source.patterns, '**/*.mustache'),
      path.resolve(paths().source.patterns, '**/*.json'),
      path.resolve(paths().source.data, '*.json'),
      path.resolve(paths().source.fonts + '/*'),
      path.resolve(paths().source.images + '/*'),
      path.resolve(paths().source.data + '*.json')
    ],
    ['lab-pipe'],
    function () { browserSync.reload(); }
  );

});

//unit test
gulp.task('nodeunit', function(){
  return gulp.src('./test/**/*_tests.js')
    .pipe(nodeunit());
});

gulp.task('lab-pipe', ['lab'], function(cb){
  cb();
  browserSync.reload();
});

gulp.task('default', ['lab']);

gulp.task('assets', ['cp:js', 'cp:img', 'cp:font', 'cp:data', 'cp:css', 'cp:styleguide' ]);
gulp.task('prelab', ['clean', 'assets']);
gulp.task('lab', ['prelab', 'patternlab'], function(cb){cb();});
gulp.task('patterns', ['patternlab:only_patterns']);
gulp.task('serve', ['lab', 'connect']);
gulp.task('travis', ['lab', 'nodeunit']);

gulp.task('version', ['patternlab:version']);
gulp.task('help', ['patternlab:help']);
<commit_msg>Gulpfile enhancements: auto-watch all supported template types<commit_after>// Special thanks to oscar-g (https://github.com/oscar-g) for starting this at https://github.com/oscar-g/patternlab-node/tree/dev-gulp

var pkg = require('./package.json'),
    gulp = require('gulp'),
    path = require('path'),
    eol = require('os').EOL,
    del = require('del'),
    strip_banner = require('gulp-strip-banner'),
    header = require('gulp-header'),
    nodeunit = require('gulp-nodeunit'),
    browserSync = require('browser-sync').create();

require('gulp-load')(gulp);
var banner = [ '/** ',
  ' * <%= pkg.name %> - v<%= pkg.version %> - <%= today %>',
  ' * ',
  ' * <%= pkg.author %>, and the web community.',
  ' * Licensed under the <%= pkg.license %> license.',
  ' * ',
  ' * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.',
  ' * ', ' **/'].join(eol);

function paths () {
  return require('./config.json').paths;
}

//load patternlab-node tasks
gulp.loadTasks(__dirname+'/builder/patternlab_gulp.js');

//clean patterns dir
gulp.task('clean', function(cb){
  del.sync([path.resolve(paths().public.patterns, '*')], {force: true});
  cb();
});

//build the banner
gulp.task('banner', function(){
  return gulp.src([
    './builder/patternlab.js',
    './builder/object_factory.js',
    './builder/lineage_hunter.js',
    './builder/media_hunter.js',
    './builder/patternlab_grunt.js',
    './builder/patternlab_gulp.js',
    './builder/parameter_hunter.js',
    './builder/pattern_exporter.js',
    './builder/pattern_assembler.js',
    './builder/pseudopattern_hunter.js',
    './builder/list_item_hunter.js',
    './builder/style_modifier_hunter.js'
  ])
    .pipe(strip_banner())
    .pipe(header( banner, {
      pkg : pkg,
      today : new Date().getFullYear() }
    ))
    .pipe(gulp.dest('./builder'));
});

// COPY TASKS

// JS copy
gulp.task('cp:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)} )
    .pipe(gulp.dest(path.resolve(paths().public.js)));
});

// Images copy
gulp.task('cp:img', function(){
  return gulp.src(
    [ '**/*.gif', '**/*.png', '**/*.jpg', '**/*.jpeg'  ],
    {cwd: path.resolve(paths().source.images)} )
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Fonts copy
gulp.task('cp:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().source.fonts)})
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Data copy
gulp.task('cp:data', function(){
  return gulp.src('annotations.js', {cwd: path.resolve(paths().source.data)})
    .pipe(gulp.dest(path.resolve(paths().public.data)));
});

// CSS Copy
gulp.task('cp:css', function(){
  return gulp.src(path.resolve(paths().source.css, 'style.css'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream());
});

// Styleguide Copy
gulp.task('cp:styleguide', function(){
  return gulp.src(
      ['**/*'],
      {cwd: path.resolve(paths().source.styleguide)})
      .pipe(gulp.dest(path.resolve(paths().public.styleguide)))
      .pipe(browserSync.stream());
});

// server and watch tasks

// watch task utility functions
function getSupportedTemplateExtensions() {
  var engines = require('./builder/pattern_engines/pattern_engines');
  return engines.getSupportedFileExtensions();
}
function getTemplateWatches() {
  return getSupportedTemplateExtensions().map(function (dotExtension) {
    return path.resolve(paths().source.patterns, '**/*' + dotExtension);
  });
}

gulp.task('connect', ['lab'], function() {
  browserSync.init({
    server: {
      baseDir: path.resolve(paths().public.root)
    },
    snippetOptions: {
      // Ignore all HTML files within the templates folder
      blacklist: ['/index.html', '/']
    },
    notify: {
      styles: [
        'display: none',
        'padding: 15px',
        'font-family: sans-serif',
        'position: fixed',
        'font-size: 1em',
        'z-index: 9999',
        'bottom: 0px',
        'right: 0px',
        'border-top-left-radius: 5px',
        'background-color: #1B2032',
        'opacity: 0.4',
        'margin: 0',
        'color: white',
        'text-align: center'
      ]
    }
  });
  gulp.watch(path.resolve(paths().source.css, '**/*.css'), ['cp:css']);

  gulp.watch(path.resolve(paths().source.styleguide, '**/*.*'), ['cp:styleguide']);

  var patternWatches = [
    path.resolve(paths().source.patterns, '**/*.json'),
    path.resolve(paths().source.data, '*.json'),
    path.resolve(paths().source.fonts + '/*'),
    path.resolve(paths().source.images + '/*')
  ].concat(getTemplateWatches());

  gulp.watch(patternWatches, ['lab-pipe'], function () { browserSync.reload(); });
});

//unit test
gulp.task('nodeunit', function(){
  return gulp.src('./test/**/*_tests.js')
    .pipe(nodeunit());
});

gulp.task('lab-pipe', ['lab'], function(cb){
  cb();
  browserSync.reload();
});

gulp.task('default', ['lab']);

gulp.task('assets', ['cp:js', 'cp:img', 'cp:font', 'cp:data', 'cp:css', 'cp:styleguide' ]);
gulp.task('prelab', ['clean', 'assets']);
gulp.task('lab', ['prelab', 'patternlab'], function(cb){cb();});
gulp.task('patterns', ['patternlab:only_patterns']);
gulp.task('serve', ['lab', 'connect']);
gulp.task('travis', ['lab', 'nodeunit']);

gulp.task('version', ['patternlab:version']);
gulp.task('help', ['patternlab:help']);
<|endoftext|>


<commit_before>angular.module('mrlapp.service.MarySpeechGui', [])
        .controller('MarySpeechGuiCtrl', ['$scope', '$log', 'mrl', '$modal', function ($scope, $log, mrl, $modal) {
                $log.info('MarySpeechGuiCtrl');
                var _self = this;
                var msg = this.msg;

                this.updateState = function (service) {
                    var installationstatechanged = false;
                    if (service.installationstate != $scope.service.state
                            || service.installationstate == 'installationprogress') {
                        installationstatechanged = true;
                    }
                    $scope.service = service;
                    console.log('mary-updateState', service);
                    if (installationstatechanged) {
                        switch (service.installationstate) {
                            case 'noinstallationstarted':
                                break;
                            case 'nothingselected':
                            case 'installcomponents':
                            case 'installationprogress':
                                var modalInstance = $modal.open({
                                    animation: true,
                                    templateUrl: 'MarySpeechInstallation' + service.installationstate + '.html',
                                    controller: 'MarySpeechInstallationNothingSelectedCtrl',
                                    size: 'sm',
                                    scope: $scope
                                });
                                break;
                            case 'showlicenses':
                                var modalInstance = $modal.open({
                                    animation: true,
                                    templateUrl: 'MarySpeechInstallation' + service.installationstate + '.html',
                                    controller: 'MarySpeechInstalltionNothingSelectedCtrl',
                                    scope: $scope,
                                    size: 'lg'
                                });
                                break;
                        }
                    }
                };
                _self.updateState($scope.service);

                $scope.collapse = true;
                $log.info('Mary-voices', $scope.service.possibleVoices);
                $scope.componenturl = $scope.service.INSTALLFILEURL;
                console.log('mary', $scope.service);

                this.onMsg = function (inMsg) {
                    switch (inMsg.method) {
                        case 'onState':
                            _self.updateState(inMsg.data[0]);
                            $scope.$apply();
                            break;
                        default:
                            $log.error("ERROR - unhandled method " + $scope.name + " " + inMsg.method);
                            break;
                    }
                };

                $scope.install = function () {
                    var toInstall = [];
                    angular.forEach($scope.service.possibleVoices, function (value, key) {
                        if (value.isSelected) {
                            toInstall.push(value.name);
                        }
                    });
                    msg.send('installSelectedLanguagesAndVoices', toInstall);
                };

                msg.subscribe(this);
            }
        ])

        .controller('MarySpeechInstallationNothingSelectedCtrl', function ($scope, $modalInstance, $http, $sce) {
            $scope.close = $modalInstance.close();

            $scope.isUndefinedOrNull = function (val) {
                return angular.isUndefined(val) || val === null;
            };

            if ($scope.service.installationstate == 'showlicenses') {
                $scope.alllicenses = [];
                angular.forEach($scope.service.installationstateparam1, function (value, key) {
                    $scope.alllicenses.push(key);
                });
                $scope.counter = -1;

                $scope.showNextLicense = function () {
                    $scope.counter++;
                    console.log($scope.counter, $scope.alllicenses.length);
                    if ($scope.counter >= $scope.alllicenses.length) {
                        $scope.msg.installSelectedLanguagesAndVoices3();
                        $scope.close();
                    } else {
                        $scope.license = 'Loading license';
                        console.log($scope.alllicenses[$scope.counter]);
                        if (!$scope.isUndefinedOrNull($scope.alllicenses[$scope.counter])) {
                            $scope.license = $sce.trustAsHtml($scope.service.installationstateparam2[$scope.alllicenses[$scope.counter]]);
                        } else {
                            $scope.license = 'No license found';
                        }
                    }
                };

                $scope.showNextLicense();
            }
        });
<commit_msg>MarySpeech - fix introduced errors<commit_after>angular.module('mrlapp.service.MarySpeechGui', [])
        .controller('MarySpeechGuiCtrl', ['$scope', '$log', 'mrl', '$modal', function ($scope, $log, mrl, $modal) {
                $log.info('MarySpeechGuiCtrl');
                var _self = this;
                var msg = this.msg;

                this.updateState = function (service) {
                    var installationstatechanged = false;
                    if (service.installationstate != $scope.service.state
                            || service.installationstate == 'installationprogress') {
                        installationstatechanged = true;
                    }
                    $scope.service = service;
                    console.log('mary-updateState', service);
                    if (installationstatechanged) {
                        switch (service.installationstate) {
                            case 'noinstallationstarted':
                                break;
                            case 'nothingselected':
                            case 'installcomponents':
                            case 'installationprogress':
                                var modalInstance = $modal.open({
                                    animation: true,
                                    templateUrl: 'MarySpeechInstallation' + service.installationstate + '.html',
                                    controller: 'MarySpeechInstallationNothingSelectedCtrl',
                                    size: 'sm',
                                    scope: $scope
                                });
                                break;
                            case 'showlicenses':
                                var modalInstance = $modal.open({
                                    animation: true,
                                    templateUrl: 'MarySpeechInstallation' + service.installationstate + '.html',
                                    controller: 'MarySpeechInstallationNothingSelectedCtrl',
                                    scope: $scope,
                                    size: 'lg'
                                });
                                break;
                        }
                    }
                };
                _self.updateState($scope.service);

                $scope.collapse = true;
                $log.info('Mary-voices', $scope.service.possibleVoices);
                $scope.componenturl = $scope.service.INSTALLFILEURL;
                console.log('mary', $scope.service);

                this.onMsg = function (inMsg) {
                    switch (inMsg.method) {
                        case 'onState':
                            _self.updateState(inMsg.data[0]);
                            $scope.$apply();
                            break;
                        default:
                            $log.error("ERROR - unhandled method " + $scope.name + " " + inMsg.method);
                            break;
                    }
                };

                $scope.install = function () {
                    var toInstall = [];
                    angular.forEach($scope.service.possibleVoices, function (value, key) {
                        if (value.isSelected) {
                            toInstall.push(value.name);
                        }
                    });
                    msg.send('installSelectedLanguagesAndVoices', toInstall);
                };

                msg.subscribe(this);
            }
        ])

        .controller('MarySpeechInstallationNothingSelectedCtrl', function ($scope, $modalInstance, $http, $sce) {
            $scope.close = function() {
                $modalInstance.close()
            };

            $scope.isUndefinedOrNull = function (val) {
                return angular.isUndefined(val) || val === null;
            };

            if ($scope.service.installationstate == 'showlicenses') {
                $scope.alllicenses = [];
                angular.forEach($scope.service.installationstateparam1, function (value, key) {
                    $scope.alllicenses.push(key);
                });
                $scope.counter = -1;

                $scope.showNextLicense = function () {
                    $scope.counter++;
                    console.log($scope.counter, $scope.alllicenses.length);
                    if ($scope.counter >= $scope.alllicenses.length) {
                        $scope.msg.installSelectedLanguagesAndVoices3();
                        $scope.close();
                    } else {
                        $scope.license = 'Loading license';
                        console.log($scope.alllicenses[$scope.counter]);
                        if (!$scope.isUndefinedOrNull($scope.alllicenses[$scope.counter])) {
                            $scope.license = $sce.trustAsHtml($scope.service.installationstateparam2[$scope.alllicenses[$scope.counter]]);
                        } else {
                            $scope.license = 'No license found';
                        }
                    }
                };

                $scope.showNextLicense();
            }
        });
<|endoftext|>


<commit_before>$(document).ready(function() {
    console.log('Hi!');
});
<commit_msg>Initialize Foundation by default.<commit_after>$(document).ready(function() {
    $(document).foundation();
});
<|endoftext|>


<commit_before>// @flow

import {
  LOADED_KEY,
  Resets,
  addListener,
  bind,
  log,
  unreachable,
} from "../shared/main";
import type {
  ElementWithHint,
  FromBackground,
  FromRenderer,
  HintUpdate,
  ToBackground,
} from "../data/Messages";

import { type Rule, applyStyles, parseCSS } from "./css";

// It's tempting to put a random number or something in the ID, but in case
// something goes wrong and a rogue container is left behind it's always
// possible to find and remove it if the ID is known.
const CONTAINER_ID = "SynthWebExt";
const HINT_CLASS = "hint";
const HIDDEN_HINT_CLASS = "hiddenHint";
const MATCHED_HINT_CLASS = "matchedHint";
const MATCHED_CHARS_CLASS = "matchedChars";

const MAX_IMMEDIATE_HINT_MOVEMENTS = 50;
const UNRENDER_DELAY = 200; // ms

const CONTAINER_STYLES = {
  all: "unset",
  position: "absolute",
  "z-index": "2147483647", // Maximum z-index browsers support.
  width: "100%",
  height: "100%",
  "pointer-events": "none",
  overflow: "hidden",
};

const CSS = `
.${HINT_CLASS} {
  position: absolute;
  transform: translateY(-50%);
  box-sizing: border-box;
  padding: 2px;
  border: solid 1px rgba(0, 0, 0, 0.4);
  background-color: #ffd76e;
  color: black;
  font: menu;
  font-size: 12px;
  line-height: 1;
  font-weight: bold;
  white-space: nowrap;
  text-align: center;
  text-transform: uppercase;
}

.${HIDDEN_HINT_CLASS} {
  opacity: 0;
}

.${MATCHED_HINT_CLASS} {
  background-color: lime;
}

.${MATCHED_CHARS_CLASS} {
  opacity: 0.3;
}
`.trim();

export default class RendererProgram {
  css: string;
  parsedCSS: ?Array<Rule>;
  resets: Resets;

  constructor() {
    this.css = CSS;
    this.parsedCSS = undefined;
    this.resets = new Resets();

    bind(this, [
      [this.onMessage, { catch: true }],
      [this.sendMessage, { catch: true }],
      [this.start, { log: true, catch: true }],
      [this.stop, { log: true, catch: true }],
    ]);
  }

  start() {
    // The background program checks for this global using `executeScript` (in
    // the top frame only) to see if content scripts have been loaded
    // automatically from `content_scripts` in manifest.json.
    window[LOADED_KEY] = true;

    this.resets.add(addListener(browser.runtime.onMessage, this.onMessage));

    // In Chrome, content scripts continue to live after the extension has been
    // disabled, uninstalled or reloaded. A way to detect this is to make a
    // `Port` and listen for `onDisconnect`.
    // In Firefox, content scripts are nuked when uninstalling. `onDisconnect`
    // never runs. However, when reloading the content scripts seems to be
    // re-run (with the new code), but not connected to the background. Super
    // weird. That causes any kind of messaging with the background to throw
    // errors. And the port to immediately disconnect. So this port stuff for
    // dealing with “orphaned” content scripts ends up working in Firefox as
    // well, just in a slightly different way. Unfortunately, the
    // `port.postMessage()` call below causes a fat `TypeError: extension is
    // undefined` error to be logged to the Browser console for “orphaned”
    // content scripts. (The error is only logged, not `throw`n.) This bloats
    // the console a little, but doesn’t cause any other problems.
    const port = browser.runtime.connect();
    port.postMessage(wrapMessage({ type: "RendererScriptAdded" }));
    port.onDisconnect.addListener(() => {
      this.stop();
    });
  }

  stop() {
    window[LOADED_KEY] = false;
    this.resets.reset();
    this.unrender();
  }

  async sendMessage(message: FromRenderer): Promise<void> {
    log("log", "RendererProgram#sendMessage", message.type, message);
    await browser.runtime.sendMessage(wrapMessage(message));
  }

  onMessage(wrappedMessage: FromBackground) {
    if (wrappedMessage.type !== "ToRenderer") {
      return;
    }

    const { message } = wrappedMessage;

    log("log", "RendererProgram#onMessage", message.type, message);

    switch (message.type) {
      case "StateSync":
        log.level = message.logLevel;
        break;

      case "Render":
        this.render(message.elements);
        break;

      case "UpdateHints":
        this.updateHints(message.updates, { markMatched: message.markMatched });
        break;

      case "Unrender":
        this.unrender({ delayed: message.delayed });
        break;

      default:
        unreachable(message.type, message);
    }
  }

  render(elements: Array<ElementWithHint>) {
    this.unrender();

    // I've tried creating the container in the constructor and re-using it for
    // all renders, but that didn't turn out to be faster.
    const container = document.createElement("div");
    container.id = CONTAINER_ID;
    setStyles(container, {
      ...CONTAINER_STYLES,
      left: `${window.scrollX}px`,
      top: `${window.scrollY}px`,
    });

    // Using `mode: "closed"` is tempting, but then Firefox does not seem to
    // allow inspecting the elements inside in its devtools. That's important
    // for people who want to customize the styling of the hints.
    const root = container.attachShadow({ mode: "open" });

    if (this.parsedCSS == null) {
      // Inserting a `<style>` element is way faster than doing
      // `element.style.setProperty()` on every element.
      const style = document.createElement("style");
      style.append(document.createTextNode(this.css));
      root.append(style);

      // Chrome nicely allows inline styles inserted by an extension regardless
      // of CSP. I look forward to the day Firefox works this way too. See
      // <bugzil.la/1267027>. If `style.sheet` is null in Firefox (it is always
      // null in Chrome), it means that the style tag was blocked by CSP. Unlike
      // the case with the script tag in ElementManager.js, a data URI (`<link
      // rel="stylesheet" href="data:text/css;utf8,...">`) does not work here
      // (it causes no CSP warning in the console, but no styles are applied).
      // The only workaround I could find was manually parsing and applying the
      // CSS.
      if (BROWSER === "firefox" && style.sheet == null) {
        this.parsedCSS = parseCSS(this.css);
      }
    }

    if (document.documentElement != null) {
      document.documentElement.append(container);
    }

    if (elements.length === 0) {
      const element = createHintElement("¯\\_(ツ)_/¯");
      element.style.top = "50%";
      element.style.left = "50%";
      element.style.transform = "translate(-50%, -50%)";
      root.append(element);
      this.maybeApplyStyles(element);
      return;
    }

    // "W" is usually (one of) the widest character(s). This is surprisingly
    // cheap to calculate.
    const probe1 = createHintElement("W");
    const probe2 = createHintElement("WW");
    root.append(probe1);
    root.append(probe2);
    this.maybeApplyStyles(probe1);
    this.maybeApplyStyles(probe2);
    const rect1 = probe1.getBoundingClientRect();
    const rect2 = probe2.getBoundingClientRect();
    const halfHeight = Math.ceil(rect1.height / 2);
    const widthK = rect2.width - rect1.width;
    const widthM = rect1.width - widthK;
    probe1.remove();
    probe2.remove();

    const edgeElements = [];
    const restElements = [];
    let numEdgeElements = 0;

    // Use the rect of the container to get viewport width and height rather
    // than relying on `window.innerWidth` and `window.innerHeight`, to avoid
    // rendering hints behind the page scrollbars (if any). We've already
    // inserted the container into the DOM and made other DOM measurements
    // anyway. This is fast.
    const containerRect = container.getBoundingClientRect();

    for (const { hintMeasurements, hint } of elements) {
      const element = createHintElement(hint);

      // Use `right` rather than `left` since the hints should be right-aligned
      // rather than left-aligned. This could also be done using `left` and
      // `transform: translateX(-100%)`, but that results in blurry hints in
      // Chrome due to Chrome making the widths of the hints non-integer based
      // on the font. `calc()` does not affect performance.
      element.style.right = `calc(100% - ${Math.round(hintMeasurements.x)}px)`;
      element.style.top = `${Math.round(hintMeasurements.y)}px`;

      root.append(element);

      this.maybeApplyStyles(element);

      if (
        numEdgeElements < MAX_IMMEDIATE_HINT_MOVEMENTS &&
        (hintMeasurements.x <= Math.ceil(widthM + widthK * hint.length) ||
          hintMeasurements.y <= halfHeight ||
          containerRect.height - hintMeasurements.y <= halfHeight)
      ) {
        numEdgeElements = edgeElements.push(element);
      } else {
        restElements.push(element);
      }
    }

    // Most hints are already correctly positioned, but some near the edges
    // might need to be moved a tiny bit to avoid being partially off-screen.
    // Do this in a separate animation frame if there are a lot of hints so
    // that the hints appear on screen as quickly as possible. Adjusting
    // positions is just a tweak – that can be delayed a little bit.
    if (numEdgeElements > 0) {
      moveInsideViewport(edgeElements, containerRect);
    }

    // Using double `requestAnimationFrame` since they run before paint.
    // See: https://youtu.be/cCOL7MC4Pl0?t=20m29s
    window.requestAnimationFrame(() => {
      window.requestAnimationFrame(() => {
        moveInsideViewport(restElements, containerRect);
      });
    });

    this.sendMessage({
      type: "Rendered",
      timestamp: performance.now(),
    });
  }

  updateHints(
    updates: Array<HintUpdate>,
    { markMatched = false }: {| markMatched: boolean |} = {}
  ) {
    const container = document.getElementById(CONTAINER_ID);
    const root = container == null ? undefined : container.shadowRoot;
    if (root == null) {
      log("error", "RendererProgram#updateHints: missing root", container);
      return;
    }

    const hints = root.querySelectorAll(`.${HINT_CLASS}`);

    for (const [index, update] of updates.entries()) {
      const child = hints[index];

      if (child == null) {
        log(
          "error",
          "RendererProgram#updateHints: missing child",
          index,
          update
        );
        continue;
      }

      child.classList.toggle(HIDDEN_HINT_CLASS, update.type === "Hide");

      if (update.type === "Update") {
        emptyElement(child);
        if (update.matched !== "") {
          const matched = document.createElement("span");
          matched.className = MATCHED_CHARS_CLASS;
          matched.append(document.createTextNode(update.matched));
          child.append(matched);
          this.maybeApplyStyles(matched);
        }
        if (markMatched) {
          child.classList.add(MATCHED_HINT_CLASS);
        }
        child.append(document.createTextNode(update.rest));
      }

      this.maybeApplyStyles(child);
    }
  }

  unrender({ delayed = false }: {| delayed: boolean |} = {}) {
    const container = document.getElementById(CONTAINER_ID);
    if (container != null) {
      if (delayed) {
        setTimeout(() => {
          container.remove();
        }, UNRENDER_DELAY);
      } else {
        container.remove();
      }
    }
  }

  maybeApplyStyles(element: HTMLElement) {
    if (this.parsedCSS != null) {
      applyStyles(element, this.parsedCSS);
    }
  }
}

function wrapMessage(message: FromRenderer): ToBackground {
  return {
    type: "FromRenderer",
    message,
  };
}

function setStyles(element: HTMLElement, styles: { [string]: string }) {
  for (const [property, value] of Object.entries(styles)) {
    // $FlowIgnore: Flow thinks that `value` is `mixed` here, but it is a `string`.
    element.style.setProperty(property, value, "important");
  }
}

function emptyElement(element: HTMLElement) {
  while (element.firstChild != null) {
    element.removeChild(element.firstChild);
  }
}

function moveInsideViewport(
  elements: Array<HTMLElement>,
  containerRect: ClientRect
) {
  for (const element of elements) {
    const rect = element.getBoundingClientRect();
    if (rect.left < 0) {
      element.style.marginRight = `${Math.round(rect.left)}px`;
    }
    if (rect.top < 0) {
      element.style.marginTop = `${Math.round(-rect.top)}px`;
    }
    if (rect.right > containerRect.width) {
      element.style.marginRight = `${Math.round(
        rect.right - containerRect.width
      )}px`;
    }
    if (rect.bottom > containerRect.height) {
      element.style.marginTop = `${Math.round(
        containerRect.height - rect.bottom
      )}px`;
    }
  }
}

function createHintElement(hint: string): HTMLElement {
  const element = document.createElement("div");
  element.className = HINT_CLASS;
  element.append(document.createTextNode(hint));
  return element;
}
<commit_msg>Reduce compiled code size in Chrome<commit_after>// @flow

import {
  LOADED_KEY,
  Resets,
  addListener,
  bind,
  log,
  unreachable,
} from "../shared/main";
import type {
  ElementWithHint,
  FromBackground,
  FromRenderer,
  HintUpdate,
  ToBackground,
} from "../data/Messages";

import { type Rule, applyStyles, parseCSS } from "./css";

// It's tempting to put a random number or something in the ID, but in case
// something goes wrong and a rogue container is left behind it's always
// possible to find and remove it if the ID is known.
const CONTAINER_ID = "SynthWebExt";
const HINT_CLASS = "hint";
const HIDDEN_HINT_CLASS = "hiddenHint";
const MATCHED_HINT_CLASS = "matchedHint";
const MATCHED_CHARS_CLASS = "matchedChars";

const MAX_IMMEDIATE_HINT_MOVEMENTS = 50;
const UNRENDER_DELAY = 200; // ms

const CONTAINER_STYLES = {
  all: "unset",
  position: "absolute",
  "z-index": "2147483647", // Maximum z-index browsers support.
  width: "100%",
  height: "100%",
  "pointer-events": "none",
  overflow: "hidden",
};

const CSS = `
.${HINT_CLASS} {
  position: absolute;
  transform: translateY(-50%);
  box-sizing: border-box;
  padding: 2px;
  border: solid 1px rgba(0, 0, 0, 0.4);
  background-color: #ffd76e;
  color: black;
  font: menu;
  font-size: 12px;
  line-height: 1;
  font-weight: bold;
  white-space: nowrap;
  text-align: center;
  text-transform: uppercase;
}

.${HIDDEN_HINT_CLASS} {
  opacity: 0;
}

.${MATCHED_HINT_CLASS} {
  background-color: lime;
}

.${MATCHED_CHARS_CLASS} {
  opacity: 0.3;
}
`.trim();

export default class RendererProgram {
  css: string;
  parsedCSS: ?Array<Rule>;
  resets: Resets;

  constructor() {
    this.css = CSS;
    this.parsedCSS = undefined;
    this.resets = new Resets();

    bind(this, [
      [this.onMessage, { catch: true }],
      [this.sendMessage, { catch: true }],
      [this.start, { log: true, catch: true }],
      [this.stop, { log: true, catch: true }],
    ]);
  }

  start() {
    // The background program checks for this global using `executeScript` (in
    // the top frame only) to see if content scripts have been loaded
    // automatically from `content_scripts` in manifest.json.
    window[LOADED_KEY] = true;

    this.resets.add(addListener(browser.runtime.onMessage, this.onMessage));

    // In Chrome, content scripts continue to live after the extension has been
    // disabled, uninstalled or reloaded. A way to detect this is to make a
    // `Port` and listen for `onDisconnect`.
    // In Firefox, content scripts are nuked when uninstalling. `onDisconnect`
    // never runs. However, when reloading the content scripts seems to be
    // re-run (with the new code), but not connected to the background. Super
    // weird. That causes any kind of messaging with the background to throw
    // errors. And the port to immediately disconnect. So this port stuff for
    // dealing with “orphaned” content scripts ends up working in Firefox as
    // well, just in a slightly different way. Unfortunately, the
    // `port.postMessage()` call below causes a fat `TypeError: extension is
    // undefined` error to be logged to the Browser console for “orphaned”
    // content scripts. (The error is only logged, not `throw`n.) This bloats
    // the console a little, but doesn’t cause any other problems.
    const port = browser.runtime.connect();
    port.postMessage(wrapMessage({ type: "RendererScriptAdded" }));
    port.onDisconnect.addListener(() => {
      this.stop();
    });
  }

  stop() {
    window[LOADED_KEY] = false;
    this.resets.reset();
    this.unrender();
  }

  async sendMessage(message: FromRenderer): Promise<void> {
    log("log", "RendererProgram#sendMessage", message.type, message);
    await browser.runtime.sendMessage(wrapMessage(message));
  }

  onMessage(wrappedMessage: FromBackground) {
    if (wrappedMessage.type !== "ToRenderer") {
      return;
    }

    const { message } = wrappedMessage;

    log("log", "RendererProgram#onMessage", message.type, message);

    switch (message.type) {
      case "StateSync":
        log.level = message.logLevel;
        break;

      case "Render":
        this.render(message.elements);
        break;

      case "UpdateHints":
        this.updateHints(message.updates, { markMatched: message.markMatched });
        break;

      case "Unrender":
        this.unrender({ delayed: message.delayed });
        break;

      default:
        unreachable(message.type, message);
    }
  }

  render(elements: Array<ElementWithHint>) {
    this.unrender();

    // I've tried creating the container in the constructor and re-using it for
    // all renders, but that didn't turn out to be faster.
    const container = document.createElement("div");
    container.id = CONTAINER_ID;
    setStyles(container, {
      ...CONTAINER_STYLES,
      left: `${window.scrollX}px`,
      top: `${window.scrollY}px`,
    });

    // Using `mode: "closed"` is tempting, but then Firefox does not seem to
    // allow inspecting the elements inside in its devtools. That's important
    // for people who want to customize the styling of the hints.
    const root = container.attachShadow({ mode: "open" });

    if (this.parsedCSS == null) {
      // Inserting a `<style>` element is way faster than doing
      // `element.style.setProperty()` on every element.
      const style = document.createElement("style");
      style.append(document.createTextNode(this.css));
      root.append(style);

      // Chrome nicely allows inline styles inserted by an extension regardless
      // of CSP. I look forward to the day Firefox works this way too. See
      // <bugzil.la/1267027>. If `style.sheet` is null in Firefox (it is always
      // null in Chrome), it means that the style tag was blocked by CSP. Unlike
      // the case with the script tag in ElementManager.js, a data URI (`<link
      // rel="stylesheet" href="data:text/css;utf8,...">`) does not work here
      // (it causes no CSP warning in the console, but no styles are applied).
      // The only workaround I could find was manually parsing and applying the
      // CSS.
      if (BROWSER === "firefox" && style.sheet == null) {
        this.parsedCSS = parseCSS(this.css);
      }
    }

    if (document.documentElement != null) {
      document.documentElement.append(container);
    }

    if (elements.length === 0) {
      const element = createHintElement("¯\\_(ツ)_/¯");
      element.style.top = "50%";
      element.style.left = "50%";
      element.style.transform = "translate(-50%, -50%)";
      root.append(element);
      this.maybeApplyStyles(element);
      return;
    }

    // "W" is usually (one of) the widest character(s). This is surprisingly
    // cheap to calculate.
    const probe1 = createHintElement("W");
    const probe2 = createHintElement("WW");
    root.append(probe1);
    root.append(probe2);
    this.maybeApplyStyles(probe1);
    this.maybeApplyStyles(probe2);
    const rect1 = probe1.getBoundingClientRect();
    const rect2 = probe2.getBoundingClientRect();
    const halfHeight = Math.ceil(rect1.height / 2);
    const widthK = rect2.width - rect1.width;
    const widthM = rect1.width - widthK;
    probe1.remove();
    probe2.remove();

    const edgeElements = [];
    const restElements = [];
    let numEdgeElements = 0;

    // Use the rect of the container to get viewport width and height rather
    // than relying on `window.innerWidth` and `window.innerHeight`, to avoid
    // rendering hints behind the page scrollbars (if any). We've already
    // inserted the container into the DOM and made other DOM measurements
    // anyway. This is fast.
    const containerRect = container.getBoundingClientRect();

    for (const { hintMeasurements, hint } of elements) {
      const element = createHintElement(hint);

      // Use `right` rather than `left` since the hints should be right-aligned
      // rather than left-aligned. This could also be done using `left` and
      // `transform: translateX(-100%)`, but that results in blurry hints in
      // Chrome due to Chrome making the widths of the hints non-integer based
      // on the font. `calc()` does not affect performance.
      element.style.right = `calc(100% - ${Math.round(hintMeasurements.x)}px)`;
      element.style.top = `${Math.round(hintMeasurements.y)}px`;

      root.append(element);

      this.maybeApplyStyles(element);

      if (
        numEdgeElements < MAX_IMMEDIATE_HINT_MOVEMENTS &&
        (hintMeasurements.x <= Math.ceil(widthM + widthK * hint.length) ||
          hintMeasurements.y <= halfHeight ||
          containerRect.height - hintMeasurements.y <= halfHeight)
      ) {
        numEdgeElements = edgeElements.push(element);
      } else {
        restElements.push(element);
      }
    }

    // Most hints are already correctly positioned, but some near the edges
    // might need to be moved a tiny bit to avoid being partially off-screen.
    // Do this in a separate animation frame if there are a lot of hints so
    // that the hints appear on screen as quickly as possible. Adjusting
    // positions is just a tweak – that can be delayed a little bit.
    if (numEdgeElements > 0) {
      moveInsideViewport(edgeElements, containerRect);
    }

    // Using double `requestAnimationFrame` since they run before paint.
    // See: https://youtu.be/cCOL7MC4Pl0?t=20m29s
    window.requestAnimationFrame(() => {
      window.requestAnimationFrame(() => {
        moveInsideViewport(restElements, containerRect);
      });
    });

    this.sendMessage({
      type: "Rendered",
      timestamp: performance.now(),
    });
  }

  updateHints(
    updates: Array<HintUpdate>,
    { markMatched = false }: {| markMatched: boolean |} = {}
  ) {
    const container = document.getElementById(CONTAINER_ID);
    const root = container == null ? undefined : container.shadowRoot;
    if (root == null) {
      log("error", "RendererProgram#updateHints: missing root", container);
      return;
    }

    const hints = root.querySelectorAll(`.${HINT_CLASS}`);

    for (const [index, update] of updates.entries()) {
      const child = hints[index];

      if (child == null) {
        log(
          "error",
          "RendererProgram#updateHints: missing child",
          index,
          update
        );
        continue;
      }

      child.classList.toggle(HIDDEN_HINT_CLASS, update.type === "Hide");

      if (update.type === "Update") {
        emptyElement(child);
        if (update.matched !== "") {
          const matched = document.createElement("span");
          matched.className = MATCHED_CHARS_CLASS;
          matched.append(document.createTextNode(update.matched));
          child.append(matched);
          this.maybeApplyStyles(matched);
        }
        if (markMatched) {
          child.classList.add(MATCHED_HINT_CLASS);
        }
        child.append(document.createTextNode(update.rest));
      }

      this.maybeApplyStyles(child);
    }
  }

  unrender({ delayed = false }: {| delayed: boolean |} = {}) {
    const container = document.getElementById(CONTAINER_ID);
    if (container != null) {
      if (delayed) {
        setTimeout(() => {
          container.remove();
        }, UNRENDER_DELAY);
      } else {
        container.remove();
      }
    }
  }

  maybeApplyStyles(element: HTMLElement) {
    if (BROWSER === "firefox" && this.parsedCSS != null) {
      applyStyles(element, this.parsedCSS);
    }
  }
}

function wrapMessage(message: FromRenderer): ToBackground {
  return {
    type: "FromRenderer",
    message,
  };
}

function setStyles(element: HTMLElement, styles: { [string]: string }) {
  for (const [property, value] of Object.entries(styles)) {
    // $FlowIgnore: Flow thinks that `value` is `mixed` here, but it is a `string`.
    element.style.setProperty(property, value, "important");
  }
}

function emptyElement(element: HTMLElement) {
  while (element.firstChild != null) {
    element.removeChild(element.firstChild);
  }
}

function moveInsideViewport(
  elements: Array<HTMLElement>,
  containerRect: ClientRect
) {
  for (const element of elements) {
    const rect = element.getBoundingClientRect();
    if (rect.left < 0) {
      element.style.marginRight = `${Math.round(rect.left)}px`;
    }
    if (rect.top < 0) {
      element.style.marginTop = `${Math.round(-rect.top)}px`;
    }
    if (rect.right > containerRect.width) {
      element.style.marginRight = `${Math.round(
        rect.right - containerRect.width
      )}px`;
    }
    if (rect.bottom > containerRect.height) {
      element.style.marginTop = `${Math.round(
        containerRect.height - rect.bottom
      )}px`;
    }
  }
}

function createHintElement(hint: string): HTMLElement {
  const element = document.createElement("div");
  element.className = HINT_CLASS;
  element.append(document.createTextNode(hint));
  return element;
}
<|endoftext|>


<commit_before>if (typeof define !== 'function') {
  var define = function (f) { module.exports = f (require); }
}

define(function(require) {
  'use strict';

  var Vec2 = require('./vec2');

  function intPower (n,p) {
    if (p < 1) return n;
    while (--p > 0) n *= n;
    return n;
  }
  function fact (n) {
    var ret = n;
    while (n > 1) ret *= --n;
    return ret;
  }
  function nChooseK (n,k) {
    return fact(n) / (fact(k) * fact(n-k));
  }

  /**
   * Given the coordinates of the end points of two line segments, this function returns
   * their intersection point, or null if they do not intersect.
   */
  var geom = {
    lineIntersect: function (p00x, p00y, p01x, p01y, p10x, p10y, p11x, p11y) {
      var dx1x3 = p00x - p10x;
      var dy1y3 = p00y - p10y;
      var dx2x1 = p01x - p00x;
      var dy2y1 = p01y - p00y;
      var dx4x3 = p11x - p10x;
      var dy4y3 = p11y - p10y;

      var denom = dy4y3*dx2x1 - dx4x3*dy2y1;
      var numa  = dx4x3*dy1y3 - dy4y3*dx1x3;
      var numb  = dx2x1*dy1y3 - dy2y1*dx1x3;

      if (denom === 0) return null;

      numa /= denom;
      numb /= denom;

      if (numa >= 0 && numa <= 1 && numb >= 0 && numb <= 1) {
        return {
          x: p00x + dx2x1*numa,
          y: p00y + dy2y1*numa
        };
      }

      return null;
    },

    /**
     * Returns true if the supplied point (x,y) lies in the space bounded by two
     * infinite lines which intersect the points defining the provided line segment, and
     * are perpendicular to the provided line segment.
     */
    pointInLinePerpSpace: function (ax, ay, bx, by, x, y) {
      var _ax, _ay;
      var _bx, _by;
      var _cx, _cy;

      float perpSlope = (ax-bx)/(by-ay);

      // If the slope is greater than 1, transpose the coordinate space to avoid infinity.
      if (perpSlope > 1) {
        _ax = ay; _bx = by; _cx = y;
        _ay = ax; _by = bx; _cy = x;
        perpSlope = (_ax-_bx)/(_by-_ay);
      } else {
        _ax = ax; _bx = bx; _cx = x;
        _ay = ay; _by = by; _cy = y;
      }

      float yMin, yMax;

      if (_ay > _by) {
        yMin = perpSlope*(_cx - _bx) + _by;
        yMax = perpSlope*(_cx - _ax) + _ay;
      } else {
        yMin = perpSlope*(_cx - _ax) + _ay;
        yMax = perpSlope*(_cx - _bx) + _by;
      }

      return _cy > yMin && _cy < yMax;
    }

    /**
     * Given an array of control points representing an arbitrary order Bezier curve
     * along with a value 't' between 0, and 1, this function will return a point
     * along the curve as a Vec2.
     */
    bezier: function (pts,t) {
      if (pts.length < 2) return pts[0];

      var u = 1 - t;
      var n = pts.length - 1;

      var ret = new Vec2;
      for (var i = 0; i <= n; ++i) {
        var coeff = nChooseK(n,i) * intPower(t,i) * intPower(u,n-i);
        ret.x += coeff * pts[i].x;
        ret.y += coeff * pts[i].y;
      }

      return ret;
    }
  };

  return geom;
});

<commit_msg>Fixed bad port of pointInLinePerpSpace<commit_after>if (typeof define !== 'function') {
  var define = function (f) { module.exports = f (require); }
}

define(function(require) {
  'use strict';

  var Vec2 = require('./vec2');

  function intPower (n,p) {
    if (p < 1) return n;
    while (--p > 0) n *= n;
    return n;
  }
  function fact (n) {
    var ret = n;
    while (n > 1) ret *= --n;
    return ret;
  }
  function nChooseK (n,k) {
    return fact(n) / (fact(k) * fact(n-k));
  }

  /**
   * Given the coordinates of the end points of two line segments, this function returns
   * their intersection point, or null if they do not intersect.
   */
  var geom = {
    lineIntersect: function (p00x, p00y, p01x, p01y, p10x, p10y, p11x, p11y) {
      var dx1x3 = p00x - p10x;
      var dy1y3 = p00y - p10y;
      var dx2x1 = p01x - p00x;
      var dy2y1 = p01y - p00y;
      var dx4x3 = p11x - p10x;
      var dy4y3 = p11y - p10y;

      var denom = dy4y3*dx2x1 - dx4x3*dy2y1;
      var numa  = dx4x3*dy1y3 - dy4y3*dx1x3;
      var numb  = dx2x1*dy1y3 - dy2y1*dx1x3;

      if (denom === 0) return null;

      numa /= denom;
      numb /= denom;

      if (numa >= 0 && numa <= 1 && numb >= 0 && numb <= 1) {
        return {
          x: p00x + dx2x1*numa,
          y: p00y + dy2y1*numa
        };
      }

      return null;
    },

    /**
     * Returns true if the supplied point (x,y) lies in the space bounded by two
     * infinite lines which intersect the points defining the provided line segment, and
     * are perpendicular to the provided line segment.
     */
    pointInLinePerpSpace: function (ax, ay, bx, by, x, y) {
      // If the slope is greater than 1, transpose the coordinate space to avoid infinity.
      if (perpSlope > 1) {
        var oax = ax, obx = bx, ox = x;
        ax =  ay; bx =  by;_x =  y;
        ay = oax; by = obx; y = ox;
      }

      var perpSlope = (ax-bx)/(by-ay);
      var yMin, yMax;

      if (ay > by) {
        yMin = perpSlope*(x - bx) + by;
        yMax = perpSlope*(x - ax) + ay;
      } else {
        yMin = perpSlope*(x - ax) + ay;
        yMax = perpSlope*(x - bx) + by;
      }

      return y > yMin && y < yMax;
    }

    /**
     * Given an array of control points representing an arbitrary order Bezier curve
     * along with a value 't' between 0, and 1, this function will return a point
     * along the curve as a Vec2.
     */
    bezier: function (pts,t) {
      if (pts.length < 2) return pts[0];

      var u = 1 - t;
      var n = pts.length - 1;

      var ret = new Vec2;
      for (var i = 0; i <= n; ++i) {
        var coeff = nChooseK(n,i) * intPower(t,i) * intPower(u,n-i);
        ret.x += coeff * pts[i].x;
        ret.y += coeff * pts[i].y;
      }

      return ret;
    }
  };

  return geom;
});

<|endoftext|>


<commit_before>import mongoose from 'mongoose';
const Schema = mongoose.Schema;

// esquema para la corrección de registros biológicos
const UpdatedSchema = new Schema({
  speciesOriginal: { type: String },
  locality: { type: String },
  lat: { type: Number },
  lon: { type: Number },
  dd: { type: Number },
  mm: { type: Number },
  yyyy: { type: Number },
  updatedDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

// esquema para el reporte de errores en registros biológicos
const ReportedSchema = new Schema({
  // id: Schema.ObjectId,
  isOutlier_bm: { type: Boolean },
  geoIssue_bm: { type: Boolean },
  idIssue_bm: { type: Boolean },
  oldTaxonomy_bm: { type: Boolean },
  inCaptivity_bm: { type: Boolean },
  otherIssues_bm: { type: Boolean },
  comments_bm: { type: String },
  reportedDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

// esquema para la creación de registros biológicos
const CreatedSchema = new Schema({
  _id: { type: Schema.ObjectId },
  taxID: { type: Number },
  acceptedNameUsage: String,
  locality: { type: String },
  lat: { type: Number },
  lon: { type: Number },
  alt: { type: Number },
  basisOfRecord: { type: String },
  collector: { type: String },
  source: { type: String },
  comments_bm: { type: String },
  citation_bm: { type: String },
  createdDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

const RecordSchema = new Schema(
  {
    occurrenceID: { type: String, default: null },
    taxID: { type: Number, required: true },
    acceptedNameUsage: { type: String, required: true },
    species: { type: String, default: null },
    speciesOriginal: { type: String, default: null },
    continent: { type: String, default: null },
    country: { type: String, default: null },
    adm1: { type: String, default: null },
    adm2: { type: String, default: null },
    locality: { type: String, default: null },
    lat: { type: Number, min: -90, max: 90 },
    lon: { type: Number, min: -180, max: 180 },
    alt: { type: Number, default: null },
    demAltitude: { type: Number, min: 0, max: 8000, default: null },
    interpretedElevation: { type: Number, min: 0, max: 8000, default: null },
    cellID: { type: Number, min: 0, default: null },
    basisOfRecord: { type: String, default: null },
    catalogNumber: { type: String, default: null },
    colection: { type: String, default: null },
    collector: { type: String, default: null },
    institution: { type: String, default: null },
    url: { type: String, default: null },
    earliestDateCollected: { type: String, default: null },
    latestDateCollected: { type: String, default: null },
    dd: { type: Number, min: 1, max: 31, default: null },
    mm: { type: Number, min: 1, max: 12, default: null },
    yyyy: { type: Number, min: 1800, max: 2100, default: null },
    correctCountry: { type: Boolean, default: null },
    correctStateProvince: { type: Boolean, default: null },
    correctCounty: { type: Boolean, default: null },
    hasLocality: { type: Boolean, default: null },
    inUrbanArea: { type: Boolean, default: null },
    suggestedCountry: { type: String, default: null },
    suggestedCounty: { type: String, default: null },
    suggestedMunicipality: { type: String, default: null },
    suggestedStateProvince: { type: String, default: null },
    sourceLayer: { type: String, default: null },
    coordUncertaintyM: { type: Number, default: null },
    lowUncertainty: { type: Boolean, default: null },
    altitudinalOutlier: { type: Boolean, default: null },
    consistentAltitude: { type: Boolean, default: null },
    diferenceInAltitude: { type: Number, min: 0, max: 8000, default: null },
    environmentalOutlier: { type: Boolean, default: null },
    insideKnownDistribution: { type: Boolean, default: false },
    dist2KnowRange: { type: Number, default: null },
    dbDuplicate: { type: Boolean, default: false },
    spatialDuplicated: { type: Boolean, default: false },
    reported: [ReportedSchema],
    updated: [UpdatedSchema],
    created: [CreatedSchema],
    downloadDate: { type: String, default: null },
    resourceFolder: { type: String, default: null },
    resourceIncorporationDate: { type: String, default: null },
    resourceName: { type: String, default: null },
    source: { type: String, default: null },
    contributedRecord: { type: Boolean, default: false },
    override: { type: Boolean, default: false },
    privateData: { type: Number, in: [0, 1, 2], default: 0 },
    use: { type: Boolean, default: true },
    visualizationPrivileges: { type: Number, in: [0, 1, 2], default: 0 },
    isOutlier_bm: { type: Boolean },
    geoIssue_bm: { type: Boolean },
    idIssue_bm: { type: Boolean },
    oldTaxonomy_bm: { type: Boolean },
    inCaptivity_bm: { type: Boolean },
    otherIssues_bm: { type: Boolean },
    comments_bm: { type: String },
    citation_bm: { type: String },
    userId_bm: { type: Number },
    updatedDate: { type: Date },
    reportedDate: { type: Date }
  },
  { collection: 'records' }
);

export const Record = mongoose.model('Record', RecordSchema, 'records');
<commit_msg>contributedRecord data type changed to 'String' defaul value: null; in record model schema<commit_after>import mongoose from 'mongoose';
const Schema = mongoose.Schema;

// esquema para la corrección de registros biológicos
const UpdatedSchema = new Schema({
  speciesOriginal: { type: String },
  locality: { type: String },
  lat: { type: Number },
  lon: { type: Number },
  dd: { type: Number },
  mm: { type: Number },
  yyyy: { type: Number },
  updatedDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

// esquema para el reporte de errores en registros biológicos
const ReportedSchema = new Schema({
  // id: Schema.ObjectId,
  isOutlier_bm: { type: Boolean },
  geoIssue_bm: { type: Boolean },
  idIssue_bm: { type: Boolean },
  oldTaxonomy_bm: { type: Boolean },
  inCaptivity_bm: { type: Boolean },
  otherIssues_bm: { type: Boolean },
  comments_bm: { type: String },
  reportedDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

// esquema para la creación de registros biológicos
const CreatedSchema = new Schema({
  _id: { type: Schema.ObjectId },
  taxID: { type: Number },
  acceptedNameUsage: String,
  locality: { type: String },
  lat: { type: Number },
  lon: { type: Number },
  alt: { type: Number },
  basisOfRecord: { type: String },
  collector: { type: String },
  source: { type: String },
  comments_bm: { type: String },
  citation_bm: { type: String },
  createdDate: { type: Date, default: Date.now },
  userId_bm: { type: Number }
});

const RecordSchema = new Schema(
  {
    occurrenceID: { type: String, default: null },
    taxID: { type: Number, required: true },
    acceptedNameUsage: { type: String, required: true },
    species: { type: String, default: null },
    speciesOriginal: { type: String, default: null },
    continent: { type: String, default: null },
    country: { type: String, default: null },
    adm1: { type: String, default: null },
    adm2: { type: String, default: null },
    locality: { type: String, default: null },
    lat: { type: Number, min: -90, max: 90 },
    lon: { type: Number, min: -180, max: 180 },
    alt: { type: Number, default: null },
    demAltitude: { type: Number, min: 0, max: 8000, default: null },
    interpretedElevation: { type: Number, min: 0, max: 8000, default: null },
    cellID: { type: Number, min: 0, default: null },
    basisOfRecord: { type: String, default: null },
    catalogNumber: { type: String, default: null },
    colection: { type: String, default: null },
    collector: { type: String, default: null },
    institution: { type: String, default: null },
    url: { type: String, default: null },
    earliestDateCollected: { type: String, default: null },
    latestDateCollected: { type: String, default: null },
    dd: { type: Number, min: 1, max: 31, default: null },
    mm: { type: Number, min: 1, max: 12, default: null },
    yyyy: { type: Number, min: 1800, max: 2100, default: null },
    correctCountry: { type: Boolean, default: null },
    correctStateProvince: { type: Boolean, default: null },
    correctCounty: { type: Boolean, default: null },
    hasLocality: { type: Boolean, default: null },
    inUrbanArea: { type: Boolean, default: null },
    suggestedCountry: { type: String, default: null },
    suggestedCounty: { type: String, default: null },
    suggestedMunicipality: { type: String, default: null },
    suggestedStateProvince: { type: String, default: null },
    sourceLayer: { type: String, default: null },
    coordUncertaintyM: { type: Number, default: null },
    lowUncertainty: { type: Boolean, default: null },
    altitudinalOutlier: { type: Boolean, default: null },
    consistentAltitude: { type: Boolean, default: null },
    diferenceInAltitude: { type: Number, min: 0, max: 8000, default: null },
    environmentalOutlier: { type: Boolean, default: null },
    insideKnownDistribution: { type: Boolean, default: false },
    dist2KnowRange: { type: Number, default: null },
    dbDuplicate: { type: Boolean, default: false },
    spatialDuplicated: { type: Boolean, default: false },
    reported: [ReportedSchema],
    updated: [UpdatedSchema],
    created: [CreatedSchema],
    downloadDate: { type: String, default: null },
    resourceFolder: { type: String, default: null },
    resourceIncorporationDate: { type: String, default: null },
    resourceName: { type: String, default: null },
    source: { type: String, default: null },
    contributedRecord: { type: String, default: null },
    override: { type: Boolean, default: false },
    privateData: { type: Number, in: [0, 1, 2], default: 0 },
    use: { type: Boolean, default: true },
    visualizationPrivileges: { type: Number, in: [0, 1, 2], default: 0 },
    isOutlier_bm: { type: Boolean },
    geoIssue_bm: { type: Boolean },
    idIssue_bm: { type: Boolean },
    oldTaxonomy_bm: { type: Boolean },
    inCaptivity_bm: { type: Boolean },
    otherIssues_bm: { type: Boolean },
    comments_bm: { type: String },
    citation_bm: { type: String },
    userId_bm: { type: Number },
    updatedDate: { type: Date },
    reportedDate: { type: Date }
  },
  { collection: 'records' }
);

export const Record = mongoose.model('Record', RecordSchema, 'records');
<|endoftext|>