<commit_before>var TradeFeed = function (options) {
  var self       = this,
    apiHandler   = new ApiHandler(options.url),
    div          = d3.select('#'+options.id).attr("class","tradeFeed"),
    transactions = [],
    listener, dailyTimer, high, low, close, volume;

  var summary = div.append("div").attr('class', 'summary');
  var price = summary.append("div").attr('class', 'price');
  price.append("span").attr('class', 'amount');
  price.append("span").attr('class', 'pair');

  var daily = summary.append('div').attr('class','daily');
  daily.append('span').attr('class','high').html('H: --');
  daily.append('span').attr('class','low').html('L: --');
  daily.append('span').attr('class','volume').html('VOL: --');
  daily.append('label').html('(Last 24 hours)');

  var tableWrap = div.append('div').attr('class','table').append("div").attr("class","tableWrap");
  var table     = tableWrap.append('table');
  table.append('thead');
  table.append('tbody');

  var status = tableWrap.append("h4").attr('class','status');
  var loader = tableWrap.append("img")
      .attr("class", "loader")
      .attr("src", "assets/images/rippleThrobber.png")
      .style("opacity", 0);

//load the latest trade feed for the given pair
  this.loadPair = function (base, trade) {
    self.base  = base;
    self.trade = trade;
    high = low = close = volume = 0;

    if (listener) listener.updateViewOpts({base:base,trade:trade});
    else listener = new OffersExercisedListener({base:base,trade:trade}, handleTransaction);

/*
    //mock data
    transactions = [
      {time:moment(new Date()), amount:100, price:50, type:""},
      {time:moment(new Date()), amount:110, price:200, type:"bid"},
      {time:moment(new Date()), amount:120, price:300, type:"ask"},
      {time:moment(new Date()), amount:130, price:400, type:"ask"},
      {time:moment(new Date()), amount:140, price:500, type:"ask"},
      {time:moment(new Date()), amount:150, price:600, type:"bid"},
      {time:moment(new Date()), amount:100, price:50, type:"bid"},
      {time:moment(new Date()), amount:110, price:200, type:"bid"},
      {time:moment(new Date()), amount:120, price:300, type:"ask"},
      {time:moment(new Date()), amount:130, price:400, type:"ask"},
      {time:moment(new Date()), amount:140, price:500, type:"ask"},
      {time:moment(new Date()), amount:150, price:600, type:"bid"},
      {time:moment(new Date()), amount:100, price:50, type:"bid"},
      {time:moment(new Date()), amount:110, price:200, type:"bid"}
    ];
*/
    transactions = [];
    updateTrades();     //reset the last trade list
    updateDailyStats(); //reset the daily stats
    loadHistoricalData();
  }

//process incoming transaction from the live feed handler
  function handleTransaction (data) {

    var last = transactions[0];

    var trade = {
      time   : moment.utc(data.key.slice(2)),
      amount : data.value[1], //oddly backwards from my expectation
      price  : data.value[2],
      type   : ''
    }

    if (last && last.price<trade.price)      trade.type = 'ask';
    else if (last && last.price>trade.price) trade.type = 'bid';
    //else if (last)                         trade.type = last.type;

    transactions.unshift(trade);  //prepend trade
    transactions = transactions.slice(0,50);  //keep last 50

    if (trade.price>high) high = trade.price;
    if (trade.price<low)  low  = trade.price;
    close   = trade.price;
    volume += trade.amount;

    updateDailyStats();
    updateTrades();
    loader.style('opacity', 0);
  }

//update the display with new data
  function updateTrades () {
    status.html(transactions.length ? "" : "no recent trades");

    var rows = table.select("tbody").selectAll("tr")
      .data(transactions);

    var rowEnter = rows.enter().append("tr");

    rowEnter.append("td").attr("class","type");
    rowEnter.append("td").attr("class","amount");
    rowEnter.append("td").attr("class","time");
    rowEnter.append("td").attr("class","price");
    rows.exit().remove();

    rows.select(".type").attr('class', function(d){return "type "+d.type});
    rows.select(".amount").html(function(d){return valueFilter(d.amount)+" "+self.base.currency+""});
    rows.select(".time").html(function(d){return d.time.local().format('h:mm:ss a')});
    rows.select(".price").html(function(d){return valueFilter(d.price)});
  }

//make values human readable
  function valueFilter (d) {
    if (!d) return "&nbsp";
    value = ripple.Amount.from_human(d).to_human({
        precision      : 6,
        min_precision  : 0,
        max_sig_digits : 8
    });

    //its possible there are other reasons for value being empty, but right
    //now i am assuming it is below the minimum threshold
    if (!value) return "> 0.000001"; //must match min_precision variable
    var parts = value.split(".");
    var decimalPart = parts[1] ?  parts[1].replace(/0(0+)$/, '0') : null;
    value = decimalPart && decimalPart.length > 0 ? parts[0] + "." + decimalPart : parts[0];
    return value;
  }

//load price and volume stats from the last 24hours
  function loadDailyStats () {
    var now  = moment();
    var then = moment().subtract(1, 'days');

    if (self.requestDaily) self.requestDaily.abort();
    self.requestDaily = apiHandler.offersExercised({
      startTime     : then.toDate(),
      endTime       : now.toDate(),
      timeIncrement : 'all',
      base          : self.base,
      trade         : self.trade

    }, function(data){

      if (data && data.length) {
        //TODO: should be comparing the existing high and low
        high   = data[0].high;
        low    = data[0].low;
        volume = data[0].volume;
        if (!close) close = data[0].close; //dont overwrite existing
      }

      updateDailyStats();

    }, function (error){
      console.log(error);
    });
  }

//display 24 hour stats from the known values
  function updateDailyStats () {
      daily.select(".high").html("H: "+valueFilter(high));
      daily.select(".low").html("L: "+valueFilter(low));
      daily.select(".volume").html("VOL: "+valueFilter(volume)+""+self.base.currency+"");
      price.select(".amount").html(valueFilter(close));
      price.select(".pair").html(self.base.currency+"/"+self.trade.currency);
  }

//load latest trades historical data from the API
  function loadHistoricalData() {
    if (dailyTimer) clearInterval(dailyTimer);
    dailyTimer = setInterval(loadDailyStats, 180000);
    loadDailyStats();

    loader.transition().style('opacity',1);
    status.html("");

    var now  = moment();
    var then = moment().subtract(1, 'days');

    if (self.request) self.request.abort();
    self.request = apiHandler.offersExercised({
      startTime : then.toDate(),
      endTime   : now.toDate(),
      reduce    : false,
      base      : self.base,
      trade     : self.trade,
      limit     : 50

    }, function(data){

      loader.transition().style('opacity',0);
      transactions = transactions.concat(data).slice(0,50);
      updateTrades()

    }, function (error){

      if (!transactions.length) //trades may have come through the live feed
        status.html(error.text ? error.text : "Unable to load data");

      loader.transition().style('opacity',0);
      console.log(error);
    });
  }

//stop the live feed and the daily stats updater
  this.suspend = function () {
    if (listener) listener.stopListener();
    if (dailyTimer) clearInterval(dailyTimer);
  }
}<commit_msg>reverse order of trade feed because of API change<commit_after>var TradeFeed = function (options) {
  var self       = this,
    apiHandler   = new ApiHandler(options.url),
    div          = d3.select('#'+options.id).attr("class","tradeFeed"),
    transactions = [],
    listener, dailyTimer, high, low, close, volume;

  var summary = div.append("div").attr('class', 'summary');
  var price = summary.append("div").attr('class', 'price');
  price.append("span").attr('class', 'amount');
  price.append("span").attr('class', 'pair');

  var daily = summary.append('div').attr('class','daily');
  daily.append('span').attr('class','high').html('H: --');
  daily.append('span').attr('class','low').html('L: --');
  daily.append('span').attr('class','volume').html('VOL: --');
  daily.append('label').html('(Last 24 hours)');

  var tableWrap = div.append('div').attr('class','table').append("div").attr("class","tableWrap");
  var table     = tableWrap.append('table');
  table.append('thead');
  table.append('tbody');

  var status = tableWrap.append("h4").attr('class','status');
  var loader = tableWrap.append("img")
      .attr("class", "loader")
      .attr("src", "assets/images/rippleThrobber.png")
      .style("opacity", 0);

//load the latest trade feed for the given pair
  this.loadPair = function (base, trade) {
    self.base  = base;
    self.trade = trade;
    high = low = close = volume = 0;

    if (listener) listener.updateViewOpts({base:base,trade:trade});
    else listener = new OffersExercisedListener({base:base,trade:trade}, handleTransaction);

/*
    //mock data
    transactions = [
      {time:moment(new Date()), amount:100, price:50, type:""},
      {time:moment(new Date()), amount:110, price:200, type:"bid"},
      {time:moment(new Date()), amount:120, price:300, type:"ask"},
      {time:moment(new Date()), amount:130, price:400, type:"ask"},
      {time:moment(new Date()), amount:140, price:500, type:"ask"},
      {time:moment(new Date()), amount:150, price:600, type:"bid"},
      {time:moment(new Date()), amount:100, price:50, type:"bid"},
      {time:moment(new Date()), amount:110, price:200, type:"bid"},
      {time:moment(new Date()), amount:120, price:300, type:"ask"},
      {time:moment(new Date()), amount:130, price:400, type:"ask"},
      {time:moment(new Date()), amount:140, price:500, type:"ask"},
      {time:moment(new Date()), amount:150, price:600, type:"bid"},
      {time:moment(new Date()), amount:100, price:50, type:"bid"},
      {time:moment(new Date()), amount:110, price:200, type:"bid"}
    ];
*/
    transactions = [];
    updateTrades();     //reset the last trade list
    updateDailyStats(); //reset the daily stats
    loadHistoricalData();
  }

//process incoming transaction from the live feed handler
  function handleTransaction (data) {

    var last = transactions[0];

    var trade = {
      time   : moment.utc(data.key.slice(2)),
      amount : data.value[1], //oddly backwards from my expectation
      price  : data.value[2],
      type   : ''
    }

    if (last && last.price<trade.price)      trade.type = 'ask';
    else if (last && last.price>trade.price) trade.type = 'bid';
    //else if (last)                         trade.type = last.type;

    transactions.unshift(trade);  //prepend trade
    transactions = transactions.slice(0,50);  //keep last 50

    if (trade.price>high) high = trade.price;
    if (trade.price<low)  low  = trade.price;
    close   = trade.price;
    volume += trade.amount;

    updateDailyStats();
    updateTrades();
    loader.style('opacity', 0);
  }

//update the display with new data
  function updateTrades () {
    status.html(transactions.length ? "" : "no recent trades");

    var rows = table.select("tbody").selectAll("tr")
      .data(transactions);

    var rowEnter = rows.enter().append("tr");

    rowEnter.append("td").attr("class","type");
    rowEnter.append("td").attr("class","amount");
    rowEnter.append("td").attr("class","time");
    rowEnter.append("td").attr("class","price");
    rows.exit().remove();

    rows.select(".type").attr('class', function(d){return "type "+d.type});
    rows.select(".amount").html(function(d){return valueFilter(d.amount)+" "+self.base.currency+""});
    rows.select(".time").html(function(d){return d.time.local().format('h:mm:ss a')});
    rows.select(".price").html(function(d){return valueFilter(d.price)});
  }

//make values human readable
  function valueFilter (d) {
    if (!d) return "&nbsp";
    value = ripple.Amount.from_human(d).to_human({
        precision      : 6,
        min_precision  : 0,
        max_sig_digits : 8
    });

    //its possible there are other reasons for value being empty, but right
    //now i am assuming it is below the minimum threshold
    if (!value) return "> 0.000001"; //must match min_precision variable
    var parts = value.split(".");
    var decimalPart = parts[1] ?  parts[1].replace(/0(0+)$/, '0') : null;
    value = decimalPart && decimalPart.length > 0 ? parts[0] + "." + decimalPart : parts[0];
    return value;
  }

//load price and volume stats from the last 24hours
  function loadDailyStats () {
    var now  = moment();
    var then = moment().subtract(1, 'days');

    if (self.requestDaily) self.requestDaily.abort();
    self.requestDaily = apiHandler.offersExercised({
      startTime     : then.toDate(),
      endTime       : now.toDate(),
      timeIncrement : 'all',
      base          : self.base,
      trade         : self.trade

    }, function(data){

      if (data && data.length) {
        //TODO: should be comparing the existing high and low
        high   = data[0].high;
        low    = data[0].low;
        volume = data[0].volume;
        if (!close) close = data[0].close; //dont overwrite existing
      }

      updateDailyStats();

    }, function (error){
      console.log(error);
    });
  }

//display 24 hour stats from the known values
  function updateDailyStats () {
      daily.select(".high").html("H: "+valueFilter(high));
      daily.select(".low").html("L: "+valueFilter(low));
      daily.select(".volume").html("VOL: "+valueFilter(volume)+""+self.base.currency+"");
      price.select(".amount").html(valueFilter(close));
      price.select(".pair").html(self.base.currency+"/"+self.trade.currency);
  }

//load latest trades historical data from the API
  function loadHistoricalData() {
    if (dailyTimer) clearInterval(dailyTimer);
    dailyTimer = setInterval(loadDailyStats, 180000);
    loadDailyStats();

    loader.transition().style('opacity',1);
    status.html("");

    var now  = moment();
    var then = moment().subtract(1, 'days');

    if (self.request) self.request.abort();
    self.request = apiHandler.offersExercised({
      startTime  : then.toDate(),
      endTime    : now.toDate(),
      reduce     : false,
      base       : self.base,
      trade      : self.trade,
      descending : true,
      limit      : 50

    }, function(data){

      loader.transition().style('opacity',0);
      transactions = transactions.concat(data).slice(0,50);
      updateTrades()

    }, function (error){

      if (!transactions.length) //trades may have come through the live feed
        status.html(error.text ? error.text : "Unable to load data");

      loader.transition().style('opacity',0);
      console.log(error);
    });
  }

//stop the live feed and the daily stats updater
  this.suspend = function () {
    if (listener) listener.stopListener();
    if (dailyTimer) clearInterval(dailyTimer);
  }
}<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');

gulp.task('watch', function() {
  var testFiles = [
    'es6/**/*',
    'es6/test/**/*',
    'package.json',
    '**/.jshintrc'
  ];

  gulp.watch(['es6/**/*'], ['test', 'transpile']);
});
<commit_msg>update to watch task<commit_after>'use strict';

var gulp = require('gulp');

gulp.task('watch', function() {
  var testFiles = [
    'es6/**/*',
    'es6/test/**/*',
    'package.json',
    '**/.jshintrc'
  ];

  gulp.watch(testFiles, ['test']);
});

gulp.task('watch-build', function() {
  gulp.watch(['es6/**/*'], ['test', 'transpile']);
});
<|endoftext|>


<commit_before>import ParserError from './parser_error';

class Parser {
  static processSetRequest(tokens) {
    if (tokens.length === 4) {
      const flag = tokens[3].toUpperCase();
      if (flag !== 'NX' && flag !== 'XX') {
        throw new ParserError("ParseError: syntax error - invalid flag on SET command");
      } else {
        return tokens;
      }
    } else if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for SET command");
    }
  }

  static processGetRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for GET command");
    }
  }

  static processAppendRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for APPEND command");
    }
  }

  static processStrlenRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for STRLEN command");
    }
  }

  static processTouchRequest(tokens) {
    if (tokens.length >= 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for TOUCH command");
    }
  }

  static processIncrRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for INCR command");
    }
  }

  static processDecrRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for DECR command");
    }
  }

  static processExistsRequest(tokens) {
    if (tokens.length ===  2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for EXISTS command");
    }
  }

  static processRenameRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RENAME command");
    }
  }

  static processRenameNXRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RENAMENX command");
    }
  }

  static processTypeRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for TYPE command");
    }
  }

  static processDelRequest(tokens) {
    if (tokens.length >= 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for DEL command");
    }
  }

  static processLINDEXRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LINDEX command");
    }
  }

  static processLREMRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LREM command");
    }
  }

  static processLLENRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LLEN command");
    }
  }

  static processLINSERTRequest(tokens) {
    if (tokens.length === 5) {
      const flag = tokens[2].toUpperCase();
      if (flag !== 'BEFORE' && flag !== 'AFTER') {
        throw new ParserError("ParseError: syntax error - invalid flag on LINSERT command");
      } else {
        return tokens;
      }
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LINSERT command");
    }
  }

  static processLPUSHRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LPUSH command");
    }
  }

  static processRPUSHRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RPUSH command");
    }
  }

  static processLPOPRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LPOP command");
    }
  }

  static processRPOPRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RPOP command");
    }
  }

  static processHSETRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSET command");
    }
  }

  static processHVALSRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HVALS command");
    }
  }

  static processHSTRLENRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSTRLEN command");
    }
  }

  static processHMSETRequest(tokens) {
    if (tokens.length >= 4 && tokens.length % 2 === 0) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HMSET command");
    }
  }

  static processHDELRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HDEL command");
    }
  }

  static processHGETRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HGET command");
    }
  }

  static processHGETALLRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HGETALL command");
    }
  }

  static processHLENRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HLEN command");
    }
  }

  static processHSETNXRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSETNX command");
    }
  }

  static processHMGETRequest(tokens) {
    if (tokens.length >= 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HMGET command");
    }
  }

  static processHINCRBYRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HINCRBY command");
    }
  }

  static processHKEYSRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HKEYS command");
    }
  }

  static chomp(s) {
    return s.slice().replace(/[\n|\r]*$/, '');
  }

  static convertRespStringToTokens(s) {
    let numElems = 0;

    if(!s.endsWith('\r\n')) {
      throw new ParserError("ParserError: doesn't have CRLF suffix.");
    }

    s = this.chomp(s);
    let stringArray = s.split('\r\n');

    if (stringArray[0][0] !== '*') {
      throw new ParserError("ParserError: doesn't start with *.");
    } else {
      const numElemsStr = stringArray[0].slice(1);
      if (numElemsStr.match(/[^0-9]/)) {
        throw new ParserError("ParserError: * followed by non-number.");
      } else {
        numElems = parseInt(numElemsStr);
      }
    }

    if ((numElems * 2) !== (stringArray.length - 1)) {
      throw new ParserError("ParserError: mismatch between specified number of elements and actual number of elements");
    } else {
      return this.processRespArrayElems(numElems, stringArray.slice(1));
    }
  }

  static processRespArrayElems(numElems, stringArray) {
    const tokens = [];
    for (let idx = 0; idx < (numElems * 2); idx += 2) {
      const arrayLengthElem = stringArray[idx];
      const arrayStringElem = stringArray[idx + 1];
      let expectedStringLength;

      if (arrayLengthElem[0] !== '$') {
        throw new ParserError("$ sign expected when reading length of array elem " + (idx + 1));
      } else {
        const numElemsStr = stringArray[idx].slice(1);
        if (numElemsStr.match(/[^0-9]/)) {
          throw new ParserError("non-number following $ for array elem " + (idx + 1));
        } else {
          expectedStringLength = parseInt(numElemsStr);
        }

        if (arrayStringElem.length !== expectedStringLength) {
          throw new ParserError("mismatch between length of RespArray element and element itself at elem " + (idx + 2));
        } else {
          tokens.push(arrayStringElem);
        }
      }
    }

    return tokens;
  }

  static processIncomingString(s) {
    const tokens = this.convertRespStringToTokens(s);
    const command = tokens[0].toUpperCase();

    if (!commandMap[command]) {
      throw new ParserError("ParserError: Invalid command.");
    }

    return commandMap[command](tokens);
  }
}

const commandMap = {
  'GET': Parser.processGetRequest,
  'SET': Parser.processSetRequest,
  'APPEND': Parser.processAppendRequest,
  'STRLEN': Parser.processStrlenRequest,
  'TOUCH': Parser.processTouchRequest,
  'INCR': Parser.processIncrRequest,
  'DECR': Parser.processDecrRequest,
  'EXISTS': Parser.processExistsRequest,
  'RENAME': Parser.processRenameRequest,
  'RENAMENX': Parser.processRenameNXRequest,
  'TYPE': Parser.processTypeRequest,
  'DEL': Parser.processDelRequest,
  'LINDEX': Parser.processLINDEXRequest,
  'LREM': Parser.processLREMRequest,
  'LLEN': Parser.processLLENRequest,
  'LINSERT': Parser.processLINSERTRequest,
  'LPUSH': Parser.processLPUSHRequest,
  'RPUSH': Parser.processRPUSHRequest,
  'LPOP': Parser.processLPOPRequest,
  'RPOP': Parser.processRPOPRequest,
  'HSET': Parser.processHSETRequest,
  'HVALS': Parser.processHVALSRequest,
  'HSTRLEN': Parser.processHSTRLENRequest,
  'HMSET': Parser.processHMSETRequest,
  'HDEL': Parser.processHDELRequest,
  'HGET': Parser.processHGETRequest,
  'HGETALL': Parser.processHGETALLRequest,
  'HLEN': Parser.processHLENRequest,
  'HSETNX': Parser.processHSETNXRequest,
  'HMGET': Parser.processHMGETRequest,
  'HINCRBY': Parser.processHINCRBYRequest,
  'HKEYS': Parser.processHKEYSRequest,
};

export { commandMap, Parser };
<commit_msg>fixed lpush parser method that accepted three rather than 3+ arguments<commit_after>import ParserError from './parser_error';

class Parser {
  static processSetRequest(tokens) {
    if (tokens.length === 4) {
      const flag = tokens[3].toUpperCase();
      if (flag !== 'NX' && flag !== 'XX') {
        throw new ParserError("ParseError: syntax error - invalid flag on SET command");
      } else {
        return tokens;
      }
    } else if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for SET command");
    }
  }

  static processGetRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for GET command");
    }
  }

  static processAppendRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for APPEND command");
    }
  }

  static processStrlenRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for STRLEN command");
    }
  }

  static processTouchRequest(tokens) {
    if (tokens.length >= 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for TOUCH command");
    }
  }

  static processIncrRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for INCR command");
    }
  }

  static processDecrRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for DECR command");
    }
  }

  static processExistsRequest(tokens) {
    if (tokens.length ===  2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for EXISTS command");
    }
  }

  static processRenameRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RENAME command");
    }
  }

  static processRenameNXRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RENAMENX command");
    }
  }

  static processTypeRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for TYPE command");
    }
  }

  static processDelRequest(tokens) {
    if (tokens.length >= 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for DEL command");
    }
  }

  static processLINDEXRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LINDEX command");
    }
  }

  static processLREMRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LREM command");
    }
  }

  static processLLENRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LLEN command");
    }
  }

  static processLINSERTRequest(tokens) {
    if (tokens.length === 5) {
      const flag = tokens[2].toUpperCase();
      if (flag !== 'BEFORE' && flag !== 'AFTER') {
        throw new ParserError("ParseError: syntax error - invalid flag on LINSERT command");
      } else {
        return tokens;
      }
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LINSERT command");
    }
  }

  static processLPUSHRequest(tokens) {
    if (tokens.length >= 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LPUSH command");
    }
  }

  static processRPUSHRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RPUSH command");
    }
  }

  static processLPOPRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for LPOP command");
    }
  }

  static processRPOPRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for RPOP command");
    }
  }

  static processHSETRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSET command");
    }
  }

  static processHVALSRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HVALS command");
    }
  }

  static processHSTRLENRequest(tokens) {
    if (tokens.length === 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSTRLEN command");
    }
  }

  static processHMSETRequest(tokens) {
    if (tokens.length >= 4 && tokens.length % 2 === 0) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HMSET command");
    }
  }

  static processHDELRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HDEL command");
    }
  }

  static processHGETRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HGET command");
    }
  }

  static processHGETALLRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HGETALL command");
    }
  }

  static processHLENRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HLEN command");
    }
  }

  static processHSETNXRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HSETNX command");
    }
  }

  static processHMGETRequest(tokens) {
    if (tokens.length >= 3) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HMGET command");
    }
  }

  static processHINCRBYRequest(tokens) {
    if (tokens.length === 4) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HINCRBY command");
    }
  }

  static processHKEYSRequest(tokens) {
    if (tokens.length === 2) {
      return tokens;
    } else {
      throw new ParserError("ParseError: Wrong number of arguments for HKEYS command");
    }
  }

  static chomp(s) {
    return s.slice().replace(/[\n|\r]*$/, '');
  }

  static convertRespStringToTokens(s) {
    let numElems = 0;

    if(!s.endsWith('\r\n')) {
      throw new ParserError("ParserError: doesn't have CRLF suffix.");
    }

    s = this.chomp(s);
    let stringArray = s.split('\r\n');

    if (stringArray[0][0] !== '*') {
      throw new ParserError("ParserError: doesn't start with *.");
    } else {
      const numElemsStr = stringArray[0].slice(1);
      if (numElemsStr.match(/[^0-9]/)) {
        throw new ParserError("ParserError: * followed by non-number.");
      } else {
        numElems = parseInt(numElemsStr);
      }
    }

    if ((numElems * 2) !== (stringArray.length - 1)) {
      throw new ParserError("ParserError: mismatch between specified number of elements and actual number of elements");
    } else {
      return this.processRespArrayElems(numElems, stringArray.slice(1));
    }
  }

  static processRespArrayElems(numElems, stringArray) {
    const tokens = [];
    for (let idx = 0; idx < (numElems * 2); idx += 2) {
      const arrayLengthElem = stringArray[idx];
      const arrayStringElem = stringArray[idx + 1];
      let expectedStringLength;

      if (arrayLengthElem[0] !== '$') {
        throw new ParserError("$ sign expected when reading length of array elem " + (idx + 1));
      } else {
        const numElemsStr = stringArray[idx].slice(1);
        if (numElemsStr.match(/[^0-9]/)) {
          throw new ParserError("non-number following $ for array elem " + (idx + 1));
        } else {
          expectedStringLength = parseInt(numElemsStr);
        }

        if (arrayStringElem.length !== expectedStringLength) {
          throw new ParserError("mismatch between length of RespArray element and element itself at elem " + (idx + 2));
        } else {
          tokens.push(arrayStringElem);
        }
      }
    }

    return tokens;
  }

  static processIncomingString(s) {
    const tokens = this.convertRespStringToTokens(s);
    const command = tokens[0].toUpperCase();

    if (!commandMap[command]) {
      throw new ParserError("ParserError: Invalid command.");
    }

    return commandMap[command](tokens);
  }
}

const commandMap = {
  'GET': Parser.processGetRequest,
  'SET': Parser.processSetRequest,
  'APPEND': Parser.processAppendRequest,
  'STRLEN': Parser.processStrlenRequest,
  'TOUCH': Parser.processTouchRequest,
  'INCR': Parser.processIncrRequest,
  'DECR': Parser.processDecrRequest,
  'EXISTS': Parser.processExistsRequest,
  'RENAME': Parser.processRenameRequest,
  'RENAMENX': Parser.processRenameNXRequest,
  'TYPE': Parser.processTypeRequest,
  'DEL': Parser.processDelRequest,
  'LINDEX': Parser.processLINDEXRequest,
  'LREM': Parser.processLREMRequest,
  'LLEN': Parser.processLLENRequest,
  'LINSERT': Parser.processLINSERTRequest,
  'LPUSH': Parser.processLPUSHRequest,
  'RPUSH': Parser.processRPUSHRequest,
  'LPOP': Parser.processLPOPRequest,
  'RPOP': Parser.processRPOPRequest,
  'HSET': Parser.processHSETRequest,
  'HVALS': Parser.processHVALSRequest,
  'HSTRLEN': Parser.processHSTRLENRequest,
  'HMSET': Parser.processHMSETRequest,
  'HDEL': Parser.processHDELRequest,
  'HGET': Parser.processHGETRequest,
  'HGETALL': Parser.processHGETALLRequest,
  'HLEN': Parser.processHLENRequest,
  'HSETNX': Parser.processHSETNXRequest,
  'HMGET': Parser.processHMGETRequest,
  'HINCRBY': Parser.processHINCRBYRequest,
  'HKEYS': Parser.processHKEYSRequest,
};

export { commandMap, Parser };
<|endoftext|>


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

  angular.module('foundation.core.animation', [])
    .service('FoundationAnimation', FoundationAnimation)
  ;

  function FoundationAnimation() {
    var animations = [];
    var service = {};

    var initClasses        = ['ng-enter', 'ng-leave'];
    var activeClasses      = ['ng-enter-active', 'ng-leave-active'];
    var activeGenericClass = 'is-active';
    var events = [
      'webkitAnimationEnd', 'mozAnimationEnd',
      'MSAnimationEnd', 'oanimationend',
      'animationend', 'webkitTransitionEnd',
      'otransitionend', 'transitionend'
    ];

    service.animate = animate;
    service.toggleAnimation = toggleAnimation;

    return service;

    function toggleAnimation(element, futureState) {
      if(futureState) {
        element.addClass(activeGenericClass);
      } else {
        element.removeClass(activeGenericClass);
      }
    }

    function animate(element, futureState, animationIn, animationOut) {
      var timedOut = true;
      var self = this;
      self.cancelAnimation = cancelAnimation;

      var animationClass = futureState ? animationIn: animationOut;
      var activation = futureState;
      var initClass = activation ? initClasses[0] : initClasses[1];
      var activeClass = activation ? activeClasses[0] : activeClasses[1];
      //stop animation
      registerElement(element);
      reset();
      element.addClass(animationClass);
      element.addClass(initClass);

      element.addClass(activeGenericClass);

      //force a "tick"
      reflow();

      //activate
      element[0].style.transitionDuration = '';
      element.addClass(activeClass);

      element.on(events.join(' '), eventHandler);

      function eventHandler(e) {
        if (element[0] === e.path[0]) {
          clearTimeout(animationTimeout);
          finishAnimation();
        }
      }

      var animationTimeout = setTimeout(function() {
        if(timedOut) {
          finishAnimation();
        }
      }, 3000);

      function finishAnimation() {
        deregisterElement(element);
        reset(); //reset all classes
        element[0].style.transitionDuration = '';
        element.removeClass(!activation ? activeGenericClass : ''); //if not active, remove active class
        reflow();
        timedOut = false;
        element.off(events.join(' '), eventHandler);
      }

      function cancelAnimation(element) {
        deregisterElement(element);
        angular.element(element).off(events.join(' ')); //kill all animation event handlers
        timedOut = false;
      }

      function registerElement(el) {
        var elObj = {
          el: el,
          animation: self
        };

        //kill in progress animations
        var inProgress = animations.filter(function(obj) {
          return obj.el === el;
        });
        if(inProgress.length > 0) {
          var target = inProgress[0].el[0];

          inProgress[0].animation.cancelAnimation(target);
        }

        animations.push(elObj);
      }

      function deregisterElement(el) {
        var index;
        var currentAnimation = animations.filter(function(obj, ind) {
          if(obj.el === el) {
            index = ind;
          }
        });

        if(index >= 0) {
          animations.splice(index, 1);
        }

      }

      function reflow() {
        return element[0].offsetWidth;
      }

      function reset() {
        element[0].style.transitionDuration = 0;
        element.removeClass(initClasses.join(' ') + ' ' + activeClasses.join(' ') + ' ' + animationIn + ' ' + animationOut);
      }
    }
  }

})();
<commit_msg>javascript adjustment to animations for issue 481<commit_after>(function() {
  'use strict';

  angular.module('foundation.core.animation', [])
    .service('FoundationAnimation', FoundationAnimation)
  ;

  function FoundationAnimation() {
    var animations = [];
    var service = {};

    var initClasses        = ['ng-enter', 'ng-leave'];
    var activeClasses      = ['ng-enter-active', 'ng-leave-active'];
    var activeGenericClass = 'is-active';
    var events = [
      'webkitAnimationEnd', 'mozAnimationEnd',
      'MSAnimationEnd', 'oanimationend',
      'animationend', 'webkitTransitionEnd',
      'otransitionend', 'transitionend'
    ];

    service.animate = animate;
    service.toggleAnimation = toggleAnimation;

    return service;

    function toggleAnimation(element, futureState) {
      if(futureState) {
        element.addClass(activeGenericClass);
      } else {
        element.removeClass(activeGenericClass);
      }
    }

    function animate(element, futureState, animationIn, animationOut) {
      var timedOut = true;
      var self = this;
      self.cancelAnimation = cancelAnimation;

      var animationClass = futureState ? animationIn: animationOut;
      var activation = futureState;
      var initClass = activation ? initClasses[0] : initClasses[1];
      var activeClass = activation ? activeClasses[0] : activeClasses[1];
      //stop animation
      registerElement(element);
      reset();
      element.addClass(animationClass);
      element.addClass(initClass);

      element.addClass(activeGenericClass);

      //force a "tick"
      reflow();

      //activate
      element[0].style.transitionDuration = '';
      element.addClass(activeClass);

      element.on(events.join(' '), eventHandler);

      function eventHandler(e) {
        if (element[0] === e.target) {
          clearTimeout(animationTimeout);
          finishAnimation();
        }
      }

      var animationTimeout = setTimeout(function() {
        if(timedOut) {
          finishAnimation();
        }
      }, 3000);

      function finishAnimation() {
        deregisterElement(element);
        reset(); //reset all classes
        element[0].style.transitionDuration = '';
        element.removeClass(!activation ? activeGenericClass : ''); //if not active, remove active class
        reflow();
        timedOut = false;
        element.off(events.join(' '), eventHandler);
      }

      function cancelAnimation(element) {
        deregisterElement(element);
        angular.element(element).off(events.join(' ')); //kill all animation event handlers
        timedOut = false;
      }

      function registerElement(el) {
        var elObj = {
          el: el,
          animation: self
        };

        //kill in progress animations
        var inProgress = animations.filter(function(obj) {
          return obj.el === el;
        });
        if(inProgress.length > 0) {
          var target = inProgress[0].el[0];

          inProgress[0].animation.cancelAnimation(target);
        }

        animations.push(elObj);
      }

      function deregisterElement(el) {
        var index;
        var currentAnimation = animations.filter(function(obj, ind) {
          if(obj.el === el) {
            index = ind;
          }
        });

        if(index >= 0) {
          animations.splice(index, 1);
        }

      }

      function reflow() {
        return element[0].offsetWidth;
      }

      function reset() {
        element[0].style.transitionDuration = 0;
        element.removeClass(initClasses.join(' ') + ' ' + activeClasses.join(' ') + ' ' + animationIn + ' ' + animationOut);
      }
    }
  }

})();
<|endoftext|>


<commit_before>import {Promise} from 'bluebird'
import {Registry} from './registry'
import {Set} from 'immutable'
import * as u from './useful'
import {read, set, remove, push} from './firebase_useful'
import log4js from 'log4js'
import {TODO_TRX_PATH, DONE_TRX_PATH, INTERNAL_TRX_PATH} from './settings'

let logger = log4js.getLogger('transactor')

// if the logging is not configured, use densible default
// whether logging was configured or not is determined
// by log4js.configured singleton
function configureLogging() {
  if (!log4js.configured) {
    log4js.configure({
      appenders: [{
        type: 'console',
        layout: {
          type: 'pattern',
          pattern: '[%[%5.5p%]] - %m'
        }
      }]
    })
    logger.setLevel('INFO')
  }
}

class AbortError {
  constructor(msg) {
    this.msg = msg
  }
}

class UserAbort {
  constructor(msg) {
    this.msg = msg
  }
}

/***
 * ## Server
 *
 * #### transactor(firebase, handlers, options = {})
 *
 *   Starts transactor.
 *
 *     args:
 *       firebase: firebase ref
 *       handlers: {String type: transaction_handler} map
 *       options:
 *         todoTrxRef: Firebase ref, where new transactions appear in Firebase
 *         closedTrxRef: Firebase ref, where finished transactions are put
 *         internalRef: Firebase ref, Transactor put pending writes here
 *         trCountLimit: int, concurency ammount; how many transactions should be processed at once
 *         rescheduleDelay: int, how long to wait (in ms) before re-scheduling aborted transaction
 *
 *     returns: handler = {stop, trSummary (for debug & test purposes)},
 *
 * #### stop()
 *
 *   Stops transactor
 *
 * #### transaction_handler({abort, change, push, read, set, update}, data)
 *
 *   User defined function, transaction handler associated to certain transaction type.
 *
 *   First argument are custom firebase-access functions that you can use to manipulate DB, the second argument is
 *   'data' which corresponds to submitTransaction's 'data'. Author of transaction_handler must
 *   return Promise that fulfills when the transaction is finished. If the Promise got rejected, the
 *   transaction gets to the similar state as if it was aborted by user by calling 'abort'; the
 *   Promise returned by submitTransaction will fulfill with {error: message}
 *
 * Most of Firebase-accessors functions accept keypath argument. Unlike Firebase reference, this is
 * specified as a simple array of keys, i.e. ['user', 123, 'name'] may represent path to users name.
 *
 * #### read(keypath)
 *   Reads the value.
 *     returns: Promise(value_read)
 *
 * #### set(keypath, val)
 *   Sets the value. This is synchronous process; transactor just remembers the write that should
 *   happen. Returns nothing.
 *
 * #### push(keypath, val)
 *   Analogous to Firebase's push
 *
 * #### change(keypath, fn)
 *   Read the value from given location, then set this location to fn(value)
 *
 * #### update(keypath, obj)
 *   Update the location's value with all k,v pair present in object obj. Since this is just a bunch
 *   of sets, it's also synchronous operation.
 *
 * #### abort(msg)
 * Aborts the transaction. None modification done will be saved to the DB, the transaction will be
 * understood as finished and the transactor won't try to repeat it. The Promise returned by
 * submitTransaction() call (on client side) will fulfill with {userError: msg}
 * Argument 'msg' is any object serializable by Firebase (ususally the simple String)
 *
 * #### getId()
 *   Convenience function, returns unique Firebase ID.
 *
 ***/
export function transactor(firebase, handlers, options = {}) {

  const {
    todoTrxRef = firebase.child(TODO_TRX_PATH),
    closedTrxRef = firebase.child(DONE_TRX_PATH),
    internalRef = firebase.child(INTERNAL_TRX_PATH),
    internalWritesRef = internalRef.child('writes'),
    trCountLimit = 50,
    rescheduleDelay = 100
  } = options

  if (!log4js.configured) configureLogging()

  const runs = {} // run id mapped to trData
  const waiting = []
  const trSummary = {aborted: 0, tried: 0, processed: 0}
  const registry = new Registry()
  let nextTrId = 0
  let nextRunId = 0
  let trCount = 0

  function _abort(id) {
    registry.cleanup(id)
    delete runs[id]
  }

  function refFromPath(path) {
    return firebase.child(path.join('/'))
  }

  function pushWaiting(val) {
    if (val == null) {
      throw new Error('val should be trx, not null/undefined')
    }
    waiting.push(val)
    tryConsumeWaiting()
  }

  function scheduleLater(trData) {
    setTimeout(() => {pushWaiting(trData)}, rescheduleDelay)
  }

  // --abortAndReschedule
  function abortAndReschedule(id) {
    if (runs[id] == null) {
      throw new Error('shouldnt abort transaction that is already aborted')
    }
    logger.debug(`CLEANUP & ABORT : tr no ${id}`)
    trSummary['aborted'] += 1
    scheduleLater(runs[id])
    _abort(id)
  }

  // --processTr
  function processTr(id) {
    logger.debug(`starting process ${id}`)
    const {type, data} = runs[id]
    const handler = handlers[type]
    if (handler == null) {
      throw new Error(`handler for type ${type} does not exist. Full trData: ${runs[id]}`)
    }

    if (runs[id] == null) {
      throw new Error('given run does not exist!')
    }

    return Promise.resolve()
      .then(() => {
        logger.debug(`starting handler ${id}`)
        trSummary['tried'] += 1
        return handler({
          abort: userAbort,
          change: userChange,
          getId: userGetId,
          push: userPush,
          read: userRead,
          set: userSet,
          update: userUpdate,
        }, data)
      })
      .catch((err) => {
        if (!(err instanceof AbortError)) {
          if (err instanceof UserAbort) {
            logger.debug(`user abort ${id}, msg: ${err.msg}`)
            return {userError: err.msg}
          } else {
            if (!process.env.supressErrors) {
              logger.error(`Unknown error abort ${err} ${err.stack}`)
              console.error(err)
              console.error(err.stack)
            }
            return {error: `${err}`}
          }
        }
        throw err
      })
      .then((result) => {
        // even if no Error is thrown, the transaction might be aborted in the
        // very last moment. Better check for it (userabort is not relevant now, as
        // we want to process such transaction)
        if (runs[id] != null) {
          logger.debug(`FINISH: tr no ${id}`)
          let userAborted = runs[id].status === 'useraborted'
          let writes = userAborted ? [] : registry.writesByTrx.get(id, [])
          let writesRef = push(internalWritesRef, {})
          trSummary['processed'] += 1
          runs[id].status = 'finishing'
          set(writesRef, writes)
          writes.forEach((write) => {
            // TODO immutable destructuring
            set(refFromPath(write.get('path')), write.get('value'))
          })
          let trData = runs[id]
          remove(writesRef)
          try {
            // TODO handle this better (some parts of result might get lost
            // here, so warn user about it)
            result = JSON.parse(JSON.stringify({result}))
          } catch (e) {
            let msg = `Error for transaction id=${id}, result cannot be saved\n to firebase (result=${result})`
            throw new Error(msg)
          }
          set(closedTrxRef.child(trData.frbId), {data: trData, ...result})
          remove(todoTrxRef.child(trData.frbId))
          registry.cleanup(id)
          delete runs[id]
        }
      })
      .catch((err) => {
        if (err instanceof AbortError) {
          logger.debug(`abort error ${id}`)
          return
        }
        throw err
      })

    function checkAbort() {
      if (runs[id] == null || runs[id].status === 'useraborted') {
        logger.debug('checkAbort: throwing abort')
        throw new AbortError('Transaction was aborted')
      }
      if (runs[id] === 'useraborted') {
        logger.debug('checkAbort: throwing useraborted')
        throw new AbortError('Transaction was aborted')
      }

    }

    function handlePossibleConflict(_conflict) {
      if (_conflict.constructor !== Set) {
        throw new Error('conflict must be of a type immutable.Set')
      }
      checkAbort()
      let conflict = _conflict.delete(id)
      let conflictTrIds = conflict.map((i) => runs[i].trId)
      let trId = runs[id].trId
      let finishingTrIds = conflict.filter((i) => runs[i].status === 'finishing').map((i) => runs[i].trId)
      if (!conflict.isEmpty()) {
        if (u.any(conflict, (i) => runs[i].status === 'finishing') ||
            conflictTrIds.min() < trId) {
          logger.debug(`aborting ${trId}, because of ${conflictTrIds}, finishing: ${finishingTrIds}`)
          abortAndReschedule(id)
        } else {
          logger.debug(`aborting ${conflictTrIds}, because of ${trId}, finishing: ${finishingTrIds}`)
          conflict.forEach(abortAndReschedule)
        }
      }
      checkAbort()
    }

    function normalizePath(path) {
      if (u.isImmutable(path)) path = path.toJS()
      if (u.isArray(path)) return path
      throw new Error(`path must be an array or immutable list; got ${path} instead`)
    }

    // TODO if possible, make DB operations accept also firebase ref
    function userRead(path) {
      path = normalizePath(path)
      if (u.any(path, (e) => (e == null))) throw new Error(`READ ERROR: undefined / null present in path: ${path}`)
      handlePossibleConflict(registry.conflictingWithRead(path))
      registry.addRead(id, path)
      return Promise.resolve()
        .then(() => read(refFromPath(path)))
        .then((val) => {
          checkAbort()
          return registry.readAsIfTrx(id, path, val)
        })
    }

    function userSet(path, value) {
      path = normalizePath(path)
      handlePossibleConflict(registry.conflictingWithWrite(path))
      registry.addWrite(id, path, value)
    }

    function userAbort(msg) {
      checkAbort()
      runs[id].abortMsg = msg
      runs[id].status = 'useraborted'
      throw new UserAbort(msg)
    }

    function userPush(path, value) {
      path = normalizePath(path)
      let ref = refFromPath(path).push()
      userSet([...path, ref.key()], value)
      return ref
    }

    function userUpdate(path, values) {
      path = normalizePath(path)
      if ((values == null) || (values.constructor !== Object)) {
        throw new Error(`The value argument in update must be a JS Object, found ${values}`)
      }
      Object.keys(values).forEach((key) => userSet([...path, key], values[key]))
    }

    function userChange(path, fn) {
      path = normalizePath(path)
      if (typeof fn !== 'function') {
        throw new Error(`fn argument must be a function, got ${fn} instead`)
      }
      return userRead(path)
        .then((val) => fn(val))
        .then((res) => userSet(path, res))
    }

    function userGetId() {
      return firebase.push().key()
    }
  } // end processTr

  function tryConsumeWaiting() {
    while (waiting.length > 0 && trCount < trCountLimit) {
      trCount += 1
      let trData = waiting.shift()
      let id = nextRunId++
      runs[id] = {...trData, status: 'inprocess', id}
      processTr(id)
        .then(() => {
          trCount -= 1
          tryConsumeWaiting()
        })
    }
  }

  const canStart = read(internalWritesRef)
  .then((writesl2) => {
    const waitForWrites = []
    writesl2 = writesl2 || {}
    u.forEachKV(writesl2, (_, writesl1) => {
      for (let write of writesl1) {
        waitForWrites.push(set(refFromPath(write.path), write.value))
      }
    })
    waitForWrites.push(set(internalWritesRef, null))
    let msg = Object.keys(writesl2).length === 0 ?
      'Clean start: no pending writes from previous session'
        :
      'Succesfully applied pending writes from the last session'
    return Promise.all(waitForWrites)
      .then(() => logger.info(msg))
  })

  // run transactor, remember the firebase-listening reference
  let onChildAdded
  canStart.then(() => {
    onChildAdded = todoTrxRef.on('child_added', (childSnapshot, prevChildKey) => {
      let trData = childSnapshot.val()
      if (trData.type == null) {
        logger.error('malformed data: ', trData)
        throw new Error('malformed trData')
      }
      trData.trId = nextTrId++
      logger.debug(`SCHEDULED: tr no ${trData.trId} data: ${JSON.stringify(trData)}`)
      trData.frbId = childSnapshot.key()
      pushWaiting(trData)
    })
  })

  // --end-transactor
  return {
    'stop': () => canStart.then((_) => todoTrxRef.off('child_added', onChildAdded)),
    'trSummary': trSummary,
  }

}

// Synchronous variant of finishing transaction code
//let toWait = []
//toWait.push(set(writesRef, writes))
//writes.forEach((write) => {
//  // TODO immutable destructuring
//  toWait.push(set(refFromPath(write.get('path')), write.get('value')))
//})
//let trData = runs[id]
//  Promise.all(toWait).then((_) => {
//  remove(writesRef)
//  set(firebase.child(DONE_TRX_PATH).child(trData.frbId), trData)
//  remove(firebase.child(TODO_TRX_PATH).child(trData.frbId))
//  registry.cleanup(id)
//  delete runs[id]
//})
<commit_msg>Delete legacy fragment of code<commit_after>import {Promise} from 'bluebird'
import {Registry} from './registry'
import {Set} from 'immutable'
import * as u from './useful'
import {read, set, remove, push} from './firebase_useful'
import log4js from 'log4js'
import {TODO_TRX_PATH, DONE_TRX_PATH, INTERNAL_TRX_PATH} from './settings'

let logger = log4js.getLogger('transactor')

// if the logging is not configured, use densible default
// whether logging was configured or not is determined
// by log4js.configured singleton
function configureLogging() {
  if (!log4js.configured) {
    log4js.configure({
      appenders: [{
        type: 'console',
        layout: {
          type: 'pattern',
          pattern: '[%[%5.5p%]] - %m'
        }
      }]
    })
    logger.setLevel('INFO')
  }
}

class AbortError {
  constructor(msg) {
    this.msg = msg
  }
}

class UserAbort {
  constructor(msg) {
    this.msg = msg
  }
}

/***
 * ## Server
 *
 * #### transactor(firebase, handlers, options = {})
 *
 *   Starts transactor.
 *
 *     args:
 *       firebase: firebase ref
 *       handlers: {String type: transaction_handler} map
 *       options:
 *         todoTrxRef: Firebase ref, where new transactions appear in Firebase
 *         closedTrxRef: Firebase ref, where finished transactions are put
 *         internalRef: Firebase ref, Transactor put pending writes here
 *         trCountLimit: int, concurency ammount; how many transactions should be processed at once
 *         rescheduleDelay: int, how long to wait (in ms) before re-scheduling aborted transaction
 *
 *     returns: handler = {stop, trSummary (for debug & test purposes)},
 *
 * #### stop()
 *
 *   Stops transactor
 *
 * #### transaction_handler({abort, change, push, read, set, update}, data)
 *
 *   User defined function, transaction handler associated to certain transaction type.
 *
 *   First argument are custom firebase-access functions that you can use to manipulate DB, the second argument is
 *   'data' which corresponds to submitTransaction's 'data'. Author of transaction_handler must
 *   return Promise that fulfills when the transaction is finished. If the Promise got rejected, the
 *   transaction gets to the similar state as if it was aborted by user by calling 'abort'; the
 *   Promise returned by submitTransaction will fulfill with {error: message}
 *
 * Most of Firebase-accessors functions accept keypath argument. Unlike Firebase reference, this is
 * specified as a simple array of keys, i.e. ['user', 123, 'name'] may represent path to users name.
 *
 * #### read(keypath)
 *   Reads the value.
 *     returns: Promise(value_read)
 *
 * #### set(keypath, val)
 *   Sets the value. This is synchronous process; transactor just remembers the write that should
 *   happen. Returns nothing.
 *
 * #### push(keypath, val)
 *   Analogous to Firebase's push
 *
 * #### change(keypath, fn)
 *   Read the value from given location, then set this location to fn(value)
 *
 * #### update(keypath, obj)
 *   Update the location's value with all k,v pair present in object obj. Since this is just a bunch
 *   of sets, it's also synchronous operation.
 *
 * #### abort(msg)
 * Aborts the transaction. None modification done will be saved to the DB, the transaction will be
 * understood as finished and the transactor won't try to repeat it. The Promise returned by
 * submitTransaction() call (on client side) will fulfill with {userError: msg}
 * Argument 'msg' is any object serializable by Firebase (ususally the simple String)
 *
 * #### getId()
 *   Convenience function, returns unique Firebase ID.
 *
 ***/
export function transactor(firebase, handlers, options = {}) {

  const {
    todoTrxRef = firebase.child(TODO_TRX_PATH),
    closedTrxRef = firebase.child(DONE_TRX_PATH),
    internalRef = firebase.child(INTERNAL_TRX_PATH),
    internalWritesRef = internalRef.child('writes'),
    trCountLimit = 50,
    rescheduleDelay = 100
  } = options

  if (!log4js.configured) configureLogging()

  const runs = {} // run id mapped to trData
  const waiting = []
  const trSummary = {aborted: 0, tried: 0, processed: 0}
  const registry = new Registry()
  let nextTrId = 0
  let nextRunId = 0
  let trCount = 0

  function _abort(id) {
    registry.cleanup(id)
    delete runs[id]
  }

  function refFromPath(path) {
    return firebase.child(path.join('/'))
  }

  function pushWaiting(val) {
    if (val == null) {
      throw new Error('val should be trx, not null/undefined')
    }
    waiting.push(val)
    tryConsumeWaiting()
  }

  function scheduleLater(trData) {
    setTimeout(() => {pushWaiting(trData)}, rescheduleDelay)
  }

  // --abortAndReschedule
  function abortAndReschedule(id) {
    if (runs[id] == null) {
      throw new Error('shouldnt abort transaction that is already aborted')
    }
    logger.debug(`CLEANUP & ABORT : tr no ${id}`)
    trSummary['aborted'] += 1
    scheduleLater(runs[id])
    _abort(id)
  }

  // --processTr
  function processTr(id) {
    logger.debug(`starting process ${id}`)
    const {type, data} = runs[id]
    const handler = handlers[type]
    if (handler == null) {
      throw new Error(`handler for type ${type} does not exist. Full trData: ${runs[id]}`)
    }

    if (runs[id] == null) {
      throw new Error('given run does not exist!')
    }

    return Promise.resolve()
      .then(() => {
        logger.debug(`starting handler ${id}`)
        trSummary['tried'] += 1
        return handler({
          abort: userAbort,
          change: userChange,
          getId: userGetId,
          push: userPush,
          read: userRead,
          set: userSet,
          update: userUpdate,
        }, data)
      })
      .catch((err) => {
        if (!(err instanceof AbortError)) {
          if (err instanceof UserAbort) {
            logger.debug(`user abort ${id}, msg: ${err.msg}`)
            return {userError: err.msg}
          } else {
            if (!process.env.supressErrors) {
              logger.error(`Unknown error abort ${err} ${err.stack}`)
              console.error(err)
              console.error(err.stack)
            }
            return {error: `${err}`}
          }
        }
        throw err
      })
      .then((result) => {
        // even if no Error is thrown, the transaction might be aborted in the
        // very last moment. Better check for it (userabort is not relevant now, as
        // we want to process such transaction)
        if (runs[id] != null) {
          logger.debug(`FINISH: tr no ${id}`)
          let userAborted = runs[id].status === 'useraborted'
          let writes = userAborted ? [] : registry.writesByTrx.get(id, [])
          let writesRef = push(internalWritesRef, {})
          trSummary['processed'] += 1
          runs[id].status = 'finishing'
          set(writesRef, writes)
          writes.forEach((write) => {
            // TODO immutable destructuring
            set(refFromPath(write.get('path')), write.get('value'))
          })
          let trData = runs[id]
          remove(writesRef)
          try {
            // TODO handle this better (some parts of result might get lost
            // here, so warn user about it)
            result = JSON.parse(JSON.stringify({result}))
          } catch (e) {
            let msg = `Error for transaction id=${id}, result cannot be saved\n to firebase (result=${result})`
            throw new Error(msg)
          }
          set(closedTrxRef.child(trData.frbId), {data: trData, ...result})
          remove(todoTrxRef.child(trData.frbId))
          registry.cleanup(id)
          delete runs[id]
        }
      })
      .catch((err) => {
        if (err instanceof AbortError) {
          logger.debug(`abort error ${id}`)
          return
        }
        throw err
      })

    function checkAbort() {
      if (runs[id] == null || runs[id].status === 'useraborted') {
        logger.debug('checkAbort: throwing abort')
        throw new AbortError('Transaction was aborted')
      }
    }

    function handlePossibleConflict(_conflict) {
      if (_conflict.constructor !== Set) {
        throw new Error('conflict must be of a type immutable.Set')
      }
      checkAbort()
      let conflict = _conflict.delete(id)
      let conflictTrIds = conflict.map((i) => runs[i].trId)
      let trId = runs[id].trId
      let finishingTrIds = conflict.filter((i) => runs[i].status === 'finishing').map((i) => runs[i].trId)
      if (!conflict.isEmpty()) {
        if (u.any(conflict, (i) => runs[i].status === 'finishing') ||
            conflictTrIds.min() < trId) {
          logger.debug(`aborting ${trId}, because of ${conflictTrIds}, finishing: ${finishingTrIds}`)
          abortAndReschedule(id)
        } else {
          logger.debug(`aborting ${conflictTrIds}, because of ${trId}, finishing: ${finishingTrIds}`)
          conflict.forEach(abortAndReschedule)
        }
      }
      checkAbort()
    }

    function normalizePath(path) {
      if (u.isImmutable(path)) path = path.toJS()
      if (u.isArray(path)) return path
      throw new Error(`path must be an array or immutable list; got ${path} instead`)
    }

    // TODO if possible, make DB operations accept also firebase ref
    function userRead(path) {
      path = normalizePath(path)
      if (u.any(path, (e) => (e == null))) throw new Error(`READ ERROR: undefined / null present in path: ${path}`)
      handlePossibleConflict(registry.conflictingWithRead(path))
      registry.addRead(id, path)
      return Promise.resolve()
        .then(() => read(refFromPath(path)))
        .then((val) => {
          checkAbort()
          return registry.readAsIfTrx(id, path, val)
        })
    }

    function userSet(path, value) {
      path = normalizePath(path)
      handlePossibleConflict(registry.conflictingWithWrite(path))
      registry.addWrite(id, path, value)
    }

    function userAbort(msg) {
      checkAbort()
      runs[id].abortMsg = msg
      runs[id].status = 'useraborted'
      throw new UserAbort(msg)
    }

    function userPush(path, value) {
      path = normalizePath(path)
      let ref = refFromPath(path).push()
      userSet([...path, ref.key()], value)
      return ref
    }

    function userUpdate(path, values) {
      path = normalizePath(path)
      if ((values == null) || (values.constructor !== Object)) {
        throw new Error(`The value argument in update must be a JS Object, found ${values}`)
      }
      Object.keys(values).forEach((key) => userSet([...path, key], values[key]))
    }

    function userChange(path, fn) {
      path = normalizePath(path)
      if (typeof fn !== 'function') {
        throw new Error(`fn argument must be a function, got ${fn} instead`)
      }
      return userRead(path)
        .then((val) => fn(val))
        .then((res) => userSet(path, res))
    }

    function userGetId() {
      return firebase.push().key()
    }
  } // end processTr

  function tryConsumeWaiting() {
    while (waiting.length > 0 && trCount < trCountLimit) {
      trCount += 1
      let trData = waiting.shift()
      let id = nextRunId++
      runs[id] = {...trData, status: 'inprocess', id}
      processTr(id)
        .then(() => {
          trCount -= 1
          tryConsumeWaiting()
        })
    }
  }

  const canStart = read(internalWritesRef)
  .then((writesl2) => {
    const waitForWrites = []
    writesl2 = writesl2 || {}
    u.forEachKV(writesl2, (_, writesl1) => {
      for (let write of writesl1) {
        waitForWrites.push(set(refFromPath(write.path), write.value))
      }
    })
    waitForWrites.push(set(internalWritesRef, null))
    let msg = Object.keys(writesl2).length === 0 ?
      'Clean start: no pending writes from previous session'
        :
      'Succesfully applied pending writes from the last session'
    return Promise.all(waitForWrites)
      .then(() => logger.info(msg))
  })

  // run transactor, remember the firebase-listening reference
  let onChildAdded
  canStart.then(() => {
    onChildAdded = todoTrxRef.on('child_added', (childSnapshot, prevChildKey) => {
      let trData = childSnapshot.val()
      if (trData.type == null) {
        logger.error('malformed data: ', trData)
        throw new Error('malformed trData')
      }
      trData.trId = nextTrId++
      logger.debug(`SCHEDULED: tr no ${trData.trId} data: ${JSON.stringify(trData)}`)
      trData.frbId = childSnapshot.key()
      pushWaiting(trData)
    })
  })

  // --end-transactor
  return {
    'stop': () => canStart.then((_) => todoTrxRef.off('child_added', onChildAdded)),
    'trSummary': trSummary,
  }

}

// Synchronous variant of finishing transaction code
//let toWait = []
//toWait.push(set(writesRef, writes))
//writes.forEach((write) => {
//  // TODO immutable destructuring
//  toWait.push(set(refFromPath(write.get('path')), write.get('value')))
//})
//let trData = runs[id]
//  Promise.all(toWait).then((_) => {
//  remove(writesRef)
//  set(firebase.child(DONE_TRX_PATH).child(trData.frbId), trData)
//  remove(firebase.child(TODO_TRX_PATH).child(trData.frbId))
//  registry.cleanup(id)
//  delete runs[id]
//})
<|endoftext|>


<commit_before>/**
 * Created by Tom on 07/09/2015.
 */// scrapes a given profile

//expose function for profile scrape
module.exports.profileScrape = profileScrape;

//expose arrays to hold scraped profile data
    //expose array that stores body of dom
module.exports.profileDataRaw =  profileDataRaw;
    //expose array that stores selected elements of dom
module.exports.profileDataSelected = profileDataSelected;

//import modules
var fs = require('fs');
var request = require("request");
//    cheerio = require("cheerio");

//array to store dump of entire body from DOM for profiles
var profileDataRaw = [];
// array to store explicit elements mentioned in profilescrape function
var profileDataSelected = [];

function profileScrape(queryUrl, lastScrape) {

// function that takes an array of project urls to query and returns object of all projects attributes

    request(queryUrl, function (error, response, body) {
        if (!error) {

            // write file shouldnt be there
            //it is only used to provide the callback function as i didnt know how else to implement it
            fs.writeFile('gg.txt', 'h', function(){
            console.log('called');
                profileDataRaw.push(body);
             //   profileDataSelected.push(keyAttributes);
                if(lastScrape) {
                    console.log(profileDataRaw);

                    fs.writeFile('ggp.txt', profileDataRaw, function () {
                        console.log('file written!!!!!!!!');
                    });
                }
            });
                return true;

        }
        if (error) {
            console.log('http request failed to give response');
        }

    });

}
<commit_msg>Delete ProfileScrape.js<commit_after><|endoftext|>


<commit_before>const autoprefixer = require('autoprefixer');
const coreDependencies = require('ima/build.js');
const path = require('path');

const sharedTasksState = require('./gulpState');
const macroTasks = require('./macroTasks.js');

let environment;
try {
  const environmentConfig = require(path.resolve('./app/environment.js'));
  const nodeEnv =
    process.env.NODE_ENV === 'development' ? 'dev' : process.env.NODE_ENV;
  environment = require('ima-helpers').resolveEnvironmentSetting(
    environmentConfig,
    nodeEnv
  );
} catch (error) {
  console.info(error.message);
  console.info('The default environment config will be used.');

  environment = {
    $Server: {
      port: 3001
    }
  };
}

let appDependencies;
try {
  appDependencies = require(path.resolve('.', 'app/build.js'));
} catch (error) {
  console.info(error.message);
  console.info('The default application dependencies will be used.');

  appDependencies = {
    js: [],
    languages: [],
    less: [],
    vendors: {
      common: [],
      server: [],
      client: []
    },
    bundle: {
      js: [],
      es: [],
      css: []
    }
  };
}
sharedTasksState.watchMode = process.argv.some(arg => /^dev$/.test(arg));
const isProduction = ['production', 'prod', 'test'].includes(
  process.env.NODE_ENV
);
const vendorOptions = {
  debug: false,
  insertGlobals: false,
  basedir: '.',
  cache: {},
  packageCache: {},
  noParse: ['clone']
};
const esPlugins = [
  '@babel/plugin-transform-react-constant-elements',
  '@babel/plugin-transform-react-inline-elements',
  'babel-plugin-transform-react-remove-prop-types'
];
const baseBabelPlugins = [
  '@babel/plugin-external-helpers',
  ['@babel/plugin-transform-react-jsx', { useBuiltIns: true }]
];

let babelConfig = {
  esVendor: {
    transform: [
      [
        'babelify',
        {
          babelrc: false,
          global: true,
          presets: ['@babel/preset-react'],
          plugins: isProduction
            ? [].concat(baseBabelPlugins, esPlugins)
            : baseBabelPlugins
        }
      ],
      [
        'loose-envify',
        {
          NODE_ENV: process.env.NODE_ENV || 'development'
        }
      ],
      ['ima-clientify']
    ],
    plugin: sharedTasksState.watchMode ? [['watchify']] : [],
    options: Object.assign({}, vendorOptions)
  },
  vendor: {
    transform: [
      [
        'babelify',
        {
          babelrc: false,
          global: true,
          presets: [
            ['@babel/preset-env', { loose: true }],
            '@babel/preset-react'
          ],
          plugins: baseBabelPlugins
        }
      ],
      [
        'loose-envify',
        {
          NODE_ENV: process.env.NODE_ENV || 'development'
        }
      ],
      ['ima-clientify']
    ],
    plugin: sharedTasksState.watchMode ? [['watchify']] : [],
    options: Object.assign({}, vendorOptions)
  },
  serverApp: {
    presets: ['@babel/preset-react'],
    plugins: ['@babel/plugin-transform-modules-systemjs'].concat(
      baseBabelPlugins
    )
  },
  esApp: {
    presets: [],
    plugins: ['@babel/plugin-external-helpers']
  },
  app: {
    presets: [['@babel/preset-env', { loose: true }]],
    plugins: ['@babel/plugin-external-helpers']
  },
  server: {
    presets: ['@babel/preset-react'],
    plugins: [
      '@babel/plugin-transform-modules-commonjs',
      ['@babel/plugin-transform-react-jsx', { useBuiltIns: true }]
    ]
  }
};
let $Debug = true;
let legacyCompactMode = false;

if (isProduction) {
  babelConfig.esApp.plugins = babelConfig.esApp.plugins.concat(esPlugins);
  $Debug = false;
  legacyCompactMode = true;
}

if (
  ['dev', undefined].includes(process.env.NODE_ENV) &&
  (process.argv.some(arg => /^--legacy-compat-mode$/.test(arg)) ||
    Object.keys(process.env).includes('npm_config_legacy_compat_mode'))
) {
  legacyCompactMode = true;
}

exports.legacyCompactMode = legacyCompactMode;
exports.babelConfig = babelConfig;
exports.$Debug = $Debug;

exports.uglifyCompression = {
  global_defs: {
    $Debug: $Debug
  },
  ecma: 7,
  dead_code: true
};

exports.liveServer = {
  port: undefined
};

exports.vendorDependencies = {
  common: coreDependencies.vendors.common.concat(
    appDependencies.vendors.common
  ),
  server: coreDependencies.vendors.server.concat(
    appDependencies.vendors.server
  ),
  client: coreDependencies.vendors.client.concat(
    appDependencies.vendors.client
  ),
  test: coreDependencies.vendors.test.concat(appDependencies.vendors.test)
};

exports.tasks = {
  dev: macroTasks.DEFAULT_DEV_SUBTASKS,
  build: macroTasks.DEFAULT_BUILD_SUBTASKS,
  spa: macroTasks.DEFAULT_SPA_SUBTASKS
};

exports.files = {
  vendor: {
    src: {
      client: 'vendor.client.src.js'
    },
    name: {
      server: 'vendor.server.js',
      esClient: 'vendor.client.es.js',
      client: 'vendor.client.js'
    },
    dest: {
      server: './build/ima/',
      client: './build/static/js/',
      tmp: './build/ima/'
    },
    watch: ['./app/build.js', './ima/build.js']
  },
  app: {
    name: {
      server: 'app.server.js',
      client: 'app.client.js',
      esClient: 'app.client.es.js'
    },
    clearServerSide: isProduction,
    src: [].concat(appDependencies.js, appDependencies.mainjs),
    dest: {
      server: './build/ima/',
      client: './build/static/js/'
    },
    watch: ['./app/**/*.{js,jsx}', './app/main.js', '!./app/environment.js']
  },
  server: {
    cwd: '/',
    src: ['./server/*.js', './server/**/*.js'],
    base: './server/',
    dest: './build/',
    watch: [
      './server/*.js',
      './server/**/*.js',
      './app/*.js',
      '!./server/ima/config/*.js'
    ]
  },
  less: {
    cwd: '/',
    base: './app/assets/less/',
    name: './app/assets/less/app.less',
    src: appDependencies.less,
    dest: './build/static/css/',
    watch: ['./app/**/*.less', '!./app/assets/bower/'],
    postCssPlugins: [autoprefixer()]
  },
  locale: {
    src: appDependencies.languages,
    dest: {
      server: './build/ima/locale/',
      client: './build/static/js/locale/'
    },
    watch: ['./app/**/*.json']
  },
  shim: {
    js: {
      name: 'shim.js',
      src: ['./node_modules/ima/polyfill/collectionEnumeration.js'],
      dest: {
        client: './build/static/js/'
      }
    },
    es: {
      name: 'shim.es.js',
      src: [],
      dest: {
        client: './build/static/js/',
        server: './build/ima/'
      }
    }
  },
  polyfill: {
    js: {
      name: 'polyfill.js',
      src: [
        './node_modules/@babel/polyfill/dist/polyfill.min.js',
        './node_modules/custom-event-polyfill/polyfill.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    },
    es: {
      name: 'polyfill.es.js',
      src: [],
      dest: {
        client: './build/static/js/'
      }
    },
    fetch: {
      name: 'fetch-polyfill.js',
      src: [
        './node_modules/core-js/client/shim.min.js',
        './node_modules/whatwg-fetch/dist/fetch.umd.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    },
    ima: {
      name: 'ima-polyfill.js',
      src: [
        './node_modules/ima/polyfill/imaLoader.js',
        './node_modules/ima/polyfill/imaRunner.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    }
  },
  bundle: {
    js: {
      name: 'app.bundle.min.js',
      src: appDependencies.bundle.js,
      dest: './build/static/js/'
    },
    es: {
      name: 'app.bundle.es.min.js',
      src: appDependencies.bundle.es,
      dest: './build/static/js/'
    },
    css: {
      name: 'app.bundle.min.css',
      src: appDependencies.bundle.css,
      dest: './build/static/css/'
    },
    postCssPlugins: []
  }
};

exports.occupiedPorts = {
  server: environment.$Server.port,
  livereload: exports.liveServer.port || 35729,
  'fb-flo': 5888
};

exports.onTerminate = () => {
  setTimeout(() => {
    process.exit();
  });
};
<commit_msg>Fix path to correct version of core-js shim.min.js<commit_after>const autoprefixer = require('autoprefixer');
const coreDependencies = require('ima/build.js');
const path = require('path');
const fs = require('fs');

const sharedTasksState = require('./gulpState');
const macroTasks = require('./macroTasks.js');

function getModuleChildPath(parentModule, childModule) {
  const paths = [
    `./node_modules/ima-gulp-tasks/${parentModule}/node_modules/${childModule}`,
    `./node_modules/${parentModule}/node_modules/${childModule}`,
    `./node_modules/${childModule}`
  ];

  for (let modulePath of paths) {
    if (fs.existsSync(modulePath)) {
      return modulePath;
    }
  }

  throw Error(`Could not find path for child module ${childModule} of parent module ${parentModule}`);
}

let environment;
try {
  const environmentConfig = require(path.resolve('./app/environment.js'));
  const nodeEnv =
    process.env.NODE_ENV === 'development' ? 'dev' : process.env.NODE_ENV;
  environment = require('ima-helpers').resolveEnvironmentSetting(
    environmentConfig,
    nodeEnv
  );
} catch (error) {
  console.info(error.message);
  console.info('The default environment config will be used.');

  environment = {
    $Server: {
      port: 3001
    }
  };
}

let appDependencies;
try {
  appDependencies = require(path.resolve('.', 'app/build.js'));
} catch (error) {
  console.info(error.message);
  console.info('The default application dependencies will be used.');

  appDependencies = {
    js: [],
    languages: [],
    less: [],
    vendors: {
      common: [],
      server: [],
      client: []
    },
    bundle: {
      js: [],
      es: [],
      css: []
    }
  };
}
sharedTasksState.watchMode = process.argv.some(arg => /^dev$/.test(arg));
const isProduction = ['production', 'prod', 'test'].includes(
  process.env.NODE_ENV
);
const vendorOptions = {
  debug: false,
  insertGlobals: false,
  basedir: '.',
  cache: {},
  packageCache: {},
  noParse: ['clone']
};
const esPlugins = [
  '@babel/plugin-transform-react-constant-elements',
  '@babel/plugin-transform-react-inline-elements',
  'babel-plugin-transform-react-remove-prop-types'
];
const baseBabelPlugins = [
  '@babel/plugin-external-helpers',
  ['@babel/plugin-transform-react-jsx', { useBuiltIns: true }]
];

let babelConfig = {
  esVendor: {
    transform: [
      [
        'babelify',
        {
          babelrc: false,
          global: true,
          presets: ['@babel/preset-react'],
          plugins: isProduction
            ? [].concat(baseBabelPlugins, esPlugins)
            : baseBabelPlugins
        }
      ],
      [
        'loose-envify',
        {
          NODE_ENV: process.env.NODE_ENV || 'development'
        }
      ],
      ['ima-clientify']
    ],
    plugin: sharedTasksState.watchMode ? [['watchify']] : [],
    options: Object.assign({}, vendorOptions)
  },
  vendor: {
    transform: [
      [
        'babelify',
        {
          babelrc: false,
          global: true,
          presets: [
            ['@babel/preset-env', { loose: true }],
            '@babel/preset-react'
          ],
          plugins: baseBabelPlugins
        }
      ],
      [
        'loose-envify',
        {
          NODE_ENV: process.env.NODE_ENV || 'development'
        }
      ],
      ['ima-clientify']
    ],
    plugin: sharedTasksState.watchMode ? [['watchify']] : [],
    options: Object.assign({}, vendorOptions)
  },
  serverApp: {
    presets: ['@babel/preset-react'],
    plugins: ['@babel/plugin-transform-modules-systemjs'].concat(
      baseBabelPlugins
    )
  },
  esApp: {
    presets: [],
    plugins: ['@babel/plugin-external-helpers']
  },
  app: {
    presets: [['@babel/preset-env', { loose: true }]],
    plugins: ['@babel/plugin-external-helpers']
  },
  server: {
    presets: ['@babel/preset-react'],
    plugins: [
      '@babel/plugin-transform-modules-commonjs',
      ['@babel/plugin-transform-react-jsx', { useBuiltIns: true }]
    ]
  }
};
let $Debug = true;
let legacyCompactMode = false;

if (isProduction) {
  babelConfig.esApp.plugins = babelConfig.esApp.plugins.concat(esPlugins);
  $Debug = false;
  legacyCompactMode = true;
}

if (
  ['dev', undefined].includes(process.env.NODE_ENV) &&
  (process.argv.some(arg => /^--legacy-compat-mode$/.test(arg)) ||
    Object.keys(process.env).includes('npm_config_legacy_compat_mode'))
) {
  legacyCompactMode = true;
}

exports.legacyCompactMode = legacyCompactMode;
exports.babelConfig = babelConfig;
exports.$Debug = $Debug;

exports.uglifyCompression = {
  global_defs: {
    $Debug: $Debug
  },
  ecma: 7,
  dead_code: true
};

exports.liveServer = {
  port: undefined
};

exports.vendorDependencies = {
  common: coreDependencies.vendors.common.concat(
    appDependencies.vendors.common
  ),
  server: coreDependencies.vendors.server.concat(
    appDependencies.vendors.server
  ),
  client: coreDependencies.vendors.client.concat(
    appDependencies.vendors.client
  ),
  test: coreDependencies.vendors.test.concat(appDependencies.vendors.test)
};

exports.tasks = {
  dev: macroTasks.DEFAULT_DEV_SUBTASKS,
  build: macroTasks.DEFAULT_BUILD_SUBTASKS,
  spa: macroTasks.DEFAULT_SPA_SUBTASKS
};

exports.files = {
  vendor: {
    src: {
      client: 'vendor.client.src.js'
    },
    name: {
      server: 'vendor.server.js',
      esClient: 'vendor.client.es.js',
      client: 'vendor.client.js'
    },
    dest: {
      server: './build/ima/',
      client: './build/static/js/',
      tmp: './build/ima/'
    },
    watch: ['./app/build.js', './ima/build.js']
  },
  app: {
    name: {
      server: 'app.server.js',
      client: 'app.client.js',
      esClient: 'app.client.es.js'
    },
    clearServerSide: isProduction,
    src: [].concat(appDependencies.js, appDependencies.mainjs),
    dest: {
      server: './build/ima/',
      client: './build/static/js/'
    },
    watch: ['./app/**/*.{js,jsx}', './app/main.js', '!./app/environment.js']
  },
  server: {
    cwd: '/',
    src: ['./server/*.js', './server/**/*.js'],
    base: './server/',
    dest: './build/',
    watch: [
      './server/*.js',
      './server/**/*.js',
      './app/*.js',
      '!./server/ima/config/*.js'
    ]
  },
  less: {
    cwd: '/',
    base: './app/assets/less/',
    name: './app/assets/less/app.less',
    src: appDependencies.less,
    dest: './build/static/css/',
    watch: ['./app/**/*.less', '!./app/assets/bower/'],
    postCssPlugins: [autoprefixer()]
  },
  locale: {
    src: appDependencies.languages,
    dest: {
      server: './build/ima/locale/',
      client: './build/static/js/locale/'
    },
    watch: ['./app/**/*.json']
  },
  shim: {
    js: {
      name: 'shim.js',
      src: ['./node_modules/ima/polyfill/collectionEnumeration.js'],
      dest: {
        client: './build/static/js/'
      }
    },
    es: {
      name: 'shim.es.js',
      src: [],
      dest: {
        client: './build/static/js/',
        server: './build/ima/'
      }
    }
  },
  polyfill: {
    js: {
      name: 'polyfill.js',
      src: [
        './node_modules/@babel/polyfill/dist/polyfill.min.js',
        './node_modules/custom-event-polyfill/polyfill.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    },
    es: {
      name: 'polyfill.es.js',
      src: [],
      dest: {
        client: './build/static/js/'
      }
    },
    fetch: {
      name: 'fetch-polyfill.js',
      src: [
        getModuleChildPath('@babel/polyfill', 'core-js') + '/client/shim.min.js',
        './node_modules/whatwg-fetch/dist/fetch.umd.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    },
    ima: {
      name: 'ima-polyfill.js',
      src: [
        './node_modules/ima/polyfill/imaLoader.js',
        './node_modules/ima/polyfill/imaRunner.js'
      ],
      dest: {
        client: './build/static/js/'
      }
    }
  },
  bundle: {
    js: {
      name: 'app.bundle.min.js',
      src: appDependencies.bundle.js,
      dest: './build/static/js/'
    },
    es: {
      name: 'app.bundle.es.min.js',
      src: appDependencies.bundle.es,
      dest: './build/static/js/'
    },
    css: {
      name: 'app.bundle.min.css',
      src: appDependencies.bundle.css,
      dest: './build/static/css/'
    },
    postCssPlugins: []
  }
};

exports.occupiedPorts = {
  server: environment.$Server.port,
  livereload: exports.liveServer.port || 35729,
  'fb-flo': 5888
};

exports.onTerminate = () => {
  setTimeout(() => {
    process.exit();
  });
};
<|endoftext|>


<commit_before>/*
  tags: basic

This example shows how you can use mipmaps in regl.

 */

const regl = require('../regl')()

const drawCheckerboard = regl({
  frag: `
  precision mediump float;
  uniform sampler2D texture;
  uniform float tick;
  varying vec2 uv;
  void main () {
    mat3 m = mat3(
      cos(tick), sin(tick), -1.1 + cos(tick),
      -sin(tick), cos(tick), 0,
      0, 0, 1);
    vec3 p = m * vec3(uv, 1);
    gl_FragColor = texture2D(texture, p.xy / p.z);
  }`,

  vert: `
  precision mediump float;
  attribute vec2 position;
  varying vec2 uv;
  void main () {
    uv = position;
    gl_Position = vec4(1.0 - 2.0 * position, 0, 1);
  }`,

  attributes: {
    position: [
      -2, 0,
      0, -2,
      2, 2]
  },

  uniforms: {
    tick: ({tick}) => 0.005 * tick,

    texture: regl.texture({
      min: 'nearest mipmap linear',
      mag: 'nearest',
      wrap: 'repeat',
      data: [
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255]
      ]
    })
  },

  count: 3
})

regl.frame(() => {
  drawCheckerboard()
})
<commit_msg>example/mipmap.js: Fix so that the min filter is linear mipmap linear' instead of 'nearest mipmap linear', because it looks much better.<commit_after>/*
  tags: basic

This example shows how you can use mipmaps in regl.

 */

const regl = require('../regl')()

const drawCheckerboard = regl({
  frag: `
  precision mediump float;
  uniform sampler2D texture;
  uniform float tick;
  varying vec2 uv;
  void main () {
    mat3 m = mat3(
      cos(tick), sin(tick), -1.1 + cos(tick),
      -sin(tick), cos(tick), 0,
      0, 0, 1);
    vec3 p = m * vec3(uv, 1);
    gl_FragColor = texture2D(texture, p.xy / p.z);
  }`,

  vert: `
  precision mediump float;
  attribute vec2 position;
  varying vec2 uv;
  void main () {
    uv = position;
    gl_Position = vec4(1.0 - 2.0 * position, 0, 1);
  }`,

  attributes: {
    position: [
      -2, 0,
      0, -2,
      2, 2]
  },

  uniforms: {
    tick: ({tick}) => 0.005 * tick,

    texture: regl.texture({
      min: 'linear mipmap linear',
      mag: 'nearest',
      wrap: 'repeat',
      data: [
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [255, 255, 255, 255, 0, 0, 0, 0],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255],
        [0, 0, 0, 0, 255, 255, 255, 255]
      ]
    })
  },

  count: 3
})

regl.frame(() => {
  drawCheckerboard()
})
<|endoftext|>