<commit_before>var sanitizeHtml = require('sanitize-html')
var end = require('../lib/end')

export default function Organization (arcgis) {
  function get (id = 'self') {
    return arcgis.request({url: `portals/${id}`})
      .then(function (o) {
        o.description = sanitizeHtml(o.description)
        return o
      })
  }

  return function getOrganization (orgId, cb) {
    var promise = get(orgId).then(function (o) {
      o.get = get
      o.update = function (options, cb) {
        var updatePromise = arcgis.request({
          url: `portals/${o.id}/update`,
          form: options,
          post: true
        })
          .then(function (confirmation) {
            return o.get(o.id)
          })
        return end(updatePromise, cb)
      }
      o.content = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        return end(arcgis.search({
          queryString: `"" accountid:${o.id}`,
          page: page,
          sort: sort,
          order: order
        }), cb)
      }
      o.members = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        return end(o.request({
          url: 'portals/self/users',
          form: {
            num: num,
            page: page,
            sort: sort,
            order: order
          }
        }), cb)
      }
      o.featured = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        var featuredPromise = o.get(o.id)
          .then(function (o) {
            var featuredGroupId = o.homePageFeaturedContent.split(':')[1]
            return o.group(featuredGroupId)
              .then(function (group) {
                return group.content({
                  num: num,
                  page: page,
                  sort: sort,
                  order: order
                })
              })
          })
        return end(featuredPromise, cb)
      }

      return o
    })
    return end(promise, cb)
  }
}
<commit_msg>o.req => arcgis.req<commit_after>var sanitizeHtml = require('sanitize-html')
var end = require('../lib/end')

export default function Organization (arcgis) {
  function get (id = 'self') {
    return arcgis.request({url: `portals/${id}`})
      .then(function (o) {
        o.description = sanitizeHtml(o.description)
        return o
      })
  }

  return function getOrganization (orgId, cb) {
    var promise = get(orgId).then(function (o) {
      o.get = get
      o.update = function (options, cb) {
        var updatePromise = arcgis.request({
          url: `portals/${o.id}/update`,
          form: options,
          post: true
        })
          .then(function (confirmation) {
            return o.get(o.id)
          })
        return end(updatePromise, cb)
      }
      o.content = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        return end(arcgis.search({
          queryString: `"" accountid:${o.id}`,
          page: page,
          sort: sort,
          order: order
        }), cb)
      }
      o.members = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        return end(arcgis.request({
          url: 'portals/self/users',
          form: {
            num: num,
            page: page,
            sort: sort,
            order: order
          }
        }), cb)
      }
      o.featured = function ({ num = 100, page = 0, sort = 'created', order = 'desc' } = {}, cb) {
        var featuredPromise = o.get(o.id)
          .then(function (o) {
            var featuredGroupId = o.homePageFeaturedContent.split(':')[1]
            return o.group(featuredGroupId)
              .then(function (group) {
                return group.content({
                  num: num,
                  page: page,
                  sort: sort,
                  order: order
                })
              })
          })
        return end(featuredPromise, cb)
      }

      return o
    })
    return end(promise, cb)
  }
}
<|endoftext|>


<commit_before>var CHS = require( 'chs' )
var isBuffer = Buffer.isBuffer

/**
 * MBR Partition
 * @param {Buffer} buffer (optional)
 * @param {Number} start (optional)
 * @param {Number} end (optional)
 * @return {Partition}
 */
function Partition( buffer, start, end ) {

  if( !(this instanceof Partition) )
    return new Partition( buffer, start, end )

  if( buffer != null && !isBuffer( buffer ) )
    throw new TypeError( 'Argument must be a Buffer' )

  this.status = 0x00
  this.type = 0x00
  this.sectors = 0x00
  this.firstLBA = 0x00
  this.firstCHS = new CHS()
  this.lastCHS = new CHS()

  if( buffer != null ) {
    this.buffer = buffer.slice( start, end )
  }

}

/**
 * List of partition type IDs
 * used for extended partitions
 * @type {Array}
 */
Partition.EXTENDED = [
  // MS Extended Partition (CHS)
  0x05,
  // MS Extended Partition (LBA)
  0x0F,
  // Linux Extended Partition
  0x85,
  // Other Extended Partition Types:
  // Hidden
  0x15, 0x1F, 0x91, 0x9B,
  // Access-restricted
  0x5E, 0x5F,
  // Secured
  0xCF, 0xD5,
  // DR DOS Secured Extended Partition
  0xC5,
]

/**
 * Parse a MBR Partition structure
 * @param {Buffer} buffer (optional)
 * @param {Number} start (optional)
 * @param {Number} end (optional)
 * @return {Partition}
 */
Partition.parse = function( buffer, start, end ) {
  return new Partition( buffer, start, end )
}

/**
 * Determines if a given partition type
 * describes an extended partition
 * @param  {Number}  type
 * @return {Boolean}
 */
Partition.isExtended = function( type ) {
  return !!~Partition.EXTENDED.indexOf( type )
}

/**
 * Partition prototype
 * @type {Object}
 */
Partition.prototype = {

  constructor: Partition,

  get statusText() {
    switch( this.status ) {
      case 0x80: return 'active'; break
      case 0x00: return 'inactive'; break
      default:   return 'invalid'; break
    }
  },

  get active() {
    return this.status === 0x80
  },

  get inactive() {
    return this.status === 0x00
  },

  get invalid() {
    return !this.active && !this.inactive
  },

  get extended() {
    return Partition.isExtended( this.type )
  },

  get lastLBA() {
    return this.firstLBA + this.sectors
  },

  /**
   * Calculates the partition's offset in bytes
   * @param  {Number} blockSize (optional, default: 512)
   * @return {Number}
   */
  byteOffset: function( blockSize ) {
    blockSize = blockSize || 512
    return this.firstLBA * blockSize
  },

  /**
   * Calculates the partition's size in bytes
   * @param  {Number} blockSize (optional, default: 512)
   * @return {Number}
   */
  byteSize: function( blockSize ) {
    blockSize = blockSize || 512
    return this.sectors * blockSize
  },

  parse: function( buffer, start, end ) {
    this.buffer = buffer.slice( start, end )
  },

  get buffer() {

    var buffer = new Buffer( 0x10 )
    buffer.fill( 0 )

    buffer.writeUInt8( this.status, 0 )
    buffer.writeUInt8( this.type, 4 )
    buffer.writeUInt32LE( this.firstLBA, 8 )
    buffer.writeUInt32LE( this.sectors, 12 )

    this.firstCHS.buffer.copy( buffer, 1 )
    this.lastCHS.buffer.copy( buffer, 5 )

    return buffer

  },

  set buffer( value ) {

    if( !isBuffer( value ) )
      throw new TypeError( 'Argument must be a Buffer' )

    if( value.length < 16 ) {
      throw new SyntaxError(
        'Partition entry size unacceptable:' +
        'expected 16 bytes, but got ' + data.length
      )
    }

    this.status   = value.readUInt8( 0 )
    this.type     = value.readUInt8( 4 )
    this.firstLBA = value.readUInt32LE( 8 )
    this.sectors  = value.readUInt32LE( 12 )

    this.firstCHS.buffer = value.slice( 1, 4 )
    this.lastCHS.buffer = value.slice( 5, 8 )

  },

}

// Exports
module.exports = Partition
<commit_msg>Fixed CHS buffer in lib/partition<commit_after>var CHS = require( 'chs' )
var isBuffer = Buffer.isBuffer

/**
 * MBR Partition
 * @param {Buffer} buffer (optional)
 * @param {Number} start (optional)
 * @param {Number} end (optional)
 * @return {Partition}
 */
function Partition( buffer, start, end ) {

  if( !(this instanceof Partition) )
    return new Partition( buffer, start, end )

  if( buffer != null && !isBuffer( buffer ) )
    throw new TypeError( 'Argument must be a Buffer' )

  this.status = 0x00
  this.type = 0x00
  this.sectors = 0x00
  this.firstLBA = 0x00
  this.firstCHS = new CHS()
  this.lastCHS = new CHS()

  if( buffer != null ) {
    this.buffer = buffer.slice( start, end )
  }

}

/**
 * List of partition type IDs
 * used for extended partitions
 * @type {Array}
 */
Partition.EXTENDED = [
  // MS Extended Partition (CHS)
  0x05,
  // MS Extended Partition (LBA)
  0x0F,
  // Linux Extended Partition
  0x85,
  // Other Extended Partition Types:
  // Hidden
  0x15, 0x1F, 0x91, 0x9B,
  // Access-restricted
  0x5E, 0x5F,
  // Secured
  0xCF, 0xD5,
  // DR DOS Secured Extended Partition
  0xC5,
]

/**
 * Parse a MBR Partition structure
 * @param {Buffer} buffer (optional)
 * @param {Number} start (optional)
 * @param {Number} end (optional)
 * @return {Partition}
 */
Partition.parse = function( buffer, start, end ) {
  return new Partition( buffer, start, end )
}

/**
 * Determines if a given partition type
 * describes an extended partition
 * @param  {Number}  type
 * @return {Boolean}
 */
Partition.isExtended = function( type ) {
  return !!~Partition.EXTENDED.indexOf( type )
}

/**
 * Partition prototype
 * @type {Object}
 */
Partition.prototype = {

  constructor: Partition,

  get statusText() {
    switch( this.status ) {
      case 0x80: return 'active'; break
      case 0x00: return 'inactive'; break
      default:   return 'invalid'; break
    }
  },

  get active() {
    return this.status === 0x80
  },

  get inactive() {
    return this.status === 0x00
  },

  get invalid() {
    return !this.active && !this.inactive
  },

  get extended() {
    return Partition.isExtended( this.type )
  },

  get lastLBA() {
    return this.firstLBA + this.sectors
  },

  /**
   * Calculates the partition's offset in bytes
   * @param  {Number} blockSize (optional, default: 512)
   * @return {Number}
   */
  byteOffset: function( blockSize ) {
    blockSize = blockSize || 512
    return this.firstLBA * blockSize
  },

  /**
   * Calculates the partition's size in bytes
   * @param  {Number} blockSize (optional, default: 512)
   * @return {Number}
   */
  byteSize: function( blockSize ) {
    blockSize = blockSize || 512
    return this.sectors * blockSize
  },

  parse: function( buffer, start, end ) {
    this.buffer = buffer.slice( start, end )
  },

  get buffer() {

    var buffer = new Buffer( 0x10 )
    buffer.fill( 0 )

    buffer.writeUInt8( this.status, 0 )
    buffer.writeUInt8( this.type, 4 )
    buffer.writeUInt32LE( this.firstLBA, 8 )
    buffer.writeUInt32LE( this.sectors, 12 )

    this.firstCHS.copy( buffer, 1 )
    this.lastCHS.copy( buffer, 5 )

    return buffer

  },

  set buffer( value ) {

    if( !isBuffer( value ) )
      throw new TypeError( 'Argument must be a Buffer' )

    if( value.length < 16 ) {
      throw new SyntaxError(
        'Partition entry size unacceptable:' +
        'expected 16 bytes, but got ' + data.length
      )
    }

    this.status   = value.readUInt8( 0 )
    this.type     = value.readUInt8( 4 )
    this.firstLBA = value.readUInt32LE( 8 )
    this.sectors  = value.readUInt32LE( 12 )

    this.firstCHS.buffer = value.slice( 1, 4 )
    this.lastCHS.buffer = value.slice( 5, 8 )

  },

}

// Exports
module.exports = Partition
<|endoftext|>


<commit_before>/*
 * electron-builder
 * https://github.com/loopline-systems/electron-builder
 *
 * Licensed under the MIT license.
 */

module.exports = {
  //osx   : require( './osx' ),
  win   : require( './win' ),
  win32 : require( './win' ),
  linux : require( './linux' )
};
<commit_msg>Fix missing osx platform in platforms.js<commit_after>/*
 * electron-builder
 * https://github.com/loopline-systems/electron-builder
 *
 * Licensed under the MIT license.
 */

module.exports = {
  osx   : require( './osx' ),
  win   : require( './win' ),
  win32 : require( './win' ),
  linux : require( './linux' )
};
<|endoftext|>


<commit_before>module.exports = class Portfolio {
  constructor() {
    this.positions = {};
    // this.initialCash;
    this.totalPortfolioValue;
    // this.closedPositions;
  }

  /*****************************|
  |********  Modifiers  ********|
  |*****************************/

  /**
   * Adds new position to Portfolio
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  // addNewPosition(currencyPair, quantity, timestamp) {
  //   if (!(currencyPair in this.positions) && quantity != undefined && timestamp != undefined) {
  //     console.log('\nAdding new position...');
  //     var position = {
  //       currencyPair: currencyPair,
  //       quantity: quantity,
  //       timestamp: [timestamp]
  //     };
  //     console.log('NOW');
  //     this.printAllPositions();
  //     this.positions[currencyPair] = position;
  //     this.positions[currencyPair].positionLog = [];
  //     console.log('New position added:');
  //     console.log(this);
  //     console.log();
  //   }
  // }

  /**
   * Modifies an existing position, if position doesn't exist, add new one.
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  // modifiyPosition(currencyPair, quantity, timestamp) {
  //   console.log('EFFORTS',exports.candlestickData);
  //   console.log('--modifiyPosition');
  //   if (currencyPair != undefined && quantity != undefined && timestamp != undefined) {
  //     if (currencyPair in this.positions) {
  //       console.log('## mod',currencyPair, quantity, timestamp);
  //       this.positions[currencyPair].quantity += quantity;
  //       //this.positions[currencyPair].timestamp.push(timestamp);
  //       this.logPosition();
  //       this.positions[currencyPair].positionLog.push(Object.assign({}, this.positions[currencyPair]));
  //       console.log('PORTFOLIO: modifying position', currencyPair);
  //     } else {
  //       this.addNewPosition(currencyPair, quantity, timestamp);
  //       console.log('PORTFOLIO: added new position', currencyPair);
  //     }
  //   }
  //   else {
  //     console.log('\n### ERROR\ncurrencyPair:' ,currencyPair);
  //     console.log('quantity:', quantity);
  //     console.log('timestamp:', timestamp);
  //     throw 'ERROR: at least one argument is undefined.', console.log(new Error().stack);
  //   }
  // }

  /**
   * Modifies an existing position, if position doesn't exist, add new one.
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  modifiyPosition2(order, marketData) {
    console.log('+++ Portfolio: modifying position...');
    var pair = order.currencyPair;
    var quantity = order.quantity;
    var timestamp = order.timestamp;

    //console.log(order);
    if (pair in this.positions) {
      var currentPosition = this.positions[pair];
      currentPosition.quantity += quantity;
      this.logPosition(order);
      this.updatePortfolioValue2(order, marketData);
    }
    else {
      this.addNewPosition2(order);
      this.logPosition(order);
      //this.updatePortfolioValue2(order, marketData);
    }

  }

  /**
   * Adds new position to Portfolio
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  addNewPosition2(order) {
    this.positions[order.currencyPair] = order;
    this.positions[order.currencyPair].positionLog = [];
  }

  logPosition(position) {
    //console.log(position);
    //var position_ = jQuery.extend(true, {}, position);
    var cloneOfA = JSON.parse(JSON.stringify(position));
    this.positions[position.currencyPair].positionLog.push(cloneOfA);
  }

  /**
  Takes in current market price for a currencyPair. This updates the portfolio.
  */
  updatePortfolioValue2(order, marketData) {
    var tickIndex = this.findTickIndexByTimestamp(marketData, order.timestamp);
    this.positions[order.currencyPair].value = order.quantity * marketData[tickIndex].close;
  }

  findTickIndexByTimestamp(candlestickData, timestamp) {
    if (timestamp != null) {
      for (var i = 0; i < candlestickData.length; i++) {
        if (candlestickData[i].date == timestamp) {
          return i;
        }
      }
      throw 'ERROR: cannot find tick', console.log(new Error().stack);;
    }
    else {
      throw 'ERROR: timestamp is null.', console.log(new Error().stack);
    }
  }

  // /** TODO
  //  * Sells all currency of current pair.
  //  * @param {string} currencyPair reference
  //  * @param {int} quantity amount of currency to add to position
  //  * @param {int} timestamp unix time
  //  */
  // exitPosition(currencyPair) {
  //
  // }

  // /* Getters */
  // getAllPositions() {
  //
  // }
  printPortfolio() {
    console.log('\n-----------PORTFOLIO------------');
    console.log(this);
    console.log('---------------------------------\n');
  }

  calculateHistoricalPerformance(candlestickData, currencyPair, metric) {
    var backtest = [];
    // [timestamp, portfolioValue]

    // This function runs through the positionLog and calculates the portfolio
    // value at every time step.

    var numPositions = this.positions[currencyPair].positionLog.length;
    var positionLog = this.positions[currencyPair].positionLog;

    var currentPortfolioValue = 0;
    for (var i = 0; i < candlestickData.length; i++) {
      var positionLog = this.positions[currencyPair].positionLog;
      for (var j = 0; j < numPositions; j++) {
        if (candlestickData[i].date == positionLog[j].timestamp) {
          currentPortfolioValue = positionLog[j].quantity * candlestickData[i].close;
          console.log([candlestickData[i].date, currentPortfolioValue]);
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
        else {
          currentPortfolioValue = candlestickData[i].close *
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
      }
    }
    return backtest;
  }

  // printHistoricalPerformance(currencyPair, metric) {
  //   if (metric == 'PnL') {
  //     for (var i = 0; i < this.positions[currencyPair].positionLog.length; i++) {
  //       var valueAtTime = this.positions[currencyPair].positionLog[i].timestamp[i];
  //       var portfolioValue = this.positions[currencyPair].positionLog[i].value;
  //       console.log('Time:',valueAtTime,'|', 'Value:', portfolioValue);
  //     }
  //   }
  //   else {
  //     console.log('no metric availble for', metric);
  //   }
  // }
  //
  // printPositionLog(currencyPair) {
  //   console.log('Past Positions:');
  //   for (var i = 0; i < this.positions[currencyPair].positionLog.length; i++) {
  //     console.log(this.positions[currencyPair].positionLog[i]);
  //   }
  // }

  /**
  Takes in current market price for a currencyPair. This updates the portfolio.
  */
  // updatePortfolioValue(currencyPair, price) {
  //   var quantity = this.positions[currencyPair].quantity;
  //   this.positions[currencyPair].value =  quantity * price;
  // }

  /**
   * Calculates current portfolio value by multiplying quantity of currency
   * by price of currency.
   * @param {object} marketPriceData An object that contains market data for
   * each currency. {currencyA: price, currencyB: price, ...}
   */
  // getTotalPortfolioValue(marketPriceData) {
  //
  // }
  // getTradeLogs() {
  //
  // }
  // getSharpe() {
  //   // other desired metrics
  // }
}

/*
Class structure

Portfolio --> positions -->

Portfolio

* Positions
  exchange
    currencypair
      :amount
    currencypair
      :amount
  exchange
    currencypair
      :amount
    currencypair
      :amount
* Metrics
    current total value
    summary view
    sharpe ratios
* Logs
    exchange
      list of trades
    exchange
      list of trades

*/
<commit_msg>Fixed portfolio<commit_after>module.exports = class Portfolio {
  constructor() {
    this.positions = {};
    // this.initialCash;
    this.totalPortfolioValue;
    // this.closedPositions;
  }

  /*****************************|
  |********  Modifiers  ********|
  |*****************************/

  /**
   * Adds new position to Portfolio
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  // addNewPosition(currencyPair, quantity, timestamp) {
  //   if (!(currencyPair in this.positions) && quantity != undefined && timestamp != undefined) {
  //     console.log('\nAdding new position...');
  //     var position = {
  //       currencyPair: currencyPair,
  //       quantity: quantity,
  //       timestamp: [timestamp]
  //     };
  //     console.log('NOW');
  //     this.printAllPositions();
  //     this.positions[currencyPair] = position;
  //     this.positions[currencyPair].positionLog = [];
  //     console.log('New position added:');
  //     console.log(this);
  //     console.log();
  //   }
  // }

  /**
   * Modifies an existing position, if position doesn't exist, add new one.
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  // modifiyPosition(currencyPair, quantity, timestamp) {
  //   console.log('EFFORTS',exports.candlestickData);
  //   console.log('--modifiyPosition');
  //   if (currencyPair != undefined && quantity != undefined && timestamp != undefined) {
  //     if (currencyPair in this.positions) {
  //       console.log('## mod',currencyPair, quantity, timestamp);
  //       this.positions[currencyPair].quantity += quantity;
  //       //this.positions[currencyPair].timestamp.push(timestamp);
  //       this.logPosition();
  //       this.positions[currencyPair].positionLog.push(Object.assign({}, this.positions[currencyPair]));
  //       console.log('PORTFOLIO: modifying position', currencyPair);
  //     } else {
  //       this.addNewPosition(currencyPair, quantity, timestamp);
  //       console.log('PORTFOLIO: added new position', currencyPair);
  //     }
  //   }
  //   else {
  //     console.log('\n### ERROR\ncurrencyPair:' ,currencyPair);
  //     console.log('quantity:', quantity);
  //     console.log('timestamp:', timestamp);
  //     throw 'ERROR: at least one argument is undefined.', console.log(new Error().stack);
  //   }
  // }

  /**
   * Modifies an existing position, if position doesn't exist, add new one.
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  modifiyPosition2(order, marketData) {
    console.log('+++ Portfolio: modifying position...');
    var pair = order.currencyPair;
    var quantity = order.quantity;
    var timestamp = order.timestamp;

    //console.log(order);
    if (pair in this.positions) {
      var currentPosition = this.positions[pair];
      currentPosition.quantity += quantity;
      this.logPosition(order);
      this.updatePortfolioValue2(order, marketData);
    }
    else {
      this.addNewPosition2(order);
      this.logPosition(order);
      //this.updatePortfolioValue2(order, marketData);
    }

  }

  /**
   * Adds new position to Portfolio
   * @param {string} currencyPair reference
   * @param {int} quantity amount of currency to add to position
   * @param {int} timestamp unix time
   */
  addNewPosition2(order) {
    this.positions[order.currencyPair] = order;
    this.positions[order.currencyPair].positionLog = [];
  }

  logPosition(position) {
    //console.log(position);
    //var position_ = jQuery.extend(true, {}, position);
    var cloneOfA = JSON.parse(JSON.stringify(position));
    this.positions[position.currencyPair].positionLog.push(cloneOfA);
  }

  /**
  Takes in current market price for a currencyPair. This updates the portfolio.
  */
  updatePortfolioValue2(order, marketData) {
    var tickIndex = this.findTickIndexByTimestamp(marketData, order.timestamp);
    this.positions[order.currencyPair].value = order.quantity * marketData[tickIndex].close;
  }

  findTickIndexByTimestamp(candlestickData, timestamp) {
    if (timestamp != null) {
      for (var i = 0; i < candlestickData.length; i++) {
        if (candlestickData[i].date == timestamp) {
          return i;
        }
      }
      throw 'ERROR: cannot find tick', console.log(new Error().stack);;
    }
    else {
      throw 'ERROR: timestamp is null.', console.log(new Error().stack);
    }
  }

  // /** TODO
  //  * Sells all currency of current pair.
  //  * @param {string} currencyPair reference
  //  * @param {int} quantity amount of currency to add to position
  //  * @param {int} timestamp unix time
  //  */
  // exitPosition(currencyPair) {
  //
  // }

  // /* Getters */
  // getAllPositions() {
  //
  // }
  printPortfolio() {
    console.log('\n-----------PORTFOLIO------------');
    console.log(this);
    console.log('---------------------------------\n');
  }
  /*
  calculateHistoricalPerformance(candlestickData, currencyPair, metric) {
    var backtest = [];
    // [timestamp, portfolioValue]

    // This function runs through the positionLog and calculates the portfolio
    // value at every time step.

    var numPositions = this.positions[currencyPair].positionLog.length;
    var positionLog = this.positions[currencyPair].positionLog;

    var currentPortfolioValue = 0;
    for (var i = 0; i < candlestickData.length; i++) {
      var positionLog = this.positions[currencyPair].positionLog;
      for (var j = 0; j < numPositions; j++) {
        if (candlestickData[i].date == positionLog[j].timestamp) {
          currentPortfolioValue = positionLog[j].quantity * candlestickData[i].close;
          console.log([candlestickData[i].date, currentPortfolioValue]);
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
        else {
          currentPortfolioValue = candlestickData[i].close *
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
      }
    }
    return backtest;
  } */

  calculateHistoricalPerformance(candlestickData, currencyPair, metric) {
    // Container for the portfolio value over time
    var backtest = [];

    // Initializing starting amounts
    var USD = 1000;
    var BTC = 0;

    // Pulling the positionLog from this.positions
    var numPositions = this.positions[currencyPair].positionLog.length;
    var positionLog = this.positions[currencyPair].positionLog;
    var currentPortfolioValue = 0;

    // Looping through USD-BTC data, looking at each date-close pair
    for (var i = 0; i < candlestickData.length; i++) {

      // Looping through every position
      for (var j = 0; j < numPositions; j++) {

        // If this is a date we need to execute a position, execute it
        if (candlestickData[i].date == positionLog[j].timestamp) {

          // If BUY, use all USD to purchase BTC, using current exchange rate
          if(positionLog[j].longShort == 'BUY'){
            BTC = USD/candlestickData[i].close;
            USD = 0;
          }
          // If SELL, use all BTC to purchase USD, using current exchange rate
          else {
            // If we don't have any BTC, that means we havent executed a BUY yet, so continue
            if(BTC == 0){
              continue;
            }
            USD = BTC*candlestickData[i].close;
            BTC = 0;
          }

          // Pushing the portfolio value and timestamp after executing a position
          currentPortfolioValue = USD + BTC * candlestickData[i].close;
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
        else {
          // Pushing the portfolio value and timestamp
          currentPortfolioValue = USD + BTC * candlestickData[i].close;
          backtest.push([candlestickData[i].date, currentPortfolioValue]);
        }
      }
    }
    return backtest;
  }

  // printHistoricalPerformance(currencyPair, metric) {
  //   if (metric == 'PnL') {
  //     for (var i = 0; i < this.positions[currencyPair].positionLog.length; i++) {
  //       var valueAtTime = this.positions[currencyPair].positionLog[i].timestamp[i];
  //       var portfolioValue = this.positions[currencyPair].positionLog[i].value;
  //       console.log('Time:',valueAtTime,'|', 'Value:', portfolioValue);
  //     }
  //   }
  //   else {
  //     console.log('no metric availble for', metric);
  //   }
  // }
  //
  // printPositionLog(currencyPair) {
  //   console.log('Past Positions:');
  //   for (var i = 0; i < this.positions[currencyPair].positionLog.length; i++) {
  //     console.log(this.positions[currencyPair].positionLog[i]);
  //   }
  // }

  /**
  Takes in current market price for a currencyPair. This updates the portfolio.
  */
  // updatePortfolioValue(currencyPair, price) {
  //   var quantity = this.positions[currencyPair].quantity;
  //   this.positions[currencyPair].value =  quantity * price;
  // }

  /**
   * Calculates current portfolio value by multiplying quantity of currency
   * by price of currency.
   * @param {object} marketPriceData An object that contains market data for
   * each currency. {currencyA: price, currencyB: price, ...}
   */
  // getTotalPortfolioValue(marketPriceData) {
  //
  // }
  // getTradeLogs() {
  //
  // }
  // getSharpe() {
  //   // other desired metrics
  // }
}

/*
Class structure

Portfolio --> positions -->

Portfolio

* Positions
  exchange
    currencypair
      :amount
    currencypair
      :amount
  exchange
    currencypair
      :amount
    currencypair
      :amount
* Metrics
    current total value
    summary view
    sharpe ratios
* Logs
    exchange
      list of trades
    exchange
      list of trades

*/
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var fm = require('front-matter');
var async = require('async');

module.exports = function (postsDir, permLinkFunction, useCache) {
    var _posts;

    if (!useCache) {
        console.log('WARNING: not using cache!');
    }

    fs.watch(postsDir, { persistent: false }, function () {
        // flush cache on changes
        if (useCache && _posts) {
            _posts = null;
        }
    });

    this.findPosts = function (count, offset, callback) {
        readPosts(function (err, posts) {
            callback(err, err ? null : posts.slice(offset, offset + count));
        });
    }

    this.getPost = function (permLink, callback) {
        readPosts(function (err, posts) {
            callback(err, err ? null : getMatchingPost(posts, permLink));
        });
    }

    var getMatchingPost = function (posts, permLink) {
        var matchingPosts = posts.filter(function (p) {
            return p.attributes.link === permLink;
        });
        return matchingPosts.length > 0 ? matchingPosts[0] : null;
    }

    var readPosts = function (callback) {
        if (useCache && _posts) {
            callback(null, _posts);
            return;
        }

        fs.readdir(postsDir, function (err, files) {
            if (err) {
                callback(err);
            } else {
                files = files.map(function (f) {
                    return path.join(postsDir, f);
                });

                async.map(files, fs.readFile, function (err, postFiles) {
                    if (err) {
                        callback(err);
                    } else {
                        var posts = postFiles.map(parsePost).filter(function (post) {
                            return post;
                        });

                        posts = posts.sort(function (a, b) {
                            return (new Date(b.attributes.date)) - (new Date(a.attributes.date));
                        });
                        for (var p = 0; p < posts.length; p++) {
                            if (p > 0) {
                                posts[p].next = { attributes: posts[p - 1].attributes };
                            }
                            if (p < posts.length - 1) {
                                posts[p].previous = { attributes: posts[p + 1].attributes };
                            }
                            if (!posts[p].attributes.link) {
                                try {
                                    posts[p].attributes.link = permLinkFunction(posts[p].attributes);
                                } catch (err) {
                                    var msg = 'Error calling permLinkFunction for ' + files[p];
                                    if(typeof err === Error) {
                                        err.message = msg + ': ' + err.message;
                                    }
                                    else {
                                        err = new Error(msg + ': ' + err);
                                    }
                                    callback(err);
                                    return;
                                }
                            }
                        }

                        if (useCache) {
                            _posts = posts;
                        }

                        callback(null, posts);
                    }
                });
            }
        });
    }

    var parsePost = function (fileContents) {
        var content = parseFrontMatter(fileContents.toString());
        if (content)
            content.body = parseBody(content.body);
        return content;
    }

    var parseFrontMatter = function (fileContents) {
        // quick check for front-matter, skip the file if its missing
        if (fileContents.slice(0, 3) !== '---') {
            return null;
        }
        return fm(fileContents);
    }

    var parseBody = function (body) {
        var md = require('markdown');
        return md.parse(body);
    }
}

<commit_msg>Restructuring and clean up of posts repo<commit_after>var fs = require('fs');
var path = require('path');
var fm = require('front-matter');
var async = require('async');

module.exports = function (postsDir, permLinkFunction, useCache) {
    var _posts;

    if (!useCache) {
        console.log('WARNING: not using cache!');
    }

    fs.watch(postsDir, { persistent: false }, function () {
        // flush cache on changes
        if (useCache && _posts) {
            _posts = null;
        }
    });

    this.findPosts = function (count, offset, callback) {
        readPosts(function (err, posts) {
            callback(err, err ? null : posts.slice(offset, offset + count));
        });
    };

    this.getPost = function (permLink, callback) {
        readPosts(function (err, posts) {
            callback(err, err ? null : getMatchingPost(posts, permLink));
        });
    };
};

var getMatchingPost = function (posts, permLink) {
    var matchingPosts = posts.filter(function (p) {
        return p.attributes.link === permLink;
    });
    return matchingPosts.length > 0 ? matchingPosts[0] : null;
};

// Wrapper around reading posts to handle caching
var readPosts = function(callback) {
    if (useCache && _posts) {
        callback(null, _posts);
        return;
    }

    doReadPosts(function(err, posts) {
        if(useCache && !err) {
            _posts = posts;
        }
        callback(err, posts);
    });
};

var doReadPosts = function (callback) {
    async.waterfall([
        function(next) {
            fs.readdir(postsDir, next);
        },
        function(fileNames, next) {
            async.map(fileNames.map(getAbsolutePath), fs.readFile, next);
        },
        function(files, next) {
            var posts = files.map(parsePost).filter(notNull).sort(byDate);

            // create next/prev metadata
            for (var p = 0; p < posts.length; p++) {
                if (p > 0) {
                    posts[p].next = stripBody(posts[p - 1]);
                }
                if (p < posts.length - 1) {
                    posts[p].previous = stripBody(posts[p + 1]);
                }
            }

            next(null, posts);
        }
    ], callback);
};

var getAbsolutePath = function(postPath) {
    return path.join(postsDir, postPath);
};

var parsePost = function (fileContents) {
    var post = parseFrontMatter(fileContents.toString());
    if (post) {
        post.body = parseBody(post.body);
        if (!post.attributes.link) {
            post.attributes.link = buildPermLink(post);
        }
    }
    return post;
};

var parseFrontMatter = function (fileContents) {
    // quick check for front-matter, skip the file if its missing
    if (fileContents.slice(0, 3) !== '---') {
        return null;
    }
    return fm(fileContents);
};

var parseBody = function (body) {
    var md = require('markdown');
    return md.parse(body);
};

var notNull = function(x) {
    return x;
};

var byDate = function (a, b) {
    return (new Date(b.attributes.date)) - (new Date(a.attributes.date));
};

var stripBody = function(post) {
    return {
        attributes: post.attributes
    };
};

var buildPermLink = function(post) {
    return permLinkFunction(post.attributes);
};

<|endoftext|>


<commit_before>var MongoClient = require('mongodb');
var PulsarJob = require('./job');
var _ = require('underscore');

module.exports = (function() {

  var PulsarDB = function(config, callback) {
    this.connect(config.host, config.port, config.db, 'jobs', callback);
  };

  PulsarDB.prototype.getUniqueJobID = function() {
    return MongoClient.ObjectID().toString();
  };

  PulsarDB.prototype.saveJob = function(job, callback) {
    job.id = this.getUniqueJobID();
    this.collection.insert({_id: job.id, data: job.getData(), args: job.getArgs()}, {safe: true}, function(err) {
      return callback(err);
    });
  };

  PulsarDB.prototype.updateJob = function(job, callback) {
    this.collection.update({_id: job.id}, {$set: {data: job.getData()}}, {safe: true}, function(err) {
      return callback(err);
    });
  };

  PulsarDB.prototype.getJob = function(jobId, callback) {
    this.collection.findOne({_id: jobId}, function(err, result) {
      var job;
      if (!err && result) {
        job = new PulsarJob(result.args, result.data);
        return callback(null, job);
      }
      return callback(err || new ValidationError('Invalid job id'));
    });
  };

  PulsarDB.prototype.getJobList = function(callback) {
    this.collection.find().toArray(function(err, resultList) {
      if (!err) {
        resultList = _.map(resultList, function(result) {
          return new PulsarJob(result.args, result.data);
        });
      }
      return callback(err, resultList);
    });
  };

  PulsarDB.prototype.connect = function(host, port, db, collection, callback) {
    var url = 'mongodb://' + host + ':' + port + '/' + db;

    this.client = MongoClient.connect(url, function(err, db) {
      if (err) {
        return callback(err);
      }
      this.db = db;
      this.collection = db.collection(collection);
      return callback(null, this);
    }.bind(this));
  };

  return PulsarDB;

})();
<commit_msg>Improve readability of PulsarDB.getJob.<commit_after>var MongoClient = require('mongodb');
var PulsarJob = require('./job');
var _ = require('underscore');

module.exports = (function() {

  var PulsarDB = function(config, callback) {
    this.connect(config.host, config.port, config.db, 'jobs', callback);
  };

  PulsarDB.prototype.getUniqueJobID = function() {
    return MongoClient.ObjectID().toString();
  };

  PulsarDB.prototype.saveJob = function(job, callback) {
    job.id = this.getUniqueJobID();
    this.collection.insert({_id: job.id, data: job.getData(), args: job.getArgs()}, {safe: true}, function(err) {
      return callback(err);
    });
  };

  PulsarDB.prototype.updateJob = function(job, callback) {
    this.collection.update({_id: job.id}, {$set: {data: job.getData()}}, {safe: true}, function(err) {
      return callback(err);
    });
  };

  PulsarDB.prototype.getJob = function(jobId, callback) {
    this.collection.findOne({_id: jobId}, function(err, result) {
      if (err) {
        return callback(err);
      }
      if (!result) {
        return callback(new ValidationError('Invalid job'));
      }
      var job = new PulsarJob(result.args, result.data);
      return callback(null, job);
    });
  };

  PulsarDB.prototype.getJobList = function(callback) {
    this.collection.find().toArray(function(err, resultList) {
      if (!err) {
        resultList = _.map(resultList, function(result) {
          return new PulsarJob(result.args, result.data);
        });
      }
      return callback(err, resultList);
    });
  };

  PulsarDB.prototype.connect = function(host, port, db, collection, callback) {
    var url = 'mongodb://' + host + ':' + port + '/' + db;

    this.client = MongoClient.connect(url, function(err, db) {
      if (err) {
        return callback(err);
      }
      this.db = db;
      this.collection = db.collection(collection);
      return callback(null, this);
    }.bind(this));
  };

  return PulsarDB;

})();
<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function(grunt) {

  // Configurable paths
  var yoConfig = {
    livereload: 35729,
    src: 'src',
    dist: 'dist'
  };

  // Livereload setup
  var lrSnippet = require('connect-livereload')({port: yoConfig.livereload});
  var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
  };

  // Load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Project configuration
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    yo: yoConfig,
    meta: {
      banner: '/**\n' +
      ' * <%%= pkg.name %>\n' +
      ' * @version v<%%= pkg.version %> - <%%= grunt.template.today("yyyy-mm-dd") %>\n' +
      ' * @link <%%= pkg.homepage %>\n' +
      ' * @author <%%= pkg.author.name %> <<%%= pkg.author.email %>>\n' +
      ' * @license <%= props.license %> License, http://www.opensource.org/licenses/<%= props.license %>\n' +
      ' */\n'
    },
    open: {
      server: {
        path: 'http://localhost:<%%= connect.options.port %>'
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%%= yo.dist %>/*',
            '!<%%= yo.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },
    watch: {
      gruntfile: {
        files: '<%%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      less: {
        files: ['<%%= yo.src %>/{,*/}*.less'],
        tasks: ['less:dist']
      },
      app: {
        files: [
          '<%%= yo.src %>/{,*/}*.html',
          '{.tmp,<%%= yo.src %>}/{,*/}*.css',
          '{.tmp,<%%= yo.src %>}/{,*/}*.js'
        ],
        options: {
          livereload: yoConfig.livereload
        }
      },
      test: {
        files: '<%%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      }
    },
    connect: {
      options: {
        port: 9000,
        hostname: '0.0.0.0' // Change this to '0.0.0.0' to access the server from outside.
      },
      livereload: {
        options: {
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, '.tmp'),
              mountFolder(connect, yoConfig.src)
            ];
          }
        }
      }
    },
    less: {
      options: {
        // dumpLineNumbers: 'all',
        paths: ['<%%= yo.src %>']
      },
      dist: {
        files: {
          '<%%= yo.src %>/<%%= yo.name %>.css': '<%%= yo.src %>/<%%= yo.name %>.less'
        }
      }
    },
    jshint: {
      gruntfile: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: 'Gruntfile.js'
      },
      src: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: ['<%= yo.src %>/{,*/}*.js']
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/**/*.js']
      }
    },
    karma: {
      options: {
        configFile: 'karma.conf.js',
        browsers: ['PhantomJS']
      },
      unit: {
        singleRun: true
      },
      server: {
        autoWatch: true
      }
    },
    ngmin: {
      options: {
        banner: '<%%= meta.banner %>'
      },
      dist: {
        src: ['<%%= yo.src %>/<%%= pkg.name %>.js'],
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.js'
      }
      // dist: {
      //   files: {
      //     '<%= yeoman.dist %>/<%= yeoman.name %>.js': '<%= yeoman.app %>/<%= yeoman.name %>.js'
      //   }
      // }
    },
    concat: {
      options: {
        banner: '<%%= meta.banner %>',
        stripBanners: true
      },
      dist: {
        src: ['<%%= yo.src %>/<%%= pkg.name %>.js'],
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '<%%= meta.banner %>'
      },
      dist: {
        src: '<%%= concat.dist.dest %>',
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.min.js'
      }
    }
  });

  grunt.registerTask('test', [
    'jshint',
    'karma:unit'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'less:dist',
    'ngmin:dist',
    'uglify:dist'
  ]);

  grunt.registerTask('release', [
    'test',
    'bump-only',
    'dist',
    'bump-commit'
  ]);

  grunt.registerTask('default', ['build']);

};
<commit_msg>Templating fix<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function(grunt) {

  // Configurable paths
  var yoConfig = {
    livereload: 35729,
    src: 'src',
    dist: 'dist'
  };

  // Livereload setup
  var lrSnippet = require('connect-livereload')({port: yoConfig.livereload});
  var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
  };

  // Load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  // Project configuration
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    yo: yoConfig,
    meta: {
      banner: '/**\n' +
      ' * <%%= pkg.name %>\n' +
      ' * @version v<%%= pkg.version %> - <%%= grunt.template.today("yyyy-mm-dd") %>\n' +
      ' * @link <%%= pkg.homepage %>\n' +
      ' * @author <%%= pkg.author.name %> <<%%= pkg.author.email %>>\n' +
      ' * @license <%= props.license %> License, http://www.opensource.org/licenses/<%= props.license %>\n' +
      ' */\n'
    },
    open: {
      server: {
        path: 'http://localhost:<%%= connect.options.port %>'
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%%= yo.dist %>/*',
            '!<%%= yo.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },
    watch: {
      gruntfile: {
        files: '<%%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      less: {
        files: ['<%%= yo.src %>/{,*/}*.less'],
        tasks: ['less:dist']
      },
      app: {
        files: [
          '<%%= yo.src %>/{,*/}*.html',
          '{.tmp,<%%= yo.src %>}/{,*/}*.css',
          '{.tmp,<%%= yo.src %>}/{,*/}*.js'
        ],
        options: {
          livereload: yoConfig.livereload
        }
      },
      test: {
        files: '<%%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      }
    },
    connect: {
      options: {
        port: 9000,
        hostname: '0.0.0.0' // Change this to '0.0.0.0' to access the server from outside.
      },
      livereload: {
        options: {
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, '.tmp'),
              mountFolder(connect, yoConfig.src)
            ];
          }
        }
      }
    },
    less: {
      options: {
        // dumpLineNumbers: 'all',
        paths: ['<%%= yo.src %>']
      },
      dist: {
        files: {
          '<%%= yo.src %>/<%%= yo.name %>.css': '<%%= yo.src %>/<%%= yo.name %>.less'
        }
      }
    },
    jshint: {
      gruntfile: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: 'Gruntfile.js'
      },
      src: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: ['<%%= yo.src %>/{,*/}*.js']
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/**/*.js']
      }
    },
    karma: {
      options: {
        configFile: 'karma.conf.js',
        browsers: ['PhantomJS']
      },
      unit: {
        singleRun: true
      },
      server: {
        autoWatch: true
      }
    },
    ngmin: {
      options: {
        banner: '<%%= meta.banner %>'
      },
      dist: {
        src: ['<%%= yo.src %>/<%%= pkg.name %>.js'],
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.js'
      }
      // dist: {
      //   files: {
      //     '<%= yeoman.dist %>/<%= yeoman.name %>.js': '<%= yeoman.app %>/<%= yeoman.name %>.js'
      //   }
      // }
    },
    concat: {
      options: {
        banner: '<%%= meta.banner %>',
        stripBanners: true
      },
      dist: {
        src: ['<%%= yo.src %>/<%%= pkg.name %>.js'],
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '<%%= meta.banner %>'
      },
      dist: {
        src: '<%%= concat.dist.dest %>',
        dest: '<%%= yo.dist %>/<%%= pkg.name %>.min.js'
      }
    }
  });

  grunt.registerTask('test', [
    'jshint',
    'karma:unit'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'less:dist',
    'ngmin:dist',
    'uglify:dist'
  ]);

  grunt.registerTask('release', [
    'test',
    'bump-only',
    'dist',
    'bump-commit'
  ]);

  grunt.registerTask('default', ['build']);

};
<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        config: {
            // Configurable paths
            app: 'app',
            dist: 'dist'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {<% if (coffee) { %>
            coffee: {
                files: ['<%%= config.app %>/scripts/{,*/}*.{coffee,litcoffee,coffee.md}'],
                tasks: ['coffee:dist']
            },
            coffeeTest: {
                files: ['test/spec/{,*/}*.{coffee,litcoffee,coffee.md}'],
                tasks: ['coffee:test', 'test:watch']
            },<% } else { %>
            js: {
                files: ['<%%= config.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },<% } %>
            gruntfile: {
                files: ['Gruntfile.js']
            },<% if (includeCompass) { %>
            compass: {
                files: ['<%%= config.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['compass:server', 'autoprefixer']
            },<% } %>
            styles: {
                files: ['<%%= config.app %>/styles/{,*/}*.css'],
                tasks: ['newer:copy:styles', 'autoprefixer']
            },
            livereload: {
                options: {
                    livereload: '<%%= connect.options.livereload %>'
                },
                files: [
                    '<%%= config.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',<% if (coffee) { %>
                    '.tmp/scripts/{,*/}*.js',<% } %>
                    '<%%= config.app %>/images/{,*/}*'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%%= config.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%%= config.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    open: true,
                    base: '<%%= config.dist %>',
                    livereload: false
                }
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= config.dist %>/*',
                        '!<%%= config.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%%= config.app %>/scripts/{,*/}*.js',
                '!<%%= config.app %>/scripts/vendor/*',
                'test/spec/{,*/}*.js'
            ]
        },<% if (testFramework === 'mocha') { %>

        // Mocha testing framework configuration options
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://<%%= connect.test.options.hostname %>:<%%= connect.test.options.port %>/index.html']
                }
            }
        },<% } else if (testFramework === 'jasmine') { %>

        // Jasmine testing framework configuration options
        jasmine: {
            all: {
                options: {
                    specs: 'test/spec/{,*/}*.js'
                }
            }
        },<% } %><% if (coffee) { %>

        // Compiles CoffeeScript to JavaScript
        coffee: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/scripts',
                    src: '{,*/}*.{coffee,litcoffee,coffee.md}',
                    dest: '.tmp/scripts',
                    ext: '.js'
                }]
            },
            test: {
                files: [{
                    expand: true,
                    cwd: 'test/spec',
                    src: '{,*/}*.{coffee,litcoffee,coffee.md}',
                    dest: '.tmp/spec',
                    ext: '.js'
                }]
            }
        },<% } %><% if (includeCompass) { %>

        // Compiles Sass to CSS and generates necessary files if requested
        compass: {
            options: {
                sassDir: '<%%= config.app %>/styles',
                cssDir: '.tmp/styles',
                generatedImagesDir: '.tmp/images/generated',
                imagesDir: '<%%= config.app %>/images',
                javascriptsDir: '<%%= config.app %>/scripts',
                fontsDir: '<%%= config.app %>/styles/fonts',
                importPath: '<%%= config.app %>/bower_components',
                httpImagesPath: '/images',
                httpGeneratedImagesPath: '/images/generated',
                httpFontsPath: '/styles/fonts',
                relativeAssets: false,
                assetCacheBuster: false
            },
            dist: {
                options: {
                    generatedImagesDir: '<%%= config.dist %>/images/generated'
                }
            },
            server: {
                options: {
                    debugInfo: true
                }
            }
        },<% } %>

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/styles/',
                    src: '{,*/}*.css',
                    dest: '.tmp/styles/'
                }]
            }
        },

        // Automatically inject Bower components into the HTML file
        bowerInstall: {
            app: {
                src: ['<%%= config.app %>/index.html'],
                ignorePath: '<%%= config.app %>/'<% if (includeCompass) { %>,
                exclude: ['<%%= config.app %>/bower_components/bootstrap-sass/vendor/assets/javascripts/bootstrap.js']
            },
            sass: {
                src: ['<%%= config.app %>/styles/{,*/}*.{scss,sass}'],
                ignorePath: '<%%= config.app %>/bower_components/'
            }<% } else { %>
            }<% } %>
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= config.dist %>/scripts/{,*/}*.js',
                        '<%%= config.dist %>/styles/{,*/}*.css',
                        '<%%= config.dist %>/images/{,*/}*.*',
                        '<%%= config.dist %>/styles/fonts/{,*/}*.*',
                        '<%%= config.dist %>/*.{ico,png}'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            options: {
                dest: '<%%= config.dist %>'
            },
            html: '<%%= config.app %>/index.html'
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            options: {
                assetsDirs: ['<%%= config.dist %>', '<%%= config.dist %>/images']
            },
            html: ['<%%= config.dist %>/{,*/}*.html'],
            css: ['<%%= config.dist %>/styles/{,*/}*.css']
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/images',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%%= config.dist %>/images'
                }]
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/images',
                    src: '{,*/}*.svg',
                    dest: '<%%= config.dist %>/images'
                }]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%%= config.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%%= config.dist %>'
                }]
            }
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //     dist: {
        //         files: {
        //             '<%%= config.dist %>/styles/main.css': [
        //                 '.tmp/styles/{,*/}*.css',
        //                 '<%%= config.app %>/styles/{,*/}*.css'
        //             ]
        //         }
        //     }
        // },
        // uglify: {
        //     dist: {
        //         files: {
        //             '<%%= config.dist %>/scripts/scripts.js': [
        //                 '<%%= config.dist %>/scripts/scripts.js'
        //             ]
        //         }
        //     }
        // },
        // concat: {
        //     dist: {}
        // },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%%= config.app %>',
                    dest: '<%%= config.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        'styles/fonts/{,*/}*.*'<% if (includeBootstrap) { %>,<% if (includeCompass) { %>
                        'bower_components/bootstrap-sass/vendor/assets/fonts/bootstrap/*.*'<% } else { %>
                        'bower_components/bootstrap/dist/fonts/*.*'<% } %><% } %>
                    ]
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%%= config.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },<% if (includeModernizr) { %>

        // Generates a custom Modernizr build that includes only the tests you
        // reference in your app
        modernizr: {
            devFile: '<%%= config.app %>/bower_components/modernizr/modernizr.js',
            outputFile: '<%%= config.dist %>/scripts/vendor/modernizr.js',
            files: [
                '<%%= config.dist %>/scripts/{,*/}*.js',
                '<%%= config.dist %>/styles/{,*/}*.css',
                '!<%%= config.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },<% } %>

        // Run some tasks in parallel to speed up build process
        concurrent: {
            server: [<% if (includeCompass) { %>
                'compass:server',<% } if (coffee) { %>
                'coffee:dist',<% } %>
                'copy:styles'
            ],
            test: [<% if (coffee) { %>
                'coffee',<% } %>
                'copy:styles'
            ],
            dist: [<% if (coffee) { %>
                'coffee',<% } if (includeCompass) { %>
                'compass',<% } %>
                'copy:styles',
                'imagemin',
                'svgmin'
            ]
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', function (target) {
        if (target !== 'watch') {
            grunt.task.run([
                'clean:server',
                'concurrent:test',
                'autoprefixer'
            ]);
        }

        grunt.task.run([
            'connect:test',<% if (testFramework === 'mocha') { %>
            'mocha'<% } else if (testFramework === 'jasmine') { %>
            'jasmine'<% } %>
        ]);
    });

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'cssmin',
        'uglify',
        'copy:dist',<% if (includeModernizr) { %>
        'modernizr',<% } %>
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<commit_msg>use bowerInstall on `watch` task.<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        config: {
            // Configurable paths
            app: 'app',
            dist: 'dist'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['bowerInstall']
            },<% if (coffee) { %>
            coffee: {
                files: ['<%%= config.app %>/scripts/{,*/}*.{coffee,litcoffee,coffee.md}'],
                tasks: ['coffee:dist']
            },
            coffeeTest: {
                files: ['test/spec/{,*/}*.{coffee,litcoffee,coffee.md}'],
                tasks: ['coffee:test', 'test:watch']
            },<% } else { %>
            js: {
                files: ['<%%= config.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },<% } %>
            gruntfile: {
                files: ['Gruntfile.js']
            },<% if (includeCompass) { %>
            compass: {
                files: ['<%%= config.app %>/styles/{,*/}*.{scss,sass}'],
                tasks: ['compass:server', 'autoprefixer']
            },<% } %>
            styles: {
                files: ['<%%= config.app %>/styles/{,*/}*.css'],
                tasks: ['newer:copy:styles', 'autoprefixer']
            },
            livereload: {
                options: {
                    livereload: '<%%= connect.options.livereload %>'
                },
                files: [
                    '<%%= config.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',<% if (coffee) { %>
                    '.tmp/scripts/{,*/}*.js',<% } %>
                    '<%%= config.app %>/images/{,*/}*'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%%= config.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%%= config.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    open: true,
                    base: '<%%= config.dist %>',
                    livereload: false
                }
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= config.dist %>/*',
                        '!<%%= config.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%%= config.app %>/scripts/{,*/}*.js',
                '!<%%= config.app %>/scripts/vendor/*',
                'test/spec/{,*/}*.js'
            ]
        },<% if (testFramework === 'mocha') { %>

        // Mocha testing framework configuration options
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://<%%= connect.test.options.hostname %>:<%%= connect.test.options.port %>/index.html']
                }
            }
        },<% } else if (testFramework === 'jasmine') { %>

        // Jasmine testing framework configuration options
        jasmine: {
            all: {
                options: {
                    specs: 'test/spec/{,*/}*.js'
                }
            }
        },<% } %><% if (coffee) { %>

        // Compiles CoffeeScript to JavaScript
        coffee: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/scripts',
                    src: '{,*/}*.{coffee,litcoffee,coffee.md}',
                    dest: '.tmp/scripts',
                    ext: '.js'
                }]
            },
            test: {
                files: [{
                    expand: true,
                    cwd: 'test/spec',
                    src: '{,*/}*.{coffee,litcoffee,coffee.md}',
                    dest: '.tmp/spec',
                    ext: '.js'
                }]
            }
        },<% } %><% if (includeCompass) { %>

        // Compiles Sass to CSS and generates necessary files if requested
        compass: {
            options: {
                sassDir: '<%%= config.app %>/styles',
                cssDir: '.tmp/styles',
                generatedImagesDir: '.tmp/images/generated',
                imagesDir: '<%%= config.app %>/images',
                javascriptsDir: '<%%= config.app %>/scripts',
                fontsDir: '<%%= config.app %>/styles/fonts',
                importPath: '<%%= config.app %>/bower_components',
                httpImagesPath: '/images',
                httpGeneratedImagesPath: '/images/generated',
                httpFontsPath: '/styles/fonts',
                relativeAssets: false,
                assetCacheBuster: false
            },
            dist: {
                options: {
                    generatedImagesDir: '<%%= config.dist %>/images/generated'
                }
            },
            server: {
                options: {
                    debugInfo: true
                }
            }
        },<% } %>

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/styles/',
                    src: '{,*/}*.css',
                    dest: '.tmp/styles/'
                }]
            }
        },

        // Automatically inject Bower components into the HTML file
        bowerInstall: {
            app: {
                src: ['<%%= config.app %>/index.html'],
                ignorePath: '<%%= config.app %>/'<% if (includeCompass) { %>,
                exclude: ['<%%= config.app %>/bower_components/bootstrap-sass/vendor/assets/javascripts/bootstrap.js']
            },
            sass: {
                src: ['<%%= config.app %>/styles/{,*/}*.{scss,sass}'],
                ignorePath: '<%%= config.app %>/bower_components/'
            }<% } else { %>
            }<% } %>
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= config.dist %>/scripts/{,*/}*.js',
                        '<%%= config.dist %>/styles/{,*/}*.css',
                        '<%%= config.dist %>/images/{,*/}*.*',
                        '<%%= config.dist %>/styles/fonts/{,*/}*.*',
                        '<%%= config.dist %>/*.{ico,png}'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            options: {
                dest: '<%%= config.dist %>'
            },
            html: '<%%= config.app %>/index.html'
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            options: {
                assetsDirs: ['<%%= config.dist %>', '<%%= config.dist %>/images']
            },
            html: ['<%%= config.dist %>/{,*/}*.html'],
            css: ['<%%= config.dist %>/styles/{,*/}*.css']
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/images',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%%= config.dist %>/images'
                }]
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= config.app %>/images',
                    src: '{,*/}*.svg',
                    dest: '<%%= config.dist %>/images'
                }]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%%= config.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%%= config.dist %>'
                }]
            }
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //     dist: {
        //         files: {
        //             '<%%= config.dist %>/styles/main.css': [
        //                 '.tmp/styles/{,*/}*.css',
        //                 '<%%= config.app %>/styles/{,*/}*.css'
        //             ]
        //         }
        //     }
        // },
        // uglify: {
        //     dist: {
        //         files: {
        //             '<%%= config.dist %>/scripts/scripts.js': [
        //                 '<%%= config.dist %>/scripts/scripts.js'
        //             ]
        //         }
        //     }
        // },
        // concat: {
        //     dist: {}
        // },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%%= config.app %>',
                    dest: '<%%= config.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        'styles/fonts/{,*/}*.*'<% if (includeBootstrap) { %>,<% if (includeCompass) { %>
                        'bower_components/bootstrap-sass/vendor/assets/fonts/bootstrap/*.*'<% } else { %>
                        'bower_components/bootstrap/dist/fonts/*.*'<% } %><% } %>
                    ]
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%%= config.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },<% if (includeModernizr) { %>

        // Generates a custom Modernizr build that includes only the tests you
        // reference in your app
        modernizr: {
            devFile: '<%%= config.app %>/bower_components/modernizr/modernizr.js',
            outputFile: '<%%= config.dist %>/scripts/vendor/modernizr.js',
            files: [
                '<%%= config.dist %>/scripts/{,*/}*.js',
                '<%%= config.dist %>/styles/{,*/}*.css',
                '!<%%= config.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },<% } %>

        // Run some tasks in parallel to speed up build process
        concurrent: {
            server: [<% if (includeCompass) { %>
                'compass:server',<% } if (coffee) { %>
                'coffee:dist',<% } %>
                'copy:styles'
            ],
            test: [<% if (coffee) { %>
                'coffee',<% } %>
                'copy:styles'
            ],
            dist: [<% if (coffee) { %>
                'coffee',<% } if (includeCompass) { %>
                'compass',<% } %>
                'copy:styles',
                'imagemin',
                'svgmin'
            ]
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'concurrent:server',
            'autoprefixer',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', function (target) {
        if (target !== 'watch') {
            grunt.task.run([
                'clean:server',
                'concurrent:test',
                'autoprefixer'
            ]);
        }

        grunt.task.run([
            'connect:test',<% if (testFramework === 'mocha') { %>
            'mocha'<% } else if (testFramework === 'jasmine') { %>
            'jasmine'<% } %>
        ]);
    });

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'cssmin',
        'uglify',
        'copy:dist',<% if (includeModernizr) { %>
        'modernizr',<% } %>
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> v<%= pkg.version %>

module.exports = function(grunt) {

  grunt.initConfig({
    clean: {
      public: 'public/**/*'
    },
    jade: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: '**/*.jade',
          dest: 'public/',
          ext: '.html'
        }],
        options: {
          pretty: true
        }
      }
    },
    stylus: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: '**/*.styl',
          dest: 'public/',
          ext: '.css'
        }],
        options: {
          compress: false
        }
      }
    },
    copy: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: [
            '**/*',
            '!<%%= jade.src.files[0].src %>',
            '!<%%= stylus.src.files[0].src %>'
          ],
          dest: 'public/'
        }]
      }
    },
    watch: {
      jade: {
        files: '<%%= jade.src.files[0].cwd + jade.src.files[0].src %>',
        tasks: 'jade'
      },
      stylus: {
        files: '<%%= stylus.src.files[0].cwd + stylus.src.files[0].src %>',
        tasks: 'stylus'
      },
      copy: {
        files: [
          '<%%= copy.src.files[0].cwd %>**/*',
          '!<%%= jade.src.files[0].cwd + jade.src.files[0].src %>',
          '!<%%= stylus.src.files[0].cwd + stylus.src.files[0].src %>'
        ],
        tasks: 'copy:src'
      },
      public: {
        files: [
          'public/**/*',
          '!public/bower_components/**/*'
        ],
        options: {
          livereload: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8000,
          base: 'public',
          keepalive: true,
          middleware: function(connect, options) {
            return [
              require('connect-livereload')(),
              connect.static(options.base)
            ];
          }
        }
      }
    },
    concurrent: {
      compile: {
        tasks: [
          'jade',
          'stylus',
          'copy'
        ],
        options: {
            logConcurrentOutput: false
        }
      },
      server: {
        tasks: [
          'connect',
          'watch:jade',
          'watch:stylus',
          'watch:copy',
          'watch:public'
        ],
        options: {
            logConcurrentOutput: true
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-stylus');
  grunt.loadNpmTasks('grunt-concurrent');

  grunt.registerTask('default', ['clean', 'concurrent:compile']);
  grunt.registerTask('server', ['default', 'concurrent:server']);

};
<commit_msg>Make 'copy' watch target more consistent<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> v<%= pkg.version %>

module.exports = function(grunt) {

  grunt.initConfig({
    clean: {
      public: 'public/**/*'
    },
    jade: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: '**/*.jade',
          dest: 'public/',
          ext: '.html'
        }],
        options: {
          pretty: true
        }
      }
    },
    stylus: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: '**/*.styl',
          dest: 'public/',
          ext: '.css'
        }],
        options: {
          compress: false
        }
      }
    },
    copy: {
      src: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: [
            '**/*',
            '!<%%= jade.src.files[0].src %>',
            '!<%%= stylus.src.files[0].src %>'
          ],
          dest: 'public/'
        }]
      }
    },
    watch: {
      jade: {
        files: '<%%= jade.src.files[0].cwd + jade.src.files[0].src %>',
        tasks: 'jade'
      },
      stylus: {
        files: '<%%= stylus.src.files[0].cwd + stylus.src.files[0].src %>',
        tasks: 'stylus'
      },
      copy: {
        files: [
          '<%%= copy.src.files[0].cwd + copy.src.files[0].src %>',
          '!<%%= jade.src.files[0].cwd + jade.src.files[0].src %>',
          '!<%%= stylus.src.files[0].cwd + stylus.src.files[0].src %>'
        ],
        tasks: 'copy:src'
      },
      public: {
        files: [
          'public/**/*',
          '!public/bower_components/**/*'
        ],
        options: {
          livereload: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8000,
          base: 'public',
          keepalive: true,
          middleware: function(connect, options) {
            return [
              require('connect-livereload')(),
              connect.static(options.base)
            ];
          }
        }
      }
    },
    concurrent: {
      compile: {
        tasks: [
          'jade',
          'stylus',
          'copy'
        ],
        options: {
            logConcurrentOutput: false
        }
      },
      server: {
        tasks: [
          'connect',
          'watch:jade',
          'watch:stylus',
          'watch:copy',
          'watch:public'
        ],
        options: {
            logConcurrentOutput: true
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-stylus');
  grunt.loadNpmTasks('grunt-concurrent');

  grunt.registerTask('default', ['clean', 'concurrent:compile']);
  grunt.registerTask('server', ['default', 'concurrent:server']);

};
<|endoftext|>


<commit_before>/**
 * The Remington module
 * @module remington
 */

const keycodes = require('./keycodes');
const constants = require('./constants');

/**
 * The Remington constructor
 * @constructor
 * @param {Element} element - The DOM element to which to attach this Remington instance
 * @param {Function} [inputCallback] - A callback that fires whenever the Remington instance detects input. Takes a single parameter, the event that was fired
 */
const Remington = function(element, inputCallback) {
    const self = this;

    /**
     * The text buffer of the Remington instance
     * @type {String}
     */
    self.buffer = "";

    /**
     * A list of rows in the buffer, used to index cursor locations
     * @private
     */
    const rows = [];

    /**
     * The current cursor location, where text will be inputted into the buffer
     * @type {Object}
     * @property {Number} row - The current row
     * @property {Number} col - The current column
     */
    self.cursor = {
        row: 0,
        col: 0
    };

    /**
     * The current index into the buffer
     * @private
     */
    let currentIndex = 0;

    /**
     * Calculate the current index into the buffer based on cursor location
     * @private
     */
    const calculateCurrentIndex = function() {
        let index = 0;
        let newlinesVisited = 0;
        // first, find the beginning of the current row
        while(newlinesVisited < self.cursor.row) {
            index = self.buffer.indexOf(constants.NEWLINE, index);
            newlinesVisited++;
        }
        // then, move the index to the current column
        index += self.cursor.col;
        currentIndex = index;
    };

    /**
     * Generates a new string by removing existing characters and/or adding new characters
     * @param {Number} start - The index at which to start changing the string
     * @param {Number} [deleteCount] - The number of old characters to remove. If 0, no characters are removed. If omitted, equal to (string.length - start).
     * @params {...String} [items] - Characters or strings to add to the string
     * @returns {String} The modified string
     */
    const spliceString = function(start, deleteCount, ...items) {
        if (typeof deleteCount === "string") {
            items.splice(0, 0, deleteCount);
            deleteCount = this.length - start;
        }
        const string = this.slice(0, start) + items.join('') + this.slice(start + deleteCount, this.length);
        return string;
    }

    // Add splice as a non-enumerable read-only property of String.prototype
    Object.defineProperty(String.prototype, 'splice', {value: spliceString});

    /**
     * The keypress event listener handles inserting regular characters
     */
    element.addEventListener('keypress', function(event) {
        const character = String.fromCharCode(event.charCode);
        self.buffer = self.buffer.splice(currentIndex, 0, character);
        if (!rows[self.cursor.row]) {
            rows[self.cursor.row] = "";
        }
        rows[self.cursor.row] = rows[self.cursor.row].splice(self.cursor.col, 0, character);
        currentIndex++;
        self.cursor.col++;
        if (inputCallback && typeof inputCallback === 'function') {
            inputCallback(event);
        }
    });

    /**
     * The keydown event listener handles non-character keys such as ENTER
     */
    element.addEventListener('keydown', function(event) {
        switch(event.keyCode) {
            case keycodes.ENTER: {
                self.buffer = self.buffer.splice(currentIndex, 0, constants.NEWLINE);
                currentIndex++;
                if (!rows[self.cursor.row]) {
                    rows[self.cursor.row] = "";
                }
                const remainingRow = rows[self.cursor.row].slice(currentIndex, rows[self.cursor.row].length);
                rows[self.cursor.row] = rows[self.cursor.row].splice(currentIndex, constants.NEWLINE);
                rows.splice(self.cursor.row, 0, remainingRow);
                self.cursor.row++;
                self.cursor.col = 0;
                break;
            }
            case keycodes.BACKSPACE: {
                // BACKSPACE deletes the character before the currentIndex, unless currentIndex is 0
                if (currentIndex > 0) {
                    self.buffer = self.buffer.splice(currentIndex - 1, 1);
                    currentIndex--;
                }
                // if the cursor is at the beginning of a row, go the end of the previous row
                if (self.cursor.col === 0 && self.cursor.row > 0) {
                    // concatenate the current row with the previous one
                    // and delete the newline at the end of the previous one
                    rows[self.cursor.row] = rows[self.cursor.row].splice(rows[self.cursor.row - 1].length - 1, 1, rows[self.cursor.row]);
                    self.cursor.row--;
                    self.cursor.col = rows[self.cursor.row].length - 1;
                }
                // otherwise move the cursor back 1 column, unless it is at (0,0)
                else if (!(self.cursor.col === 0 && self.cursor.row == 0)) {
                    rows[self.cursor.row] = rows[self.cursor.row].splice(self.cursor.col - 1, 1);
                    self.cursor.col--;
                }
                break;
            }
            default: {
                break;
            }
        }
        if (inputCallback && typeof inputCallback === 'function') {
            inputCallback(event);
        }
    });
}

module.exports = Remington;
<commit_msg>Add @private annotation to sliceString<commit_after>/**
 * The Remington module
 * @module remington
 */

const keycodes = require('./keycodes');
const constants = require('./constants');

/**
 * The Remington constructor
 * @constructor
 * @param {Element} element - The DOM element to which to attach this Remington instance
 * @param {Function} [inputCallback] - A callback that fires whenever the Remington instance detects input. Takes a single parameter, the event that was fired
 */
const Remington = function(element, inputCallback) {
    const self = this;

    /**
     * The text buffer of the Remington instance
     * @type {String}
     */
    self.buffer = "";

    /**
     * A list of rows in the buffer, used to index cursor locations
     * @private
     */
    const rows = [];

    /**
     * The current cursor location, where text will be inputted into the buffer
     * @type {Object}
     * @property {Number} row - The current row
     * @property {Number} col - The current column
     */
    self.cursor = {
        row: 0,
        col: 0
    };

    /**
     * The current index into the buffer
     * @private
     */
    let currentIndex = 0;

    /**
     * Calculate the current index into the buffer based on cursor location
     * @private
     */
    const calculateCurrentIndex = function() {
        let index = 0;
        let newlinesVisited = 0;
        // first, find the beginning of the current row
        while(newlinesVisited < self.cursor.row) {
            index = self.buffer.indexOf(constants.NEWLINE, index);
            newlinesVisited++;
        }
        // then, move the index to the current column
        index += self.cursor.col;
        currentIndex = index;
    };

    /**
     * Generates a new string by removing existing characters and/or adding new characters
     * @private
     * @param {Number} start - The index at which to start changing the string
     * @param {Number} [deleteCount] - The number of old characters to remove. If 0, no characters are removed. If omitted, equal to (string.length - start).
     * @params {...String} [items] - Characters or strings to add to the string
     * @returns {String} The modified string
     */
    const spliceString = function(start, deleteCount, ...items) {
        if (typeof deleteCount === "string") {
            items.splice(0, 0, deleteCount);
            deleteCount = this.length - start;
        }
        const string = this.slice(0, start) + items.join('') + this.slice(start + deleteCount, this.length);
        return string;
    }

    // Add splice as a non-enumerable read-only property of String.prototype
    Object.defineProperty(String.prototype, 'splice', {value: spliceString});

    /**
     * The keypress event listener handles inserting regular characters
     */
    element.addEventListener('keypress', function(event) {
        const character = String.fromCharCode(event.charCode);
        self.buffer = self.buffer.splice(currentIndex, 0, character);
        if (!rows[self.cursor.row]) {
            rows[self.cursor.row] = "";
        }
        rows[self.cursor.row] = rows[self.cursor.row].splice(self.cursor.col, 0, character);
        currentIndex++;
        self.cursor.col++;
        if (inputCallback && typeof inputCallback === 'function') {
            inputCallback(event);
        }
    });

    /**
     * The keydown event listener handles non-character keys such as ENTER
     */
    element.addEventListener('keydown', function(event) {
        switch(event.keyCode) {
            case keycodes.ENTER: {
                self.buffer = self.buffer.splice(currentIndex, 0, constants.NEWLINE);
                currentIndex++;
                if (!rows[self.cursor.row]) {
                    rows[self.cursor.row] = "";
                }
                const remainingRow = rows[self.cursor.row].slice(currentIndex, rows[self.cursor.row].length);
                rows[self.cursor.row] = rows[self.cursor.row].splice(currentIndex, constants.NEWLINE);
                rows.splice(self.cursor.row, 0, remainingRow);
                self.cursor.row++;
                self.cursor.col = 0;
                break;
            }
            case keycodes.BACKSPACE: {
                // BACKSPACE deletes the character before the currentIndex, unless currentIndex is 0
                if (currentIndex > 0) {
                    self.buffer = self.buffer.splice(currentIndex - 1, 1);
                    currentIndex--;
                }
                // if the cursor is at the beginning of a row, go the end of the previous row
                if (self.cursor.col === 0 && self.cursor.row > 0) {
                    // concatenate the current row with the previous one
                    // and delete the newline at the end of the previous one
                    rows[self.cursor.row] = rows[self.cursor.row].splice(rows[self.cursor.row - 1].length - 1, 1, rows[self.cursor.row]);
                    self.cursor.row--;
                    self.cursor.col = rows[self.cursor.row].length - 1;
                }
                // otherwise move the cursor back 1 column, unless it is at (0,0)
                else if (!(self.cursor.col === 0 && self.cursor.row == 0)) {
                    rows[self.cursor.row] = rows[self.cursor.row].splice(self.cursor.col - 1, 1);
                    self.cursor.col--;
                }
                break;
            }
            default: {
                break;
            }
        }
        if (inputCallback && typeof inputCallback === 'function') {
            inputCallback(event);
        }
    });
}

module.exports = Remington;
<|endoftext|>