<commit_before>var Bitcoincoid = require('bitcoin-co-id'),
   _ = require('lodash'),
   moment = require('moment'),
   log = require('../core/log');

var Trader = function(config) {
  _.bindAll(this);
  if(_.isObject(config)) {
    this.key = config.key;
    this.secret = config.secret;
    this.clientID = config.username;
    this.currency = config.currency.toLowerCase();
    this.asset = config.asset.toLowerCase();
    this.pair = this.asset + '_' + this.currency;
  }
  this.name = 'Bitcoin-co-id';
  this.bitcoincoid = new Bitcoincoid(this.key, this.secret);
}

Trader.prototype.roundAmount = function(amount) {

  var priceDivider = 100000000; // one hundred million;
  amount *= priceDivider;
  amount = Math.floor(amount);
  amount /= priceDivider;
  return amount;
};

// if the exchange errors we try the same call again after
// waiting 10 seconds
Trader.prototype.retry = function(method, args) {
  var wait = +moment.duration(10, 'seconds');
  log.debug(this.name, 'returned an error, retrying..');

  var self = this;

  // make sure the callback (and any other fn)
  // is bound to Trader
  _.each(args, function(arg, i) {
    if(_.isFunction(arg))
      args[i] = _.bind(arg, self);
  });

  // run the failed method again with the same
  // arguments after wait
  setTimeout(
    function() { method.apply(self, args) },
    wait
  );
}

Trader.prototype.getTicker = function(callback) {
  var args = _.toArray(arguments),
  set = function(err, data) {
    if(err)
      return this.retry(this.getTicker, args);
      var ticker = {
      ask: this.roundAmount(data.ticker.buy),
      bid: this.roundAmount(data.ticker.sell),
    };
    callback(err, ticker);
  }.bind(this);
  this.bitcoincoid.getTicker(this.pair, set);
}

Trader.prototype.getPortfolio = function(callback) {
  var functionName = 'Trader.getPortfolio()',
  args = _.toArray(arguments);
  set = function(err, data) {
    if(err)
      return this.retry(this.getPortfolio, args);
    var assetAmount = this.roundAmount( data.return.balance[this.asset] ),
    currencyAmount = this.roundAmount( data.return.balance[this.currency] ),
    assetHold = this.roundAmount( data.return.balance_hold[this.asset] ),
    currencyHold = this.roundAmount( data.return.balance_hold[this.currency] );

    if(
      !_.isNumber(assetAmount) || _.isNaN(assetAmount) ||
      !_.isNumber(currencyAmount) || _.isNaN(currencyAmount)
    ) {
      return log.error('account balance error: Gekko is unable to trade with ',this.currency.toUpperCase(),':',currencyAmount,' or ',this.asset.toUpperCase(),':',assetAmount);
    }
    var portfolio = [
      { name: this.currency.toUpperCase(), amount: currencyAmount - currencyHold},
      { name: this.asset.toUpperCase(), amount: assetAmount - assetHold }
    ];
    callback(err, portfolio);
  }.bind(this);
  this.bitcoincoid.getAccountBalances(set);
}

Trader.prototype.getTrades = function(since, callback, descending) {
  var args = _.toArray(arguments);

  if(since)
      since = 150 //???;

  var process = function(err, data) {
    if(err)
      return this.retry(this.getTrades, args);

    var trades = _.map(data, function(trade) {
      return {
         price: +trade.price,
         amount: +trade.amount,
         tid: +trade.tid,
         date: trade.date
       }
    });
    callback(null, data.reverse());
  }.bind(this);

  this.bitcoincoid.getTrades(this.pair, process);
}

// bitcoin.co.id: Maker 0% - Taker 0.3%
// Note: trading fee: 0.3% for IDR pairs and 0% for BTC pairs
Trader.prototype.getFee = function(callback) {

  if (this.currency.toUpperCase() === 'IDR')
    {
       var fee = 0.003;
    }
    else if (this.currency.toUpperCase() === 'BTC')
    {
       var fee = 0.000;;
    }

  callback(false, fee);
};

Trader.prototype.buy = function(amount, price, callback) {
  this.type = 'buy';

  // decrease purchase by 1% to avoid trying to buy more than balance
  amount -= amount / 100;
  amount = this.roundAmount(amount);

  // decrease purchase price by 1% less than asking price
  //price -= price / 100;
  amount *= price;

  var set = function(err, data) {
    if(!err && _.isEmpty(data))
      err = 'no data';
    else if(!err && !_.isEmpty(data.errorMessage))
      err = data.errorMessage;
    if(err)
      return log.error('unable to buy', err);
  callback(null, data.return.order_id);
  }.bind(this);
  this.bitcoincoid.createOrders(
    this.pair + '',
    this.type,
    price,
    amount,
    set
  );
}

Trader.prototype.sell = function(amount, price, callback) {
  this.type = 'sell';

  // increase purchase price by 1% more than bidding price
  //price += price / 100;

  amount = this.roundAmount(amount);
  var set = function(err, data) {
    if(!err && _.isEmpty(data))
      err = 'no data';
    else if(!err && !_.isEmpty(data.errorMessage))
      err = data.errorMessage;
    if(err)
      return log.error('unable to sell', err)
    callback(null, data.return.order_id);
  }.bind(this);
  this.bitcoincoid.createOrders(
    this.pair + '',
    this.type,
    price,
    amount,
    set
  );
}

Trader.prototype.checkOrder = function(order, callback) {
  var args = _.toArray(arguments);
  if (order == null) {
    return callback('no order_id', false);
  }
  var check = function(err, data) {
    if(err){
      return this.retry(this.checkOrder, arguments);
    }
    var status = data.return.order.status;
      if (status === 'filled') {
        return callback(err, true);
      } else if (status === 'open') {
        return callback(err, false);
      }
    callback(err, false);
    }.bind(this);

  this.bitcoincoid.getOrderDetails(this.pair, order, check);
}

Trader.prototype.getOrder = function(order, callback) {
  var args = _.toArray(arguments);
  if (order == null) {
    return callback('no order_id', false);
  }
  var get = function(data, err) {
    if(err)
      return callback(err);

    var price = 0;
    var amount = 0;
    var date = moment(0);

      if(!data.success)
        return callback(null, {price, amount, date});

    var result = data.return.order;
    var orderAmount = result.order+'_'+this.asset;
    price = result.Price;
    amount = result.orderAmount;

      if(result.status === 'open') {
        date = moment(result.submit_time);
      } else {
        date = moment(result.finish_time);
      }
    callback(err, {price, amount, date});
  }.bind(this);

   this.bitcoincoid.getOrderDetails(this.pair, order, get);
}

Trader.prototype.cancelOrder = function(order, callback) {
  var args = _.toArray(arguments);
  var cancel = function(err, data) {

    if(err){
       return log.error('unable to cancel order: ',order, '(', err, '), retrying...');
       this.retry(this.cancelOrder, args);
    }
    callback();
  };
  this.bitcoincoid.cancelOrder(this.pair, order, this.type, cancel);
}

Trader.getCapabilities = function () {
  return {
    name: 'Bitcoin.co.id',
    slug: 'bitcoin-co-id',
    currencies: ['IDR', 'BTC'],
    assets: [
      'BTC', 'BCH', 'BTS', 'ETH', 'ETC', 'LTC', 'WAVE', 'XRP', 'XZR', 'BTC', 'DASH', 'DOGE', 'NXT', 'XLM', 'XEM'
    ],
    markets: [

      // IDR <-> XXXX

      { pair: ['IDR', 'BTC'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'BCH'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'ETH'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'ETC'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },
      { pair: ['IDR', 'WAVE'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['IDR', 'XRP'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['IDR', 'XZR'], minimalOrder: { amount: 0.01, unit: 'asset' } },

      // BTC <-> XXXX

      { pair: ['BTC', 'BTS'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'DASH'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'DOGE'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'NXT'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XLM'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XEM'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XRP'], minimalOrder: { amount: 0.01, unit: 'asset' } }

    ],
    requires: ['key', 'secret'],
    tid: 'tid',
    providesHistory: true,
    providesFullHistory: false,
    tradable: true
  };
}

module.exports = Trader;
<commit_msg>Fix WAVES coin name in bitcoin-co-id (#1624)<commit_after>var Bitcoincoid = require('bitcoin-co-id'),
   _ = require('lodash'),
   moment = require('moment'),
   log = require('../core/log');

var Trader = function(config) {
  _.bindAll(this);
  if(_.isObject(config)) {
    this.key = config.key;
    this.secret = config.secret;
    this.clientID = config.username;
    this.currency = config.currency.toLowerCase();
    this.asset = config.asset.toLowerCase();
    this.pair = this.asset + '_' + this.currency;
  }
  this.name = 'Bitcoin-co-id';
  this.bitcoincoid = new Bitcoincoid(this.key, this.secret);
}

Trader.prototype.roundAmount = function(amount) {

  var priceDivider = 100000000; // one hundred million;
  amount *= priceDivider;
  amount = Math.floor(amount);
  amount /= priceDivider;
  return amount;
};

// if the exchange errors we try the same call again after
// waiting 10 seconds
Trader.prototype.retry = function(method, args) {
  var wait = +moment.duration(10, 'seconds');
  log.debug(this.name, 'returned an error, retrying..');

  var self = this;

  // make sure the callback (and any other fn)
  // is bound to Trader
  _.each(args, function(arg, i) {
    if(_.isFunction(arg))
      args[i] = _.bind(arg, self);
  });

  // run the failed method again with the same
  // arguments after wait
  setTimeout(
    function() { method.apply(self, args) },
    wait
  );
}

Trader.prototype.getTicker = function(callback) {
  var args = _.toArray(arguments),
  set = function(err, data) {
    if(err)
      return this.retry(this.getTicker, args);
      var ticker = {
      ask: this.roundAmount(data.ticker.buy),
      bid: this.roundAmount(data.ticker.sell),
    };
    callback(err, ticker);
  }.bind(this);
  this.bitcoincoid.getTicker(this.pair, set);
}

Trader.prototype.getPortfolio = function(callback) {
  var functionName = 'Trader.getPortfolio()',
  args = _.toArray(arguments);
  set = function(err, data) {
    if(err)
      return this.retry(this.getPortfolio, args);
    var assetAmount = this.roundAmount( data.return.balance[this.asset] ),
    currencyAmount = this.roundAmount( data.return.balance[this.currency] ),
    assetHold = this.roundAmount( data.return.balance_hold[this.asset] ),
    currencyHold = this.roundAmount( data.return.balance_hold[this.currency] );

    if(
      !_.isNumber(assetAmount) || _.isNaN(assetAmount) ||
      !_.isNumber(currencyAmount) || _.isNaN(currencyAmount)
    ) {
      return log.error('account balance error: Gekko is unable to trade with ',this.currency.toUpperCase(),':',currencyAmount,' or ',this.asset.toUpperCase(),':',assetAmount);
    }
    var portfolio = [
      { name: this.currency.toUpperCase(), amount: currencyAmount - currencyHold},
      { name: this.asset.toUpperCase(), amount: assetAmount - assetHold }
    ];
    callback(err, portfolio);
  }.bind(this);
  this.bitcoincoid.getAccountBalances(set);
}

Trader.prototype.getTrades = function(since, callback, descending) {
  var args = _.toArray(arguments);

  if(since)
      since = 150 //???;

  var process = function(err, data) {
    if(err)
      return this.retry(this.getTrades, args);

    var trades = _.map(data, function(trade) {
      return {
         price: +trade.price,
         amount: +trade.amount,
         tid: +trade.tid,
         date: trade.date
       }
    });
    callback(null, data.reverse());
  }.bind(this);

  this.bitcoincoid.getTrades(this.pair, process);
}

// bitcoin.co.id: Maker 0% - Taker 0.3%
// Note: trading fee: 0.3% for IDR pairs and 0% for BTC pairs
Trader.prototype.getFee = function(callback) {

  if (this.currency.toUpperCase() === 'IDR')
    {
       var fee = 0.003;
    }
    else if (this.currency.toUpperCase() === 'BTC')
    {
       var fee = 0.000;;
    }

  callback(false, fee);
};

Trader.prototype.buy = function(amount, price, callback) {
  this.type = 'buy';

  // decrease purchase by 1% to avoid trying to buy more than balance
  amount -= amount / 100;
  amount = this.roundAmount(amount);

  // decrease purchase price by 1% less than asking price
  //price -= price / 100;
  amount *= price;

  var set = function(err, data) {
    if(!err && _.isEmpty(data))
      err = 'no data';
    else if(!err && !_.isEmpty(data.errorMessage))
      err = data.errorMessage;
    if(err)
      return log.error('unable to buy', err);
  callback(null, data.return.order_id);
  }.bind(this);
  this.bitcoincoid.createOrders(
    this.pair + '',
    this.type,
    price,
    amount,
    set
  );
}

Trader.prototype.sell = function(amount, price, callback) {
  this.type = 'sell';

  // increase purchase price by 1% more than bidding price
  //price += price / 100;

  amount = this.roundAmount(amount);
  var set = function(err, data) {
    if(!err && _.isEmpty(data))
      err = 'no data';
    else if(!err && !_.isEmpty(data.errorMessage))
      err = data.errorMessage;
    if(err)
      return log.error('unable to sell', err)
    callback(null, data.return.order_id);
  }.bind(this);
  this.bitcoincoid.createOrders(
    this.pair + '',
    this.type,
    price,
    amount,
    set
  );
}

Trader.prototype.checkOrder = function(order, callback) {
  var args = _.toArray(arguments);
  if (order == null) {
    return callback('no order_id', false);
  }
  var check = function(err, data) {
    if(err){
      return this.retry(this.checkOrder, arguments);
    }
    var status = data.return.order.status;
      if (status === 'filled') {
        return callback(err, true);
      } else if (status === 'open') {
        return callback(err, false);
      }
    callback(err, false);
    }.bind(this);

  this.bitcoincoid.getOrderDetails(this.pair, order, check);
}

Trader.prototype.getOrder = function(order, callback) {
  var args = _.toArray(arguments);
  if (order == null) {
    return callback('no order_id', false);
  }
  var get = function(data, err) {
    if(err)
      return callback(err);

    var price = 0;
    var amount = 0;
    var date = moment(0);

      if(!data.success)
        return callback(null, {price, amount, date});

    var result = data.return.order;
    var orderAmount = result.order+'_'+this.asset;
    price = result.Price;
    amount = result.orderAmount;

      if(result.status === 'open') {
        date = moment(result.submit_time);
      } else {
        date = moment(result.finish_time);
      }
    callback(err, {price, amount, date});
  }.bind(this);

   this.bitcoincoid.getOrderDetails(this.pair, order, get);
}

Trader.prototype.cancelOrder = function(order, callback) {
  var args = _.toArray(arguments);
  var cancel = function(err, data) {

    if(err){
       return log.error('unable to cancel order: ',order, '(', err, '), retrying...');
       this.retry(this.cancelOrder, args);
    }
    callback();
  };
  this.bitcoincoid.cancelOrder(this.pair, order, this.type, cancel);
}

Trader.getCapabilities = function () {
  return {
    name: 'Bitcoin.co.id',
    slug: 'bitcoin-co-id',
    currencies: ['IDR', 'BTC'],
    assets: [
      'BTC', 'BCH', 'BTS', 'ETH', 'ETC', 'LTC', 'WAVES', 'XRP', 'XZR', 'BTC', 'DASH', 'DOGE', 'NXT', 'XLM', 'XEM'
    ],
    markets: [

      // IDR <-> XXXX

      { pair: ['IDR', 'BTC'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'BCH'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'ETH'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'ETC'], minimalOrder: { amount: 0.0001, unit: 'asset' } },
      { pair: ['IDR', 'LTC'], minimalOrder: { amount: 0.001, unit: 'asset' } },
      { pair: ['IDR', 'WAVES'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['IDR', 'XRP'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['IDR', 'XZR'], minimalOrder: { amount: 0.01, unit: 'asset' } },

      // BTC <-> XXXX

      { pair: ['BTC', 'BTS'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'DASH'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'DOGE'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'ETH'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'LTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'NXT'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XLM'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XEM'], minimalOrder: { amount: 0.01, unit: 'asset' } },
      { pair: ['BTC', 'XRP'], minimalOrder: { amount: 0.01, unit: 'asset' } }

    ],
    requires: ['key', 'secret'],
    tid: 'tid',
    providesHistory: true,
    providesFullHistory: false,
    tradable: true
  };
}

module.exports = Trader;
<|endoftext|>


<commit_before>// From http://eloquentjavascript.net/code/chapter/06_object.js

/**
 * Repeat.
 * @param {string} string
 * @param {number} times
 * @return {string} result
 */
function repeat(string, times) {
  let result = '';
  for (let i = 0; i < times; i++)
    result += string;
  return result;
}
/**
 * Text cell.
 * @param {string} text
 */
function TextCell(text) {
  this.text = text.split('\n');
}
TextCell.prototype.minWidth = function() {
  return this.text.reduce(function(width, line) {
    return Math.max(width, line.length);
  }, 0);
};
TextCell.prototype.minHeight = function() {
  return this.text.length;
};
TextCell.prototype.draw = function(width, height) {
  let result = [];
  for (let i = 0; i < height; i++) {
    let line = this.text[i] || '';
    result.push(line + repeat(' ', width - line.length));
  }
  return result;
};

// Your code here.

/**
 * Stretch cell.
 * @param {string} inner
 * @param {number} width
 * @param {number} height
 */
function StretchCell(inner, width, height) {
	this.inner = inner;
	this.width = width;
	this.height = height;
}
StretchCell.prototype.minWidth = function() {
  return this.inner.minWidth();
};
StretchCell.prototype.minHeight = function() {
  return this.inner.minHeight() + 1;
};
StretchCell.prototype.draw = function(width, height) {
  return this.inner.draw(width, height - 1)
    .concat([repeat(' ', width)]);
};

let sc = new StretchCell(new TextCell('abc'), 1, 2);
console.log(sc.minWidth());
// → 3
console.log(sc.minHeight());
// → 2
console.log(sc.draw(3, 2));
// → ["abc", "   "]
<commit_msg>6: Another cell, fixes<commit_after>// From http://eloquentjavascript.net/code/chapter/06_object.js

/**
 * Repeat.
 * @param {string} string
 * @param {number} times
 * @return {string} result
 */
function repeat(string, times) {
  let result = '';
  for (let i = 0; i < times; i++)
    result += string;
  return result;
}
/**
 * Text cell.
 * @param {string} text
 */
function TextCell(text) {
  this.text = text.split('\n');
}
TextCell.prototype.minWidth = function() {
  return this.text.reduce(function(width, line) {
    return Math.max(width, line.length);
  }, 0);
};
TextCell.prototype.minHeight = function() {
  return this.text.length;
};
TextCell.prototype.draw = function(width, height) {
  let result = [];
  for (let i = 0; i < height; i++) {
    let line = this.text[i] || '';
    result.push(line + repeat(' ', width - line.length));
  }
  return result;
};

// Your code here.

/**
 * Stretch cell.
 * @param {string} inner
 * @param {number} width
 * @param {number} height
 */
function StretchCell(inner, width, height) {
	this.inner = inner;
	this.width = width;
	this.height = height;
}
StretchCell.prototype.minWidth = function() {
  return Math.max(this.width, this.inner.minWidth());
};
StretchCell.prototype.minHeight = function() {
  return Math.max(this.height, this.inner.minHeight());
};
StretchCell.prototype.draw = function(width, height) {
  return this.inner.draw(width, height);
};

let sc = new StretchCell(new TextCell('abc'), 1, 2);
console.log(sc.minWidth());
// → 3
console.log(sc.minHeight());
// → 2
console.log(sc.draw(3, 2));
// → ["abc", "   "]
<|endoftext|>


<commit_before>'use strict';
// from http://eloquentjavascript.net/code/#9.1
// Fill in the regular expressions

verify(/ca(r|t)/,
       ['my car', 'bad cats'],
       ['camper', 'high art']);

verify(/pr*op/,
       ['pop culture', 'mad props'],
       ['plop']);

verify(/ferr(et|y|ari)/,
       ['ferret', 'ferry', 'ferrari'],
       ['ferrum', 'transfer A']);

verify(/ious\b/,
       ['how delicious', 'spacious room'],
       ['ruinous', 'consciousness']);

verify(/.../,
       ['bad punctuation .'],
       ['escape the dot']);

verify(/.../,
       ['hottentottententen'],
       ['no', 'hotten totten tenten']);

verify(/.../,
       ['red platypus', 'wobbling nest'],
       ['earth bed', 'learning ape']);

/**
 * verify
 * @param {regexp} regexp
 * @param {array} yes
 * @param {array} no
 */
function verify(regexp, yes, no) {
  // Ignore unfinished exercises
  if (regexp.source == '...') return;
  yes.forEach(function(s) {
    if (!regexp.test(s))
      console.log('Failure to match "' + s + '"');
  });
  no.forEach(function(s) {
    if (regexp.test(s))
      console.log('Unexpected match for "' + s + '"');
  });
}
<commit_msg>9: Regexp golf: whitespace<commit_after>'use strict';
// from http://eloquentjavascript.net/code/#9.1
// Fill in the regular expressions

verify(/ca(r|t)/,
       ['my car', 'bad cats'],
       ['camper', 'high art']);

verify(/pr*op/,
       ['pop culture', 'mad props'],
       ['plop']);

verify(/ferr(et|y|ari)/,
       ['ferret', 'ferry', 'ferrari'],
       ['ferrum', 'transfer A']);

verify(/ious\b/,
       ['how delicious', 'spacious room'],
       ['ruinous', 'consciousness']);

verify(/\s(\.|,|:|;)/,
       ['bad punctuation .'],
       ['escape the dot']);

verify(/.../,
       ['hottentottententen'],
       ['no', 'hotten totten tenten']);

verify(/.../,
       ['red platypus', 'wobbling nest'],
       ['earth bed', 'learning ape']);

/**
 * verify
 * @param {regexp} regexp
 * @param {array} yes
 * @param {array} no
 */
function verify(regexp, yes, no) {
  // Ignore unfinished exercises
  if (regexp.source == '...') return;
  yes.forEach(function(s) {
    if (!regexp.test(s))
      console.log('Failure to match "' + s + '"');
  });
  no.forEach(function(s) {
    if (regexp.test(s))
      console.log('Unexpected match for "' + s + '"');
  });
}
<|endoftext|>


<commit_before>/* eslint-disable key-spacing */
import {avg, sum} from 'src/common/util'
import {STAT_DESCRIPTORS} from 'src/common/models/stat'

const {
  CHALLENGE,
  CULTURE_CONTRIBUTION,
  ELO,
  ESTIMATION_ACCURACY,
  ESTIMATION_BIAS,
  EXPERIENCE_POINTS,
  LEVEL,
  RELATIVE_CONTRIBUTION,
  TEAM_PLAY,
  TEAM_PLAY_FLEXIBLE_LEADERSHIP,
  TEAM_PLAY_FRICTION_REDUCTION,
  TEAM_PLAY_RECEPTIVENESS,
  TEAM_PLAY_RESULTS_FOCUS,
  TECHNICAL_HEALTH,
} = STAT_DESCRIPTORS

const projectStatNames = [
  CHALLENGE,
  CULTURE_CONTRIBUTION,
  ELO,
  LEVEL,
  ESTIMATION_ACCURACY,
  ESTIMATION_BIAS,
  EXPERIENCE_POINTS,
  TEAM_PLAY,
  TECHNICAL_HEALTH,
]

export function mergeOverallStatsAndDeltas(userProjectSummaries) {
  return addDeltaToStats(addPointInTimeOverallStats(userProjectSummaries))
}

export function addDeltaToStats(summariesWithOverallStats) {
  return summariesWithOverallStats.map((summary, i) => {
    const {overallStats} = summary
    const statsDifference = {}
    const isPlayersFirstProject = i === summariesWithOverallStats.length - 1

    if (!isPlayersFirstProject) {
      const previousOverallStats = summariesWithOverallStats[i + 1].overallStats
      const getDiff = stat => overallStats[stat] === null ? null : overallStats[stat] - previousOverallStats[stat]
      projectStatNames.forEach(stat => {
        statsDifference[stat] = getDiff(stat)
      })
    }

    return {...summary, statsDifference}
  })
}

export function addPointInTimeOverallStats(projectSummaries) {
  const summaries = [...projectSummaries].reverse() // COPY

  const summariesWithPointInTimeStats = summaries.map((project, i) => {
    const getAvg = _getAvgClosure(summaries, i)
    const getSum = _getSumClosure(summaries, i)

    const getAvgUnlessNull = name => project.userProjectStats[name] === null ? null : getAvg(name)
    const getSumUnlessNull = name => project.userProjectStats[name] === null ? null : getSum(name)

    return {
      ...project,
      overallStats: {
        [CHALLENGE]:                       getAvgUnlessNull(CHALLENGE),
        [CULTURE_CONTRIBUTION]:            getAvgUnlessNull(CULTURE_CONTRIBUTION),
        [ESTIMATION_ACCURACY]:             getAvgUnlessNull(ESTIMATION_ACCURACY),
        [ESTIMATION_BIAS]:                 getAvgUnlessNull(ESTIMATION_BIAS),
        [EXPERIENCE_POINTS]:               getSumUnlessNull(EXPERIENCE_POINTS),
        [ELO]:                             project.userProjectStats[ELO],
        [LEVEL]:                           (project.userProjectStats[LEVEL] || {}).ending || null,
        [RELATIVE_CONTRIBUTION]:           getAvgUnlessNull(RELATIVE_CONTRIBUTION),
        [TEAM_PLAY]:                       getAvgUnlessNull(TEAM_PLAY),
        [TEAM_PLAY_FLEXIBLE_LEADERSHIP]:   getAvgUnlessNull(TEAM_PLAY_FLEXIBLE_LEADERSHIP),
        [TEAM_PLAY_FRICTION_REDUCTION]:    getAvgUnlessNull(TEAM_PLAY_FRICTION_REDUCTION),
        [TEAM_PLAY_RECEPTIVENESS]:         getAvgUnlessNull(TEAM_PLAY_RECEPTIVENESS),
        [TEAM_PLAY_RESULTS_FOCUS]:         getAvgUnlessNull(TEAM_PLAY_RESULTS_FOCUS),
        [TECHNICAL_HEALTH]:                getAvgUnlessNull(TECHNICAL_HEALTH),
      }
    }
  })

  return summariesWithPointInTimeStats.reverse()
}

export function _getAvgClosure(list, i) {
  const endIndex = i + 1
  const startIndex = Math.max(0, endIndex - 6)
  const values = list.slice(startIndex, endIndex)
  return name => avg(
    values.map(_ => _.userProjectStats[name])
  )
}

export function _getSumClosure(list, i) {
  const values = list.slice(0, i + 1)
  return name => sum(
    values.map(_ => _.userProjectStats[name])
  )
}
<commit_msg>stats deltas: no change is calculated when there is a null for the previous week<commit_after>/* eslint-disable key-spacing */
import {avg, sum} from 'src/common/util'
import {STAT_DESCRIPTORS} from 'src/common/models/stat'

const {
  CHALLENGE,
  CULTURE_CONTRIBUTION,
  ELO,
  ESTIMATION_ACCURACY,
  ESTIMATION_BIAS,
  EXPERIENCE_POINTS,
  LEVEL,
  RELATIVE_CONTRIBUTION,
  TEAM_PLAY,
  TEAM_PLAY_FLEXIBLE_LEADERSHIP,
  TEAM_PLAY_FRICTION_REDUCTION,
  TEAM_PLAY_RECEPTIVENESS,
  TEAM_PLAY_RESULTS_FOCUS,
  TECHNICAL_HEALTH,
} = STAT_DESCRIPTORS

const projectStatNames = [
  CHALLENGE,
  CULTURE_CONTRIBUTION,
  ELO,
  LEVEL,
  ESTIMATION_ACCURACY,
  ESTIMATION_BIAS,
  EXPERIENCE_POINTS,
  TEAM_PLAY,
  TECHNICAL_HEALTH,
]

export function mergeOverallStatsAndDeltas(userProjectSummaries) {
  return addDeltaToStats(addPointInTimeOverallStats(userProjectSummaries))
}

export function addDeltaToStats(summariesWithOverallStats) {
  return summariesWithOverallStats.map((summary, i) => {
    const {overallStats} = summary
    const statsDifference = {}
    const isPlayersFirstProject = i === summariesWithOverallStats.length - 1

    if (!isPlayersFirstProject) {
      const previousOverallStats = summariesWithOverallStats[i + 1].overallStats
      const getDiff = stat => ((overallStats[stat] === null) || (previousOverallStats[stat] === null))
        ? null : overallStats[stat] - previousOverallStats[stat]

      projectStatNames.forEach(stat => {
        statsDifference[stat] = getDiff(stat)
      })
    }

    return {...summary, statsDifference}
  })
}

export function addPointInTimeOverallStats(projectSummaries) {
  const summaries = [...projectSummaries].reverse() // COPY

  const summariesWithPointInTimeStats = summaries.map((project, i) => {
    const getAvg = _getAvgClosure(summaries, i)
    const getSum = _getSumClosure(summaries, i)

    const getAvgUnlessNull = name => project.userProjectStats[name] === null ? null : getAvg(name)
    const getSumUnlessNull = name => project.userProjectStats[name] === null ? null : getSum(name)

    return {
      ...project,
      overallStats: {
        [CHALLENGE]:                       getAvgUnlessNull(CHALLENGE),
        [CULTURE_CONTRIBUTION]:            getAvgUnlessNull(CULTURE_CONTRIBUTION),
        [ESTIMATION_ACCURACY]:             getAvgUnlessNull(ESTIMATION_ACCURACY),
        [ESTIMATION_BIAS]:                 getAvgUnlessNull(ESTIMATION_BIAS),
        [EXPERIENCE_POINTS]:               getSumUnlessNull(EXPERIENCE_POINTS),
        [ELO]:                             project.userProjectStats[ELO],
        [LEVEL]:                           (project.userProjectStats[LEVEL] || {}).ending || null,
        [RELATIVE_CONTRIBUTION]:           getAvgUnlessNull(RELATIVE_CONTRIBUTION),
        [TEAM_PLAY]:                       getAvgUnlessNull(TEAM_PLAY),
        [TEAM_PLAY_FLEXIBLE_LEADERSHIP]:   getAvgUnlessNull(TEAM_PLAY_FLEXIBLE_LEADERSHIP),
        [TEAM_PLAY_FRICTION_REDUCTION]:    getAvgUnlessNull(TEAM_PLAY_FRICTION_REDUCTION),
        [TEAM_PLAY_RECEPTIVENESS]:         getAvgUnlessNull(TEAM_PLAY_RECEPTIVENESS),
        [TEAM_PLAY_RESULTS_FOCUS]:         getAvgUnlessNull(TEAM_PLAY_RESULTS_FOCUS),
        [TECHNICAL_HEALTH]:                getAvgUnlessNull(TECHNICAL_HEALTH),
      }
    }
  })

  return summariesWithPointInTimeStats.reverse()
}

export function _getAvgClosure(list, i) {
  const endIndex = i + 1
  const startIndex = Math.max(0, endIndex - 6)
  const values = list.slice(startIndex, endIndex)
  return name => avg(
    values.map(_ => _.userProjectStats[name])
  )
}

export function _getSumClosure(list, i) {
  const values = list.slice(0, i + 1)
  return name => sum(
    values.map(_ => _.userProjectStats[name])
  )
}
<|endoftext|>


<commit_before>'use strict';

var assign   = require('es5-ext/object/assign')
  , d        = require('d/d')
  , autoBind = require('d/auto-bind')
  , ee       = require('event-emitter/lib/core')
  , mark     = require('./_mark')
  , is       = require('./is')

  , defineProperty = Object.defineProperty
  , Observable;

module.exports = Observable = function (value) {
	if (is(value)) return value;
	if (!(this instanceof Observable)) return new Observable(value);
	defineProperty(this, '__value__', d('w', value));
};
mark(Object.defineProperties(ee(Observable.prototype), assign({
	__value__: d('', undefined),
	__link__: d('', undefined),
	value: d.gs('ec', function () { return this.__value__; }, function (nu) {
		var old = this.__value__, isOldObservable = this.hasOwnProperty('__link__');
		if (isOldObservable) {
			if (nu === this.__link__) return;
			this.__link__.off('change', this._mutableListener);
		}
		if (is(nu)) {
			if (isOldObservable) this.__link__ = nu;
			else defineProperty(this, '__link__', d(nu));
			nu.on('change', this._mutableListener);
			this.__value__ = nu = nu.value;
		} else {
			if (isOldObservable) delete this.__link__;
			this.__value__ = nu;
		}
		if (nu !== old) this.emit('change', nu, old);
	}),
	toString: d(function () { return String(this.__value__); })
}, autoBind({
	_mutableListener: d('', function (nu) {
		if (this.__value__ === nu) return;
		this.__value__ = nu;
		this.emit('change', nu);
	})
}))));
<commit_msg>Allow creation of linked observable<commit_after>'use strict';

var assign   = require('es5-ext/object/assign')
  , d        = require('d/d')
  , autoBind = require('d/auto-bind')
  , ee       = require('event-emitter/lib/core')
  , mark     = require('./_mark')
  , is       = require('./is')

  , defineProperty = Object.defineProperty
  , Observable;

module.exports = Observable = function (value) {
	if (!(this instanceof Observable)) return new Observable(value);
	if (is(value)) {
		defineProperty(this, '__link__', d(value));
		value.on('change', this._mutableListener);
		value = value.value;
	}
	defineProperty(this, '__value__', d('w', value));
};
mark(Object.defineProperties(ee(Observable.prototype), assign({
	__value__: d('', undefined),
	__link__: d('', undefined),
	value: d.gs('ec', function () { return this.__value__; }, function (nu) {
		var old = this.__value__, isOldObservable = this.hasOwnProperty('__link__');
		if (isOldObservable) {
			if (nu === this.__link__) return;
			this.__link__.off('change', this._mutableListener);
		}
		if (is(nu)) {
			if (isOldObservable) this.__link__ = nu;
			else defineProperty(this, '__link__', d(nu));
			nu.on('change', this._mutableListener);
			this.__value__ = nu = nu.value;
		} else {
			if (isOldObservable) delete this.__link__;
			this.__value__ = nu;
		}
		if (nu !== old) this.emit('change', nu, old);
	}),
	toString: d(function () { return String(this.__value__); })
}, autoBind({
	_mutableListener: d('', function (nu) {
		if (this.__value__ === nu) return;
		this.__value__ = nu;
		this.emit('change', nu);
	})
}))));
<|endoftext|>


<commit_before>angular.module( 'gj.Graph.Widget' ).directive( 'gjGraphWidget', function( Graph )
{
	return {
		restrict: 'E',
		templateUrl: '/lib/gj-lib-client/components/graph/widget/widget.html',
		scope: {},
		bindToController: {
			url: '@graphWidgetUrl',
			hideTable: '=graphWidgetHideTable',
		},
		controllerAs: 'ctrl',
		controller: function( $attrs, Api )
		{
			var _this = this;
			this.isLoading = true;

			$attrs.$observe( 'graphWidgetUrl', function( url )
			{
				// _this.isLoading = true;
				Api.sendRequest( url, null, { detach: true } ).then( function( response )
				{
					if ( response.data && angular.isArray( response.data ) ) {
						_this.graphData = Graph.createGraphData( response.data );
					}

					_this.isLoading = false;
				} );
			} );
		},
	};
} );

/*
angular.module( 'gj.Graph.Widget' ).directive( 'gjGraphWidget', function( Graph )
{
	return {
		restrict: 'E',
		templateUrl: '/lib/gj-lib-client/components/graph/widget/widget.html',
		scope: {},
		bindToController: {
			url: '@graphWidgetUrl',
			hideTable: '=graphWidgetHideTable',
			_graphData: '=graphWidgetData',
		},
		controllerAs: 'ctrl',
		controller: function( Api )
		{
			var _this = this;
			this.isLoading = true;

			if ( angular.isDefined( this._graphData ) ) {
				this.isLoading = false;
			}
			else {
				Api.sendRequest( this.url, null, { detach: true } ).then( function( response )
				{
					if ( response.data && angular.isArray( response.data ) ) {
						_this.graphData = Graph.createGraphData( response.data );
					}

					_this.isLoading = false;
				} );
			}

			$scope.$watch( function()
			{
				return _this._graphData;
			},
			function( graphData )
			{
				_this.graphData = graphData;
			} );
		},
	};
} );

*/
<commit_msg>Removing commented code.<commit_after>angular.module( 'gj.Graph.Widget' ).directive( 'gjGraphWidget', function( Graph )
{
	return {
		restrict: 'E',
		templateUrl: '/lib/gj-lib-client/components/graph/widget/widget.html',
		scope: {},
		bindToController: {
			url: '@graphWidgetUrl',
			hideTable: '=graphWidgetHideTable',
		},
		controllerAs: 'ctrl',
		controller: function( $attrs, Api )
		{
			var _this = this;
			this.isLoading = true;

			$attrs.$observe( 'graphWidgetUrl', function( url )
			{
				// _this.isLoading = true;
				Api.sendRequest( url, null, { detach: true } ).then( function( response )
				{
					if ( response.data && angular.isArray( response.data ) ) {
						_this.graphData = Graph.createGraphData( response.data );
					}

					_this.isLoading = false;
				} );
			} );
		},
	};
} );
<|endoftext|>


<commit_before>var curr_set;
var curr_set_index = 0;
var curr_timeout;

function initVideo(){
	video.muted=true;
	 // Capture the play event and set the button to say pause
	 video.addEventListener("play", function () {
		firstCheckPoint(active_video_id);
	   console.log( "Play");
	 }, false);

	 // Capture the pause event and set the button to say play
	 video.addEventListener("pause", function () {
	   console.log( "Pause");
	 }, false);
}

function addCheckPoint(){
	var local = curr_set.set[curr_set_index].Location;
	centerMap(local.Latitude, local.Longitude, 19);
	console.log(video.currentTime+'    '+curr_set.set[curr_set_index].Sensor.DurationTotal/1000)
	curr_set_index++;
	window.setTimeout(addCheckPoint, curr_set.set[curr_set_index].Sensor.Duration)
}

function firstCheckPoint(id){
	curr_set = getSetByVideoId(id);
	addCheckPoint();
}

function resetCheckPoints(){
	curr_set = null;
	curr_set_index = 0;
	window.clearTimeout(curr_timeout);
}<commit_msg>renamed addCheckPoint to nextCheckPoint<commit_after>var curr_set;
var curr_set_index = 0;
var curr_timeout;

function initVideo(){
	video.muted=true;
	 // Capture the play event and set the button to say pause
	 video.addEventListener("play", function () {
		firstCheckPoint(active_video_id);
	   console.log( "Play");
	 }, false);

	 // Capture the pause event and set the button to say play
	 video.addEventListener("pause", function () {
	   console.log( "Pause");
	 }, false);
}

function nextCheckPoint(){
	var local = curr_set.set[curr_set_index].Location;
	centerMap(local.Latitude, local.Longitude, 19);
	console.log(video.currentTime+'    '+curr_set.set[curr_set_index].Sensor.DurationTotal/1000)
	curr_set_index++;
	window.setTimeout(nextCheckPoint, curr_set.set[curr_set_index].Sensor.Duration)
}

function firstCheckPoint(id){
	curr_set = getSetByVideoId(id);
	nextCheckPoint();
}

function resetCheckPoints(){
	curr_set = null;
	curr_set_index = 0;
	window.clearTimeout(curr_timeout);
}<|endoftext|>


<commit_before>const logger = require('winston')
const listItems = require('../model/listitems')

const route = (request, response) => {
  logger.log('info', request)
  const data = {
    list: 'shopping',
    familyId: 2
  }
  listItems.findPromise(data)
    .then(result => {
      const listItemNames = result.listItems.map(listItem => {
        return {name: listItem.listItemName}
      })
      response.json(request)
    })
}

module.exports = {
  route
}
<commit_msg>continue testing;<commit_after>const logger = require('winston')
const listItems = require('../model/listitems')

const route = (request, response) => {
  logger.log('info', request)
  const data = {
    list: 'shopping',
    familyId: 2
  }
  listItems.findPromise(data)
    .then(result => {
      const listItemNames = result.listItems.map(listItem => {
        return {name: listItem.listItemName}
      })
      console.log(request)
      response.json(listItemNames)
    })
}

module.exports = {
  route
}
<|endoftext|>


<commit_before>// const logger = require('winston')
const lists = require('../model/lists')
const listItems = require('../model/listitems')
const modelConstants = require('../model/modelconstants')

const errorMessages = {
  notFound: 'Not found',
  alreadyExists: 'Already exists',
  generalError: 'Error'
}

const getLists = (request, response) => {
  lists.findAllPromise({familyId: 2})
    .then(result => {
      const listNames = result.lists.map(list => {
        return {name: list.listKey}
      })
      response.json(listNames)
    }, result => {
      response.status(404).send(errorMessages.generalError)
    }
  )
}

const addList = (request, response) => {
  let list = request.body.name
  lists.saveNewPromise({list, familyId: 2})
    .then(result => {
      response.json({name: list})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.duplicateList) {
        response.status(409).send(errorMessages.alreadyExists)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
  )
}

const deleteList = (request, response) => {
  let list = request.params.list
  lists.deletePromise({list, familyId: 2})
    .then(result => {
      response.json({name: list})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.listNotFound) {
        response.status(404).send(errorMessages.notFound)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
  )
}

const getListItems = (request, response) => {
  listItems.findPromise({list: request.params.list, familyId: 2})
    .then(result => {
      const listItemNames = result.listItems.map(listItem => {
        return {name: listItem.listItemName}
      })
      response.json(listItemNames)
    }, result => {
      response.status(404).send(errorMessages.generalError)
    }
  )
}

const addListItem = (request, response) => {
  let listItemName = request.body.name
  // TODO: deal with duplicates
  listItems.saveNewPromise({list: request.params.list, familyId: 2, listItemName: listItemName})
    .then(result => {
      response.json({name: listItemName})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.duplicateListItem) {
        response.status(409).send(errorMessages.alreadyExists)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
}

// Can handle delete and clear (delete all)
const deleteListItem = (request, response) => {
  let listItemName = request.params.item
  listItems.deletePromise({list: request.params.list, familyId: 2}, listItemName)
    .then(result => {
      response.json({name: listItemName})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.listItemNotFound) {
        response.status(404).send(errorMessages.notFound)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    })
}

module.exports = {
  getLists,
  addList,
  deleteList,
  getListItems,
  addListItem,
  deleteListItem
}
<commit_msg>add missing parathesis<commit_after>// const logger = require('winston')
const lists = require('../model/lists')
const listItems = require('../model/listitems')
const modelConstants = require('../model/modelconstants')

const errorMessages = {
  notFound: 'Not found',
  alreadyExists: 'Already exists',
  generalError: 'Error'
}

const getLists = (request, response) => {
  lists.findAllPromise({familyId: 2})
    .then(result => {
      const listNames = result.lists.map(list => {
        return {name: list.listKey}
      })
      response.json(listNames)
    }, result => {
      response.status(404).send(errorMessages.generalError)
    }
  )
}

const addList = (request, response) => {
  let list = request.body.name
  lists.saveNewPromise({list, familyId: 2})
    .then(result => {
      response.json({name: list})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.duplicateList) {
        response.status(409).send(errorMessages.alreadyExists)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
  )
}

const deleteList = (request, response) => {
  let list = request.params.list
  lists.deletePromise({list, familyId: 2})
    .then(result => {
      response.json({name: list})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.listNotFound) {
        response.status(404).send(errorMessages.notFound)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
  )
}

const getListItems = (request, response) => {
  listItems.findPromise({list: request.params.list, familyId: 2})
    .then(result => {
      const listItemNames = result.listItems.map(listItem => {
        return {name: listItem.listItemName}
      })
      response.json(listItemNames)
    }, result => {
      response.status(404).send(errorMessages.generalError)
    }
  )
}

const addListItem = (request, response) => {
  let listItemName = request.body.name
  // TODO: deal with duplicates
  listItems.saveNewPromise({list: request.params.list, familyId: 2, listItemName: listItemName})
    .then(result => {
      response.json({name: listItemName})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.duplicateListItem) {
        response.status(409).send(errorMessages.alreadyExists)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    }
  )
}

// Can handle delete and clear (delete all)
const deleteListItem = (request, response) => {
  let listItemName = request.params.item
  listItems.deletePromise({list: request.params.list, familyId: 2}, listItemName)
    .then(result => {
      response.json({name: listItemName})
    }, result => {
      if (result.errorMessage === modelConstants.errorTypes.listItemNotFound) {
        response.status(404).send(errorMessages.notFound)
      } else {
        response.status(404).send(errorMessages.generalError)
      }
    })
}

module.exports = {
  getLists,
  addList,
  deleteList,
  getListItems,
  addListItem,
  deleteListItem
}
<|endoftext|>


<commit_before>function startApp() {
    showHideMenuLinks();
    showHomeView();

    // Bind the navigation menu links
    $("#linkHome").click(showHomeView);
    $("#linkLogin").click(showLoginView);
    $("#linkRegister").click(showRegisterView);
    $("#linkListAds").click(listAdverts);
    $("#linkLogout").click(logoutUser);

    // Bind the form submit buttons
    $("#buttonLoginUser").click(loginUser);
    $("#buttonRegisterUser").click(registerUser);

    const kinveyBaseUrl = "https://mock.api.com/";
    const kinveyAppKey = "kid_rk";
    const kinveyAppSecret = "736804a668";

    function showView(viewName) {
        // Hide all views and show the selected view only
        $('main > section').hide();
        $('#' + viewName).show();
    }

    function showHideMenuLinks() {
        $("#linkHome").show();
        if (sessionStorage.getItem('authToken') === null) {
            // No logged in user
            $("#linkLogin").show();
            $("#linkRegister").show();
            $("#linkListAds").hide();
            $("#linkLogout").hide();
        } else {
            // We have logged in user
            $("#linkLogin").hide();
            $("#linkRegister").hide();
            $("#linkListAds").show();
            $("#linkLogout").show();
        }
    }

    function showHomeView() {
        showView('viewHome');
    }

    function showLoginView() {
        showView('viewLogin');
        $('#formLogin').trigger('reset');
    }

    function showRegisterView() {
        $('#formRegister').trigger('reset');
        showView('viewRegister');
    }

    // user/login
    function loginUser() {
        const kinveyLoginUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/login";
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };
        let userData = {
            username: $('#formLogin input[name=username]').val(),
            password: $('#formLogin input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyLoginUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: loginSuccess
        });

        function loginSuccess(userInfo) {
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    function saveAuthInSession(userInfo) {
        let userAuth = userInfo._kmd.authtoken;
        sessionStorage.setItem('authToken', userAuth);
        let userId = userInfo._id;
        sessionStorage.setItem('userId', userId);
    }

    // user/register
    function registerUser() {
        const kinveyRegisterUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/";
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };

        let userData = {
            username: $('#formRegister input[name=username]').val(),
            password: $('#formRegister input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyRegisterUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: registerSuccess
        });

        function registerSuccess(userInfo) {
            console.log(userInfo);
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    // user/logout
    function logoutUser() {
        sessionStorage.clear();
        $('#loggedInUser').text("");
        showHideMenuLinks();
        showHomeView();
    }

    // advertisement/all
    function listAdverts() {
        $('#ads').empty();
        showView('viewAds');

        const kinveyAdvertsUrl = kinveyBaseUrl + "appdata/" + kinveyAppKey + "/adverts";
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };
        $.ajax({
            method: "GET",
            url: kinveyAdvertsUrl,
            headers: kinveyAuthHeaders,
            success: loadAdvertsSuccess
        });

        function loadAdvertsSuccess(adverts) {
            if (adverts.length === 0) {
                $('#ads').text('No advertisements available.');
            } else {
                let advertsTable = $('
')
                    .append($('
').append(
                        'Title	',
                        'Description	',
                        'Publisher	',
                        'Date Published	',
                        'Price	',
                        'Actions	')
                    );

                for (let advert of adverts) {
                        let readMoreLink = $(`<a data-id="${advert._id}" href="#">[Read More]</a>`)
                        .click(function() { displayAdvert($(this).attr("data-id")) });

                    advertsTable.append($('
').append(
                        $('').text(advert.title),
                        $('').text(advert.description),
                        $('').text(advert.publisher),
                        $('').text(advert.datePublished),
                        $('').text(advert.price)
                        $('').append(readMoreLink)
                    ));
                }

                $('#ads').append(advertsTable);
            }
        }
    }

    function displayAdvert(advertId){
        const kinveyAdvertUrl = kinveyBaseUrl + "appdata/" +
            kinveyAppKey + "/adverts/" + advertId;
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };

        $.ajax({
            method: "GET",
            url: kinveyAdvertUrl,
            headers: kinveyAuthHeaders,
            success: displayAdvertSuccess
        });

        $('#viewDetailsAd').empty();

        function displayAdvertSuccess(advert) {
            let advertInfo = $('
').append(
                $('').attr("src", advert.image),
                $('
'),
                $('').text('Title:'),
                $('
').text(advert.title),
                $('').text('Description:'),
                $('
').text(advert.description),
                $('').text('Publisher:'),
                $('
').text(advert.publisher),
                $('').text('Date:'),
                $('
').text(advert.datePublished));

            $('#viewDetailsAd').append(advertInfo);

            showView('viewDetailsAd');
        }
    }
}
<commit_msg>Finished Task6-2<commit_after>function startApp() {
    showHideMenuLinks();
    showHomeView();

    // Bind the navigation menu links
    $("#linkHome").click(showHomeView);
    $("#linkLogin").click(showLoginView);
    $("#linkRegister").click(showRegisterView);
    $("#linkListAds").click(listAdverts);
    $("#linkLogout").click(logoutUser);

    // Bind the form submit buttons
    $("#buttonLoginUser").click(loginUser);
    $("#buttonRegisterUser").click(registerUser);

    const kinveyBaseUrl = "https://mock.api.com/";
    const kinveyAppKey = "kid_rk";
    const kinveyAppSecret = "736804a668";

    function showView(viewName) {
        // Hide all views and show the selected view only
        $('main > section').hide();
        $('#' + viewName).show();
    }

    function showHideMenuLinks() {
        $("#linkHome").show();
        if (sessionStorage.getItem('authToken') === null) {
            // No logged in user
            $("#linkLogin").show();
            $("#linkRegister").show();
            $("#linkListAds").hide();
            $("#linkLogout").hide();
        } else {
            // We have logged in user
            $("#linkLogin").hide();
            $("#linkRegister").hide();
            $("#linkListAds").show();
            $("#linkLogout").show();
        }
    }

    function showHomeView() {
        showView('viewHome');
    }

    function showLoginView() {
        showView('viewLogin');
        $('#formLogin').trigger('reset');
    }

    function showRegisterView() {
        $('#formRegister').trigger('reset');
        showView('viewRegister');
    }

    // user/login
    function loginUser() {
        const kinveyLoginUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/login";
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };
        let userData = {
            username: $('#formLogin input[name=username]').val(),
            password: $('#formLogin input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyLoginUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: loginSuccess
        });

        function loginSuccess(userInfo) {
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    function saveAuthInSession(userInfo) {
        let userAuth = userInfo._kmd.authtoken;
        sessionStorage.setItem('authToken', userAuth);
        let userId = userInfo._id;
        sessionStorage.setItem('userId', userId);
    }

    // user/register
    function registerUser() {
        const kinveyRegisterUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/";
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };

        let userData = {
            username: $('#formRegister input[name=username]').val(),
            password: $('#formRegister input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyRegisterUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: registerSuccess
        });

        function registerSuccess(userInfo) {
            console.log(userInfo);
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    // user/logout
    function logoutUser() {
        sessionStorage.clear();
        $('#loggedInUser').text("");
        showHideMenuLinks();
        showHomeView();
    }

    // advertisement/all
    function listAdverts() {
        $('#ads').empty();
        showView('viewAds');

        const kinveyAdvertsUrl = kinveyBaseUrl + "appdata/" + kinveyAppKey + "/adverts";
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };
        $.ajax({
            method: "GET",
            url: kinveyAdvertsUrl,
            headers: kinveyAuthHeaders,
            success: loadAdvertsSuccess
        });

        function loadAdvertsSuccess(adverts) {
            if (adverts.length === 0) {
                $('#ads').text('No advertisements available.');
            } else {
                let advertsTable = $('
')
                    .append($('
').append(
                        'Title	',
                        'Description	',
                        'Publisher	',
                        'Date Published	',
                        'Price	',
                        'Actions	')
                    );

                for (let advert of adverts) {
                    let readMoreLink = $(`<a data-id="${advert._id}" href="#">[Read More]</a>`)
                        .click(function() { displayAdvert($(this).attr("data-id")) });

                    advertsTable.append($('
').append(
                        $('').text(advert.title),
                        $('').text(advert.description),
                        $('').text(advert.publisher),
                        $('').text(advert.datePublished),
                        $('').text(advert.price),
                        $('').append(readMoreLink)
                    ));
                }

                $('#ads').append(advertsTable);
            }
        }
    }

    function displayAdvert(advertId){
        const kinveyAdvertUrl = kinveyBaseUrl + "appdata/" +
            kinveyAppKey + "/adverts/" + advertId;
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };

        $.ajax({
            method: "GET",
            url: kinveyAdvertUrl,
            headers: kinveyAuthHeaders,
            success: displayAdvertSuccess
        });

        $('#viewDetailsAd').empty();

        function displayAdvertSuccess(advert) {
            let advertInfo = $('
').append(
                $('').attr("src", advert.image),
                $('
'),
                $('').text('Title:'),
                $('
').text(advert.title),
                $('').text('Description:'),
                $('
').text(advert.description),
                $('').text('Publisher:'),
                $('
').text(advert.publisher),
                $('').text('Date:'),
                $('
').text(advert.datePublished));

            $('#viewDetailsAd').append(advertInfo);

            showView('viewDetailsAd');
        }
    }
}
<|endoftext|>


<commit_before>function startApp() {
<<<<<<>>>>>> aa18989064e970c71d54f9aa2bb275dc5f16091d
    showHideMenuLinks();
    showHomeView();

    // Bind the navigation menu links
    $("#linkHome").click(showHomeView);
    $("#linkLogin").click(showLoginView);
    $("#linkRegister").click(showRegisterView);
    $("#linkListAds").click(listAdverts);
    $("#linkLogout").click(logoutUser);

    // Bind the form submit buttons
    $("#buttonLoginUser").click(loginUser);
    $("#buttonRegisterUser").click(registerUser);

    const kinveyBaseUrl = "https://mock.api.com/";
    const kinveyAppKey = "kid_rk";
    const kinveyAppSecret = "736804a668";

    function showView(viewName) {
        // Hide all views and show the selected view only
        $('main > section').hide();
        $('#' + viewName).show();
    }

    function showHideMenuLinks() {
        $("#linkHome").show();
        if (sessionStorage.getItem('authToken') === null) {
            // No logged in user
            $("#linkLogin").show();
            $("#linkRegister").show();
            $("#linkListAds").hide();
            $("#linkLogout").hide();
<<<<<<>>>>>> aa18989064e970c71d54f9aa2bb275dc5f16091d
        } else {
            // We have logged in user
            $("#linkLogin").hide();
            $("#linkRegister").hide();
            $("#linkListAds").show();
            $("#linkLogout").show();
<<<<<<>>>>>> aa18989064e970c71d54f9aa2bb275dc5f16091d
        }
    }

    function showHomeView() {
        showView('viewHome');
    }

    function showLoginView() {
        showView('viewLogin');
        $('#formLogin').trigger('reset');
    }

    function showRegisterView() {
        $('#formRegister').trigger('reset');
        showView('viewRegister');
    }

    // user/login
    function loginUser() {
        const kinveyLoginUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/login";;
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };
        let userData = {
            username: $('#formLogin input[name=username]').val(),
            password: $('#formLogin input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyLoginUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: loginSuccess
        });

        function loginSuccess(userInfo) {
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    function saveAuthInSession(userInfo) {
        let userAuth = userInfo._kmd.authtoken;
        sessionStorage.setItem('authToken', userAuth);
        let userId = userInfo._id;
        sessionStorage.setItem('userId', userId);
<<<<<<>>>>>> aa18989064e970c71d54f9aa2bb275dc5f16091d
    // user/register
    function registerUser() {
        const kinveyRegisterUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/";;
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };

        let userData = {
            username: $('#formRegister input[name=username]').val(),
            password: $('#formRegister input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyRegisterUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: registerSuccess
        });

        function registerSuccess(userInfo) {
            console.log(userInfo);
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    // user/logout
    function logoutUser() {
        sessionStorage.clear();
        $('#loggedInUser').text("");
        showHideMenuLinks();
        showHomeView();
    }

    // advertisement/all
    function listAdverts() {
        $('#ads').empty();
        showView('viewAds');

        const kinveyAdvertsUrl = kinveyBaseUrl + "appdata/" + kinveyAppKey + "/adverts";
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };
        $.ajax({
            method: "GET",
            url: kinveyAdvertsUrl,
            headers: kinveyAuthHeaders,
            success: loadAdvertsSuccess
        });

        function loadAdvertsSuccess(adverts) {
            if (adverts.length === 0) {
                $('#ads').text('No advertisements available.');
            } else {
                let advertsTable = $('
')
                    .append($('
').append(
                        'Title	',
                        'Publisher	',
                        'Date Published	',
                        'Price	')
                    );

                for (let advert of adverts) {
                    advertsTable.append($('
').append(
                        $('').text(advert.title),
                        $('').text(advert.publisher),
                        $('').text(advert.datePublished),
                        $('').text(advert.price)
                    ));
                }

                $('#ads').append(advertsTable);
            }
        }
    }
<<<<<<>>>>>> aa18989064e970c71d54f9aa2bb275dc5f16091d
<commit_msg>more merge<commit_after>function startApp() {
    if (sessionStorage.getItem('authToken') !== null) {
        let username = sessionStorage.getItem('username');
        $('#loggedInUser').text("Welcome, " + username + "!");
    }
    showHideMenuLinks();
    showHomeView();

    // Bind the navigation menu links
    $("#linkHome").click(showHomeView);
    $("#linkLogin").click(showLoginView);
    $("#linkRegister").click(showRegisterView);
    $("#linkListAds").click(listAdverts);
    $("#linkLogout").click(logoutUser);

    // Bind the form submit buttons
    $("#buttonLoginUser").click(loginUser);
    $("#buttonRegisterUser").click(registerUser);

    const kinveyBaseUrl = "https://mock.api.com/";
    const kinveyAppKey = "kid_rk";
    const kinveyAppSecret = "736804a668";

    function showView(viewName) {
        // Hide all views and show the selected view only
        $('main > section').hide();
        $('#' + viewName).show();
    }

    function showHideMenuLinks() {
        $("#linkHome").show();
        if (sessionStorage.getItem('authToken') === null) {
            // No logged in user
            $("#linkLogin").show();
            $("#linkRegister").show();
            $("#linkListAds").hide();
            $("#linkLogout").hide();
            $("#loggedInUser").hide();
        } else {
            // We have logged in user
            $("#linkLogin").hide();
            $("#linkRegister").hide();
            $("#linkListAds").show();
            $("#linkLogout").show();
            $("#loggedInUser").show();
        }
    }

    function showHomeView() {
        showView('viewHome');
    }

    function showLoginView() {
        showView('viewLogin');
        $('#formLogin').trigger('reset');
    }

    function showRegisterView() {
        $('#formRegister').trigger('reset');
        showView('viewRegister');
    }

    // user/login
    function loginUser() {
        const kinveyLoginUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/login";;
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };
        let userData = {
            username: $('#formLogin input[name=username]').val(),
            password: $('#formLogin input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyLoginUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: loginSuccess
        });

        function loginSuccess(userInfo) {
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    function saveAuthInSession(userInfo) {
        let userAuth = userInfo._kmd.authtoken;
        sessionStorage.setItem('authToken', userAuth);
        let userId = userInfo._id;
        sessionStorage.setItem('userId', userId);
        let username = userInfo.username;
        sessionStorage.setItem('username', username);
        $('#loggedInUser').text("Welcome, " + username + "!");
    }
    // user/register
    function registerUser() {
        const kinveyRegisterUrl = kinveyBaseUrl + "user/" + kinveyAppKey + "/";;
        const kinveyAuthHeaders = {
            'Authorization': "Basic " + btoa(kinveyAppKey + ":" + kinveyAppSecret),
        };

        let userData = {
            username: $('#formRegister input[name=username]').val(),
            password: $('#formRegister input[name=passwd]').val()
        };

        $.ajax({
            method: "POST",
            url: kinveyRegisterUrl,
            headers: kinveyAuthHeaders,
            data: userData,
            success: registerSuccess
        });

        function registerSuccess(userInfo) {
            console.log(userInfo);
            saveAuthInSession(userInfo);
            showHideMenuLinks();
            listAdverts();
        }
    }

    // user/logout
    function logoutUser() {
        sessionStorage.clear();
        $('#loggedInUser').text("");
        showHideMenuLinks();
        showHomeView();
    }

    // advertisement/all
    function listAdverts() {
        $('#ads').empty();
        showView('viewAds');

        const kinveyAdvertsUrl = kinveyBaseUrl + "appdata/" + kinveyAppKey + "/adverts";
        const kinveyAuthHeaders = {
            'Authorization': "Kinvey " + sessionStorage.getItem('authToken'),
        };
        $.ajax({
            method: "GET",
            url: kinveyAdvertsUrl,
            headers: kinveyAuthHeaders,
            success: loadAdvertsSuccess
        });

        function loadAdvertsSuccess(adverts) {
            if (adverts.length === 0) {
                $('#ads').text('No advertisements available.');
            } else {
                let advertsTable = $('
')
                    .append($('
').append(
                        'Title	',
                        'Publisher	',
                        'Date Published	',
                        'Price	')
                    );

                for (let advert of adverts) {
                    advertsTable.append($('
').append(
                        $('').text(advert.title),
                        $('').text(advert.publisher),
                        $('').text(advert.datePublished),
                        $('').text(advert.price)
                    ));
                }

                $('#ads').append(advertsTable);
            }
        }
    }
}
<|endoftext|>


<commit_before>/* globals angular */
angular.module('gc.fastRepeat', []).directive('fastRepeat', ['$compile', '$parse', function ($compile, $parse) {
    'use strict';

    var fastRepeatId = 0,
        showProfilingInfo = false;

    // JSON.stringify replacer function which removes any keys that start with $$.
    // This prevents unnecessary updates when we watch a JSON stringified value.
    function JSONStripper(key, value) {
        if(key.slice && key.slice(0,2) == '$$') { return undefined; }
        return value;
    }

    function getTime() { // For profiling
        if(window.performance && window.performance.now) { return window.performance.now(); }
        else { return (new Date()).getTime(); }
    }

    return {
        restrict: 'A',
        scope: false,
        transclude: 'element',
        priority: 10000,
        compile: function(tElement, tAttrs) {
            return function link(listScope, element, attrs, ctrl, transclude) {
                var repeatParts = attrs.fastRepeat.split(' in ');
                var repeatListName = repeatParts[1], repeatVarName = repeatParts[0];
                var currentRowEls = {};
                var t;

                // Scope created for evaluating the rows -- child of the scope the list was created in.
                // Note this is almost a misnomer since the list doesn't have a scope of its own.
                var rowScope = listScope.$new(false);

                // Transclude the contents of the fast repeat.
                // This function is called for every row. It reuses the rowTpl and scope for each row.
                transclude(rowScope, function(rowTpl, scope) {
                    function render(item) {
                        scope[repeatVarName] = item;
                        scope.$digest();
                        rowTpl.attr('fast-repeat-id', item.$$fastRepeatId);
                        return rowTpl.clone();
                    }

                    var getter = $parse(repeatListName); // getter(scope) should be the value of the list.

                    // Here is the main watch. Testing has shown that watching the stringified list can
                    // save roughly 500ms per digest in certain cases.
                    // JSONStripper is used to remove the $$fastRepeatId that we attach to the objects.
                    listScope.$watch(function(scp){ return JSON.stringify(getter(scp), JSONStripper); }, function(list) {
                        list = getter(listScope);

                        if (showProfilingInfo) {
                            t = getTime();
                        }

                        // Rendering is done in a postDigest so that we are outside of the main digest cycle.
                        // This allows us to digest the individual row scope repeatedly without major hackery.
                        listScope.$$postDigest(function() {

                            // Generate ids if necessary and arrange in a hash map
                            var listByIds = {};
                            angular.forEach(list, function(item) {
                                if(!item.$$fastRepeatId) {
                                    item.$$fastRepeatId = ++fastRepeatId;
                                }
                                listByIds[item.$$fastRepeatId] = item;
                            });

                            // Delete removed rows
                            angular.forEach(currentRowEls, function(row, id) {
                                if(!listByIds[id]) {
                                    row.el.detach();
                                }
                            });

                            // Add/rearrange all rows
                            var previousEl = element;
                            angular.forEach(list, function(item) {
                                var id = item.$$fastRepeatId;
                                var row=currentRowEls[id];
                                if(row) {
                                    // We've already seen this one
                                    if(!row.compiled && !angular.equals(row.copy, item)) {
                                        // This item has not been compiled and it apparently has changed -- need to rerender
                                        var newEl = render(item);
                                        row.el.replaceWith(newEl);
                                        row.el = newEl;
                                        row.copy = angular.copy(item);
                                    }
                                } else {
                                    // This must be a new node
                                    row = {
                                        copy: angular.copy(item),
                                        item: item,
                                        el: render(item)
                                    };
                                    currentRowEls[id] =  row;
                                }
                                previousEl.after(row.el.last());
                                previousEl = row.el.last();
                            });

                            if (showProfilingInfo) {
                                t = getTime() - t;
                                console.log("Total time: ", t, "ms");
                                console.log("time per row: ", t/list.length);
                            }
                        });

                    }, false);
                });
                element.parent().on('click', '[fast-repeat-id]', function(evt) {
                    var $target = $(this);
                    var rowId = $target.attr('fast-repeat-id');
                    var newScope = listScope.$new(false);
                    // Find index of clicked dom element in list of all children element of the row.
                    // -1 would indicate the row itself was clicked.
                    var elIndex = $target.find('*').index(evt.target);

                    newScope[repeatVarName] = currentRowEls[rowId].item;
                    transclude(newScope, function(clone, scope) {
                        $target.replaceWith(clone);
                        currentRowEls[rowId] = {
                            compiled: true,
                            el: clone
                        };

                        setTimeout(function() {
                            if(elIndex >= 0) {
                                clone.find('*').eq(elIndex).trigger('click');
                            } else {
                                clone.trigger('click');
                            }
                        }, 0);

                    });
                });
            };
        },
    };
}]);
<commit_msg>Fix undefined exceptions.<commit_after>/* globals angular */
angular.module('gc.fastRepeat', []).directive('fastRepeat', ['$compile', '$parse', function ($compile, $parse) {
    'use strict';

    var fastRepeatId = 0,
        showProfilingInfo = false;

    // JSON.stringify replacer function which removes any keys that start with $$.
    // This prevents unnecessary updates when we watch a JSON stringified value.
    function JSONStripper(key, value) {
        if(key.slice && key.slice(0,2) == '$$') { return undefined; }
        return value;
    }

    function getTime() { // For profiling
        if(window.performance && window.performance.now) { return window.performance.now(); }
        else { return (new Date()).getTime(); }
    }

    return {
        restrict: 'A',
        scope: false,
        transclude: 'element',
        priority: 10000,
        compile: function(tElement, tAttrs) {
            return function link(listScope, element, attrs, ctrl, transclude) {
                var repeatParts = attrs.fastRepeat.split(' in ');
                var repeatListName = repeatParts[1], repeatVarName = repeatParts[0];
                var getter = $parse(repeatListName); // getter(scope) should be the value of the list.
                var currentRowEls = {};
                var t;

                // Scope created for evaluating the rows -- child of the scope the list was created in.
                // Note this is almost a misnomer since the list doesn't have a scope of its own.
                var rowScope = listScope.$new(false);
                rowScope[repeatVarName] = getter(listScope)[0] || {}; // The rowTpl will be digested once -- want to make sure it has valid data for the first wasted digest.  Default to first row or {} if no rows

                // Transclude the contents of the fast repeat.
                // This function is called for every row. It reuses the rowTpl and scope for each row.
                transclude(rowScope, function(rowTpl, scope) {
                    function render(item) {
                        scope[repeatVarName] = item;
                        scope.$digest();
                        rowTpl.attr('fast-repeat-id', item.$$fastRepeatId);
                        return rowTpl.clone();
                    }

                    // Here is the main watch. Testing has shown that watching the stringified list can
                    // save roughly 500ms per digest in certain cases.
                    // JSONStripper is used to remove the $$fastRepeatId that we attach to the objects.
                    listScope.$watch(function(scp){ return JSON.stringify(getter(scp), JSONStripper); }, function(list) {
                        list = getter(listScope);

                        if (showProfilingInfo) {
                            t = getTime();
                        }

                        // Rendering is done in a postDigest so that we are outside of the main digest cycle.
                        // This allows us to digest the individual row scope repeatedly without major hackery.
                        listScope.$$postDigest(function() {

                            // Generate ids if necessary and arrange in a hash map
                            var listByIds = {};
                            angular.forEach(list, function(item) {
                                if(!item.$$fastRepeatId) {
                                    item.$$fastRepeatId = ++fastRepeatId;
                                }
                                listByIds[item.$$fastRepeatId] = item;
                            });

                            // Delete removed rows
                            angular.forEach(currentRowEls, function(row, id) {
                                if(!listByIds[id]) {
                                    row.el.detach();
                                }
                            });

                            // Add/rearrange all rows
                            var previousEl = element;
                            angular.forEach(list, function(item) {
                                var id = item.$$fastRepeatId;
                                var row=currentRowEls[id];
                                if(row) {
                                    // We've already seen this one
                                    if(!row.compiled && !angular.equals(row.copy, item)) {
                                        // This item has not been compiled and it apparently has changed -- need to rerender
                                        var newEl = render(item);
                                        row.el.replaceWith(newEl);
                                        row.el = newEl;
                                        row.copy = angular.copy(item);
                                    }
                                } else {
                                    // This must be a new node
                                    row = {
                                        copy: angular.copy(item),
                                        item: item,
                                        el: render(item)
                                    };
                                    currentRowEls[id] =  row;
                                }
                                previousEl.after(row.el.last());
                                previousEl = row.el.last();
                            });

                            if (showProfilingInfo) {
                                t = getTime() - t;
                                console.log("Total time: ", t, "ms");
                                console.log("time per row: ", t/list.length);
                            }
                        });

                    }, false);
                });
                element.parent().on('click', '[fast-repeat-id]', function(evt) {
                    var $target = $(this);
                    var rowId = $target.attr('fast-repeat-id');
                    var newScope = listScope.$new(false);
                    // Find index of clicked dom element in list of all children element of the row.
                    // -1 would indicate the row itself was clicked.
                    var elIndex = $target.find('*').index(evt.target);

                    newScope[repeatVarName] = currentRowEls[rowId].item;
                    transclude(newScope, function(clone, scope) {
                        $target.replaceWith(clone);
                        currentRowEls[rowId] = {
                            compiled: true,
                            el: clone
                        };

                        setTimeout(function() {
                            if(elIndex >= 0) {
                                clone.find('*').eq(elIndex).trigger('click');
                            } else {
                                clone.trigger('click');
                            }
                        }, 0);

                    });
                });
            };
        },
    };
}]);
<|endoftext|>


<commit_before>const path = require('path')

module.exports = {
  context: path.resolve(__dirname, 'src'),
  entry: {
    index: './index.ts',
    book: './book/index.ts'
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: [ '.ts', '.js' ]
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}
<commit_msg>Fix submodule script paths<commit_after>const path = require('path')

module.exports = {
  context: path.resolve(__dirname, 'src'),
  entry: {
    index: './index.ts',
    book: './book/index.ts'
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: [ '.ts', '.js' ]
  },
  output: {
    filename: '[name]/index.js',
    path: path.resolve(__dirname, 'dist')
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'
import LiveTime from './livetime.js'
import moment from 'moment'

class Event extends React.Component {

  static propTypes = {
    subject: React.PropTypes.shape({
      photo: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string.isRequired,
    }).isRequired,
    created_at: React.PropTypes.string.isRequired,
    story: React.PropTypes.string.isRequired,
    object1: React.PropTypes.shape({
      entity: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string
    }),
    object2: React.PropTypes.shape({
      entity: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string
    }),

  }

  static defaultProps = {
  }

  render() {
    var description = `<a href="${this.props.subject.link}">${this.props.subject.text}</a> ${this.props.story}`;
    description = this._replace(description, 'object1', this.props.object1);
    description = this._replace(description, 'object2', this.props.object2);
    return (

<LiveTime time={this.props.created_at} /> on {moment(this.props.created_at).format('dddd, MMM D, YYYY @ h:mm A')}

    )
  }

  _replace(description, key, object) {
    if(object) {
      let replacement = `the ${object.entity} `;
      replacement += (object.link) ? `<a href="${object.link}">${object.text}</a>` : object.text;
      description = description.replace(`{${key}}`, replacement)
    }
    return description;
  }

}

export default Event
<commit_msg>implement default avatar and make links use react-router in feeds<commit_after>import React from 'react'
import ReactDOM from 'react-dom'
import LiveTime from './livetime.js'
import {Link} from 'react-router'
import moment from 'moment'

class Event extends React.Component {

  static propTypes = {
    subject: React.PropTypes.shape({
      photo: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string.isRequired,
    }).isRequired,
    created_at: React.PropTypes.string.isRequired,
    story: React.PropTypes.string.isRequired,
    object1: React.PropTypes.shape({
      entity: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string
    }),
    object2: React.PropTypes.shape({
      entity: React.PropTypes.string.isRequired,
      text: React.PropTypes.string.isRequired,
      link: React.PropTypes.string
    }),

  }

  static defaultProps = {
  }

  render() {
    let description = ` ${this.props.story}`;
    description = this._replace(description, 'object1', this.props.object1);
    description = this._replace(description, 'object2', this.props.object2);
    let photo = this.props.subject.photo || '/images/photo.jpg'
    return (

<LiveTime time={this.props.created_at} /> on {moment(this.props.created_at).format('dddd, MMM D, YYYY @ h:mm A')}

<Link to={this.props.subject.link}>{this.props.subject.text}</Link>

    )
  }

  _replace(description, key, object) {
    if(object) {
      let replacement = `the ${object.entity} `;
      replacement += (object.link) ? `<a href="${object.link}">${object.text}</a>` : object.text;
      description = description.replace(`{${key}}`, replacement)
    }
    return description;
  }

}

export default Event
<|endoftext|>


<commit_before>/*
 * flipbooker
 * https://github.com/corporadobob/flipbooker
 *
 * Copyright (c) 2014 JC
 * Licensed under the MIT license.
 */

(function($) {

  $.flipbooker = function(imgArr, options) {

    var opts = $.extend(true, {}, $.flipbooker.defaults, options),
    currentIndex = 0,
    $container = $(opts.container),
    $image,
    imgArrSize = imgArr.length,
    currentImg;

    // set up the image element
    $container.append('<img>');
    $image = $container.children('img');

    function plugin(){

      // set the image source to the currentImg
      // object's href value
      currentImg = imgArr[currentIndex];
      $image.attr('src', currentImg.href);

      // sleep if the currentImg object requests a pause
      if (currentImg.pause) {
        $.flipbooker.sleep(currentImg.pause);
      }

      // move onto the next image object
      currentIndex++;

      // after all images have been cycled through
      if (currentIndex >= imgArrSize) {

        // fire callback and reset the index
        opts.cb.call(this);
        currentIndex = 0;

        // loop?
        if (!opts.loop) {
          $.flipbooker.pause();
        }
      }
    }

    // loop through the plugin action
    var looper = setInterval(plugin, opts.delay);

    // listen for events
    $(window).on('pause:flipbooker', function(){
      clearInterval(looper);
    });
    $(window).on('unpause:flipbooker', function(){
      looper = setInterval(plugin, opts.delay);
    });

  };

  // Utilities and defaults
  $.flipbooker.pause = function(){
    $(window).trigger('pause:flipbooker');
  };

  $.flipbooker.unpause = function(){
    $(window).trigger('unpause:flipbooker');
  };

  $.flipbooker.sleep = function(milliseconds){
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
      if ((new Date().getTime() - start) > milliseconds){
        break;
      }
    }
  };

  $.flipbooker.defaults = {
    container: '#flipbook',
    loop: true,
    delay: 50,
    cb: function(){}
  };

}(jQuery));
<commit_msg>change function name from unpause to play<commit_after>/*
 * flipbooker
 * https://github.com/corporadobob/flipbooker
 *
 * Copyright (c) 2014 JC
 * Licensed under the MIT license.
 */

(function($) {

  $.flipbooker = function(imgArr, options) {

    var opts = $.extend(true, {}, $.flipbooker.defaults, options),
    currentIndex = 0,
    $container = $(opts.container),
    $image,
    imgArrSize = imgArr.length,
    currentImg;

    // set up the image element
    $container.append('<img>');
    $image = $container.children('img');

    function plugin(){

      // set the image source to the currentImg
      // object's href value
      currentImg = imgArr[currentIndex];
      $image.attr('src', currentImg.href);

      // sleep if the currentImg object requests a pause
      if (currentImg.pause) {
        $.flipbooker.sleep(currentImg.pause);
      }

      // move onto the next image object
      currentIndex++;

      // after all images have been cycled through
      if (currentIndex >= imgArrSize) {

        // fire callback and reset the index
        opts.cb.call(this);
        currentIndex = 0;

        // loop?
        if (!opts.loop) {
          $.flipbooker.pause();
        }
      }
    }

    // loop through the plugin action
    var looper = setInterval(plugin, opts.delay);

    // listen for events
    $(window).on('pause:flipbooker', function(){
      clearInterval(looper);
    });
    $(window).on('play:flipbooker', function(){
      looper = setInterval(plugin, opts.delay);
    });

  };

  // Utilities and defaults
  $.flipbooker.pause = function(){
    $(window).trigger('pause:flipbooker');
  };

  $.flipbooker.play = function(){
    $(window).trigger('play:flipbooker');
  };

  $.flipbooker.sleep = function(milliseconds){
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
      if ((new Date().getTime() - start) > milliseconds){
        break;
      }
    }
  };

  $.flipbooker.defaults = {
    container: '#flipbook',
    loop: true,
    delay: 50,
    cb: function(){}
  };

}(jQuery));
<|endoftext|>