<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*jslint node: true */

"use strict";

module.exports = function( makeModel, loginApi, env ) {

  var Make = makeModel,
      metrics = require( "../lib/metrics" )( env ),
      querystring = require( "querystring" ),
      deferred = require( "deferred" ),
      getUser = deferred.promisify( loginApi.getUser );

  function handleError( res, err, code, type ){
    metrics.increment( "make." + type + ".error" );
    res.json( code, { error: err } );
  }

  function handleSave( resp, err, make, type ){
    if ( err ) {
      handleError( resp, err, 400, type );
    } else {
      metrics.increment( "make." + type + ".success" );
      resp.json( make );
    }
  }

  function updateFields( res, make, body, type ) {
    Make.publicFields.forEach( function( field ) {
      // only update if the field exists on the body
      if ( field in body ) {
        make[ field ] = body[ field ];
      }
    });

    if ( body.email ) {
      make.email = body.email;
    }

    // If createdAt doesn't exist, we know this is a Create, otherwise stamp updatedAt
    if ( !make.createdAt ) {
      make.createdAt = Date.now();
    } else {
      make.updatedAt = Date.now();
    }

    make.save(function( err, make ){
      return handleSave( res, err, make, type );
    });
  }

  function getUserNames( res, results ) {
    var searchHit;
    // Query for each Make's creator and attach their username to the Make
    deferred.map( results.hits, function( make ) {

      // Query the Login API for User data using the email attached to the Make
      return getUser( make.email )
        .then(function onSuccess( user ) {
          // Create new object and copy the makes public fields to it
          searchHit = {};
          Make.publicFields.forEach(function( val ) {
            searchHit[ val ] = make[ val ];
          });
          // _id, createdAt and updatedAt are not apart of our public fields.
          // We need to manually assign it to the object we are returning
          searchHit._id = make._id;
          searchHit.createdAt = make.createdAt;
          searchHit.updatedAt = make.updatedAt;

          // Attach the Maker's username and return the result
          searchHit.username = user.username;
          searchHit.emailHash = user.emailHash;
          return searchHit;
        }, function onError( err ) {
          handleError( res, err, 500, "search" );
        });
    })
    .then(function onSuccess( result ) {
      metrics.increment( "make.search.success" );
      res.json( { makes: result, total: results.total } );
    }, function onError( err ) {
      handleError( res, err, 500, "search" );
    });
  }

  function doSearch( res, searchData ) {
    Make.search( searchData, function( err, results ) {
      if ( err ) {
        return handleError( res, err, 500, "search" );
      } else {
        getUserNames( res, results );
      }
    });
  }

  return {
    create: function( req, res ) {
      updateFields( res, new Make(), req.body.make, "create" );
    },
    update: function( req, res ) {
      updateFields( res, req.make, req.body.make, "update" );
    },
    remove: function( req, res ) {
      var make = req.make;

      make.deletedAt = Date.now();
      make.save( function( err, make ) {
        if ( err ) {
          return handleError( res, err, 500, "remove" );
        }
        metrics.increment( "make.remove.success" );
        res.json( make );
      });
    },
    search: function( req, res ) {
      var searchData, filters, filter;

      if ( !req.query.s ) {
        return handleError( res, "Malformed Request", 400, "search" );
      }

      try {
        searchData = JSON.parse( req.query.s );
      } catch ( err ) {
        return handleError ( res, "Unable to parse search data.", 400, "search" );
      }

      if ( searchData.query.filtered.filter ) {
        if ( !searchData.query.filtered.filter.and ) {
          searchData.query.filtered.filter.and = [];
        }

        filters = searchData.query.filtered.filter.and;

        // We have to unescape any URLs that were present in the data
        for ( var i = 0; i < filters.length; i++ ) {
          filter = filters[ i ];
          if ( filter.term && filter.term.url ) {
            filter.term.url = querystring.unescape( filter.term.url );
          }
        }
      }

      if ( searchData.makerID ) {
        return loginApi.getUser( searchData.makerID, function( err, userData ) {
          if ( err ) {
            return handleError( res, "Specified user does not exist", 400, "search" );
          }
          searchData.query.filtered.filter.and.push({
            term: {
              email: userData.email
            }
          });
          delete searchData.makerID;
          doSearch( res, searchData );
        });
      }

      doSearch( res, searchData );

    },
    searchTest: function( req, res ) {
      res.render( "search.html" );
    },
    healthcheck: function( req, res ) {
      res.json({ http: "okay" });
    }
  };
};
<commit_msg>Fix Bug 883230 - Limit search size to 1000<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*jslint node: true */

"use strict";

module.exports = function( makeModel, loginApi, env ) {

  var DEFAULT_SEARCH_SIZE = 10,
      MAX_SEARCH_SIZE = 1000;

  var Make = makeModel,
      metrics = require( "../lib/metrics" )( env ),
      querystring = require( "querystring" ),
      deferred = require( "deferred" ),
      getUser = deferred.promisify( loginApi.getUser );

  function handleError( res, err, code, type ){
    metrics.increment( "make." + type + ".error" );
    res.json( code, { error: err } );
  }

  function handleSave( resp, err, make, type ){
    if ( err ) {
      handleError( resp, err, 400, type );
    } else {
      metrics.increment( "make." + type + ".success" );
      resp.json( make );
    }
  }

  function updateFields( res, make, body, type ) {
    Make.publicFields.forEach( function( field ) {
      // only update if the field exists on the body
      if ( field in body ) {
        make[ field ] = body[ field ];
      }
    });

    if ( body.email ) {
      make.email = body.email;
    }

    // If createdAt doesn't exist, we know this is a Create, otherwise stamp updatedAt
    if ( !make.createdAt ) {
      make.createdAt = Date.now();
    } else {
      make.updatedAt = Date.now();
    }

    make.save(function( err, make ){
      return handleSave( res, err, make, type );
    });
  }

  function getUserNames( res, results ) {
    var searchHit;
    // Query for each Make's creator and attach their username to the Make
    deferred.map( results.hits, function( make ) {

      // Query the Login API for User data using the email attached to the Make
      return getUser( make.email )
        .then(function onSuccess( user ) {
          // Create new object and copy the makes public fields to it
          searchHit = {};
          Make.publicFields.forEach(function( val ) {
            searchHit[ val ] = make[ val ];
          });
          // _id, createdAt and updatedAt are not apart of our public fields.
          // We need to manually assign it to the object we are returning
          searchHit._id = make._id;
          searchHit.createdAt = make.createdAt;
          searchHit.updatedAt = make.updatedAt;

          // Attach the Maker's username and return the result
          searchHit.username = user.username;
          searchHit.emailHash = user.emailHash;
          return searchHit;
        }, function onError( err ) {
          handleError( res, err, 500, "search" );
        });
    })
    .then(function onSuccess( result ) {
      metrics.increment( "make.search.success" );
      res.json( { makes: result, total: results.total } );
    }, function onError( err ) {
      handleError( res, err, 500, "search" );
    });
  }

  function doSearch( res, searchData ) {
    Make.search( searchData, function( err, results ) {
      if ( err ) {
        return handleError( res, err, 500, "search" );
      } else {
        getUserNames( res, results );
      }
    });
  }

  return {
    create: function( req, res ) {
      updateFields( res, new Make(), req.body.make, "create" );
    },
    update: function( req, res ) {
      updateFields( res, req.make, req.body.make, "update" );
    },
    remove: function( req, res ) {
      var make = req.make;

      make.deletedAt = Date.now();
      make.save( function( err, make ) {
        if ( err ) {
          return handleError( res, err, 500, "remove" );
        }
        metrics.increment( "make.remove.success" );
        res.json( make );
      });
    },
    search: function( req, res ) {
      var searchData, filters, filter;

      if ( !req.query.s ) {
        return handleError( res, "Malformed Request", 400, "search" );
      }

      try {
        searchData = JSON.parse( req.query.s );
      } catch ( err ) {
        return handleError ( res, "Unable to parse search data.", 400, "search" );
      }

      if ( searchData.query.filtered.filter ) {
        if ( !searchData.query.filtered.filter.and ) {
          searchData.query.filtered.filter.and = [];
        }

        filters = searchData.query.filtered.filter.and;

        // We have to unescape any URLs that were present in the data
        for ( var i = 0; i < filters.length; i++ ) {
          filter = filters[ i ];
          if ( filter.term && filter.term.url ) {
            filter.term.url = querystring.unescape( filter.term.url );
          }
        }
      }

      // No need to check for undefined, Elastic Search assumes 10
      if ( searchData.size ) {
        if ( searchData.size <= 0 ) {
          searchData.size = DEFAULT_SEARCH_SIZE;
        } else if ( searchData.size > MAX_SEARCH_SIZE ) {
          searchData.size = MAX_SEARCH_SIZE;
        }
      }

      if ( searchData.makerID ) {
        return loginApi.getUser( searchData.makerID, function( err, userData ) {
          if ( err ) {
            return handleError( res, "Specified user does not exist", 400, "search" );
          }
          searchData.query.filtered.filter.and.push({
            term: {
              email: userData.email
            }
          });
          delete searchData.makerID;
          doSearch( res, searchData );
        });
      }

      doSearch( res, searchData );

    },
    searchTest: function( req, res ) {
      res.render( "search.html" );
    },
    healthcheck: function( req, res ) {
      res.json({ http: "okay" });
    }
  };
};
<|endoftext|>


<commit_before>'use strict'

const stream = require('pull-stream')
const pullDecode = require('pull-utf8-decoder')
const PullBlobStore = require('idb-pull-blob-store')
const PeerId = require('peer-id')

const deferred = require('deferred')

module.exports = class DatabaseManager {
  constructor (fileMetadata, EE) {
    this.metadata = fileMetadata
    this.config = new PullBlobStore('config')
    this._EE = EE
    this.myId

    this._EE.on('IncomingQueryRequest', this.onIncomingQueryRequest.bind(this))
    this._EE.on('IncomingFileRequest', this.onIncomingFileRequest.bind(this))
    this._EE.on('IncomingFileResponse', this.onIncomingFileResponse.bind(this))
  }

  onIncomingQueryRequest (request) {
    let self = this
    self.queryMetadata(request.getQuery())
      .then((queryResult) => {
        let response
        if (request.isRequestOriginThisNode()) {
          response = {id: 'local', result: queryResult}
        } else {
          response = {id: self.myId, hops:(request.getRoute().length - 1), result: queryResult}
        }
        request.setResult([response])
        self._EE.emit('IncomingResponse', request)
      })
      .catch((err) => console.error(err.stack))
  }
  onIncomingFileRequest (request) {
    let self = this
    let fileHash = request.getFile()
    if (request.isRequestOriginThisNode()) {
      stream(
        request.getConnection(),
        self.getFileWriter(fileHash, function (err) {
          if (err) throw err
          self._EE.emit('ReleaseConnection', request.getTarget())
          request.getDeferred().resolve()
        })
      )
    } else {
      self.fileExists(request.getFile()).then(function (exists) {
        if (exists) {
          self.getMetadata(request.getFile()).then((metadata) => {
            request.setResult([{accepted: true, metadata: metadata}])
            self._EE.emit('ReturnToSender', request)
            stream(
              self.getFileReader(request.getFile()),
              request.getConnection()
            )
          })
        } else {
          request.setResult([{accepted: false, error: 'file NOT found'}])
          self._EE.emit('ReturnToSender', request)
        }
      })
    }
  }

  onIncomingFileResponse (request) {
    if (!request.getResult()[0].accepted) {
      request.getDeferred().reject(new Error(request.getResult()[0].error))
    } else {
      this.storeMetadata(request.getFile(), request.getResult()[0].metadata)
    }
  }

  start (aPeerId) {
    let self = this
    return self.getConfig(aPeerId)
      .then((peerId) => {
        self.files = new PullBlobStore('files-' + peerId.toB58String())
        self.myId = peerId.toB58String()

        return peerId
      })
  }

  getConfig (aPeerId) {
    let self = this
    let def = deferred()

    if (aPeerId) {
      def.resolve(aPeerId)
    } else {
      self.configExists()
      .then((exists) => {
        if (exists) {
          self.getConfigFromStorage()
            .then((peerIdJSON) => deferred.promisify(PeerId.createFromJSON)(peerIdJSON))
            .then((peerId) => def.resolve(peerId))
        } else {
          deferred.promisify(PeerId.create)()
          .then((peerId) => {
            self.storeConfig(peerId.toJSON())
              .then(() => def.resolve(peerId))
          })
        }
      })
    }

    // return peer-id instance so other modules can use it
    return def.promise
  }

  configExists () {
    return deferred.promisify(this.config.exists.bind(this.config))('config')
  }

  getConfigFromStorage () {
    var def = deferred()
    stream(
      this.config.read('config'),
      pullDecode(),
      stream.drain((data) => def.resolve(JSON.parse(data)), (err) => { if (err) return def.reject(err) })
    )
    return def.promise
  }

  storeConfig (jsonConfig) {
    var def = deferred()
    stream(
      stream.once(new Buffer(JSON.stringify(jsonConfig))),
      this.config.write('config', (err) => { if (err) return def.reject(err); def.resolve() })
    )
    return def.promise
  }

  fileExists (fileHash) {
    return deferred.promisify(this.files.exists.bind(this.files))(fileHash)
  }
  getFile (fileHash) {
    var def = deferred()
    stream(
        this.getFileReader(fileHash),
        stream.flatten(),
        stream.collect((err, arr) => { if (err) return def.reject(err); def.resolve(arr) })
      )
    return def.promise
  }
  getFileWriter (fileHash, cb) {
    return this.files.write(fileHash, (err) => { if (err) return cb(err); cb() })
  }
  getFileReader (fileHash) {
    return this.files.read(fileHash)
  }
  deleteFile (fileHash) {
    return deferred.promisify(this.files.remove)(fileHash)
  }
  storeMetadata (fileHash, metadata) {
    return this.metadata.store(fileHash, metadata)
  }
  getMetadata (fileHash) {
    return this.metadata.get(fileHash)
  }
  queryMetadata (aQueryStr) {
    return this.metadata.query(aQueryStr)
  }
  deleteMetadata (fileHash) {
    return this.metadata.delete(fileHash)
  }
}
<commit_msg>fix lint error<commit_after>'use strict'

const stream = require('pull-stream')
const pullDecode = require('pull-utf8-decoder')
const PullBlobStore = require('idb-pull-blob-store')
const PeerId = require('peer-id')

const deferred = require('deferred')

module.exports = class DatabaseManager {
  constructor (fileMetadata, EE) {
    this.metadata = fileMetadata
    this.config = new PullBlobStore('config')
    this._EE = EE
    this.myId

    this._EE.on('IncomingQueryRequest', this.onIncomingQueryRequest.bind(this))
    this._EE.on('IncomingFileRequest', this.onIncomingFileRequest.bind(this))
    this._EE.on('IncomingFileResponse', this.onIncomingFileResponse.bind(this))
  }

  onIncomingQueryRequest (request) {
    let self = this
    self.queryMetadata(request.getQuery())
      .then((queryResult) => {
        let response
        if (request.isRequestOriginThisNode()) {
          response = {id: 'local', result: queryResult}
        } else {
          response = {id: self.myId, hops: (request.getRoute().length - 1), result: queryResult}
        }
        request.setResult([response])
        self._EE.emit('IncomingResponse', request)
      })
      .catch((err) => console.error(err.stack))
  }
  onIncomingFileRequest (request) {
    let self = this
    let fileHash = request.getFile()
    if (request.isRequestOriginThisNode()) {
      stream(
        request.getConnection(),
        self.getFileWriter(fileHash, function (err) {
          if (err) throw err
          self._EE.emit('ReleaseConnection', request.getTarget())
          request.getDeferred().resolve()
        })
      )
    } else {
      self.fileExists(request.getFile()).then(function (exists) {
        if (exists) {
          self.getMetadata(request.getFile()).then((metadata) => {
            request.setResult([{accepted: true, metadata: metadata}])
            self._EE.emit('ReturnToSender', request)
            stream(
              self.getFileReader(request.getFile()),
              request.getConnection()
            )
          })
        } else {
          request.setResult([{accepted: false, error: 'file NOT found'}])
          self._EE.emit('ReturnToSender', request)
        }
      })
    }
  }

  onIncomingFileResponse (request) {
    if (!request.getResult()[0].accepted) {
      request.getDeferred().reject(new Error(request.getResult()[0].error))
    } else {
      this.storeMetadata(request.getFile(), request.getResult()[0].metadata)
    }
  }

  start (aPeerId) {
    let self = this
    return self.getConfig(aPeerId)
      .then((peerId) => {
        self.files = new PullBlobStore('files-' + peerId.toB58String())
        self.myId = peerId.toB58String()

        return peerId
      })
  }

  getConfig (aPeerId) {
    let self = this
    let def = deferred()

    if (aPeerId) {
      def.resolve(aPeerId)
    } else {
      self.configExists()
      .then((exists) => {
        if (exists) {
          self.getConfigFromStorage()
            .then((peerIdJSON) => deferred.promisify(PeerId.createFromJSON)(peerIdJSON))
            .then((peerId) => def.resolve(peerId))
        } else {
          deferred.promisify(PeerId.create)()
          .then((peerId) => {
            self.storeConfig(peerId.toJSON())
              .then(() => def.resolve(peerId))
          })
        }
      })
    }

    // return peer-id instance so other modules can use it
    return def.promise
  }

  configExists () {
    return deferred.promisify(this.config.exists.bind(this.config))('config')
  }

  getConfigFromStorage () {
    var def = deferred()
    stream(
      this.config.read('config'),
      pullDecode(),
      stream.drain((data) => def.resolve(JSON.parse(data)), (err) => { if (err) return def.reject(err) })
    )
    return def.promise
  }

  storeConfig (jsonConfig) {
    var def = deferred()
    stream(
      stream.once(new Buffer(JSON.stringify(jsonConfig))),
      this.config.write('config', (err) => { if (err) return def.reject(err); def.resolve() })
    )
    return def.promise
  }

  fileExists (fileHash) {
    return deferred.promisify(this.files.exists.bind(this.files))(fileHash)
  }
  getFile (fileHash) {
    var def = deferred()
    stream(
        this.getFileReader(fileHash),
        stream.flatten(),
        stream.collect((err, arr) => { if (err) return def.reject(err); def.resolve(arr) })
      )
    return def.promise
  }
  getFileWriter (fileHash, cb) {
    return this.files.write(fileHash, (err) => { if (err) return cb(err); cb() })
  }
  getFileReader (fileHash) {
    return this.files.read(fileHash)
  }
  deleteFile (fileHash) {
    return deferred.promisify(this.files.remove)(fileHash)
  }
  storeMetadata (fileHash, metadata) {
    return this.metadata.store(fileHash, metadata)
  }
  getMetadata (fileHash) {
    return this.metadata.get(fileHash)
  }
  queryMetadata (aQueryStr) {
    return this.metadata.query(aQueryStr)
  }
  deleteMetadata (fileHash) {
    return this.metadata.delete(fileHash)
  }
}
<|endoftext|>


<commit_before>var kindOf             = require('../lang/kindOf')
var pad                = require('../number/pad')
var ordinal            = require('../number/ordinal')
var frmt               = require('./dateMasks')
var nameOfDay          = require('./nameOfDay')
var nameOfMonth        = require('./nameOfMonth')
var isLeapYear         = require('./isLeapYear')
var dayOfTheYear       = require('./dayOfTheYear')
var quarterOfTheYear   = require('./quarterOfTheYear')
var weekOfTheYear      = require('./weekOfTheYear')
var timezoneOffset     = require('./timezoneOffset')
var totalDaysThisMonth = require('./totalDaysThisMonth')
var totalDaysThisYear  = require('./totalDaysThisYear')

function dateFormat (date, mask) {
  if (arguments.length === 1 && kindOf(date) === 'string' && !/\d/.test(date)) {
    mask = date
    date = undefined
  }

  date = date || new Date
  if (date instanceof Date) date = new Date(date)
  else date = new Date(Date.parse(date))

  if (isNaN(date)) throw TypeError('Invalid date')

  var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMSsTt])\1?|[oZWQNv]|O{1,2}|u{1,2}|x{1,3}|'[^']*'/g
  var flags = {
    d        : date.getDate(),
    dd       : pad(date.getDate(), 2),
    ddd      : nameOfDay(date, 3),
    dddd     : nameOfDay(date),
    m        : date.getMonth() + 1,
    mm       : pad(date.getMonth() + 1, 2),
    mmm      : nameOfMonth(date, 3),
    mmmm     : nameOfMonth(date),
    yyyy     : pad(date.getFullYear(), 4),
    yy       : pad(date.getFullYear() % 100, 2),
    h        : date.getHours() % 12 || 12,
    hh       : pad(date.getHours() % 12 || 12, 2),
    H        : date.getHours(),
    HH       : pad(date.getHours(),2),
    M        : date.getMinutes(),
    MM       : pad(date.getMinutes(), 2),
    S        : date.getSeconds(),
    SS       : pad(date.getSeconds(),2),
    s        : date.getMilliseconds(),
    ss       : pad(date.getMilliseconds(), 3),
    t        : date.getHours() < 12 ? ' a' : ' p',
    tt       : date.getHours() < 12 ? ' am' : ' pm',
    T        : date.getHours() < 12 ? ' A' : ' P',
    TT       : date.getHours() < 12 ? ' AM' : ' PM',
    N        : dayOfTheYear(date),
    W        : weekOfTheYear(date),
    Q        : quarterOfTheYear(date),
    Z        : timezoneOffset(date),
    u        : totalDaysThisMonth(date),
    uu       : totalDaysThisYear(date),
    x        : daysLeftThisWeek(date),
    xx       : daysLeftThisMonth(date),
    xxx      : daysLeftThisYear(date),
    v        : isLeapYear(date),
    o        : ordinal(date.getDate()),
    O        : nameOfDay(date, 1),
    OO       : nameOfDay(date, 2)
  }

  mask = String(frmt[mask] || mask || frmt.default)
  return mask.replace(token, function (match) {
    if (match in flags) return flags[match]
    return match.slice(1, match.length - 1)
  })
}

function daysLeftThisWeek (date) {
  return 6 - date.getDay()
}

function daysLeftThisMonth (date) {
  return totalDaysThisMonth(date) - date.getDate()
}

function daysLeftThisYear (date) {
  return totalDaysThisYear(date) - dayOfTheYear(date)
}

module.exports = dateFormat
<commit_msg>refactor dateFormat.js<commit_after>var kindOf             = require('../lang/kindOf')
var pad                = require('../number/pad')
var ordinal            = require('../number/ordinal')
var frmt               = require('./dateMasks')
var nameOfDay          = require('./nameOfDay')
var nameOfMonth        = require('./nameOfMonth')
var isLeapYear         = require('./isLeapYear')
var dayOfTheYear       = require('./dayOfTheYear')
var quarterOfTheYear   = require('./quarterOfTheYear')
var weekOfTheYear      = require('./weekOfTheYear')
var timezoneOffset     = require('./timezoneOffset')
var totalDaysThisMonth = require('./totalDaysThisMonth')
var totalDaysThisYear  = require('./totalDaysThisYear')

function dateFormat (date, mask) {
  if (arguments.length === 1 && kindOf(date) === 'string' && !/\d/.test(date)) {
    mask = date
    date = undefined
  }

  date = date || new Date

  if (date instanceof Date) date = new Date(date)
  else date = new Date(Date.parse(date))

  if (isNaN(date)) throw TypeError('Invalid date')

  // what we wish to match
  var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMSsTt])\1?|[oZWQNv]|O{1,2}|u{1,2}|x{1,3}|'[^']*'/g
  // what we don't wish to match -- need to optimize!!
  var antiToken = /[AaBbCcDEeFfGgIiJjKkLlnPpqRrUVwXYz0-9\?\.\,\!@#\$%\^\&\*\(\)\+\-]/g

  // what mask to use
  mask = String(frmt[mask] || antiPattern(mask, antiToken) || frmt.default)

  function makeIterator (fn) {
    return function (mask, token) {
      return fn(date, mask)
    }
  }

  return mask.replace(token, makeIterator(convertFlag))
}

function convertFlag (date, token) {
  switch (token) {
    case 'd'     : return date.getDate()
    case 'dd'    : return pad(date.getDate(), 2)
    case 'ddd'   : return nameOfDay(date, 3)
    case 'dddd'  : return nameOfDay(date)
    case 'm'     : return date.getMonth() + 1
    case 'mm'    : return pad(date.getMonth() + 1, 2)
    case 'mmm'   : return nameOfMonth(date, 3)
    case 'mmmm'  : return nameOfMonth(date)
    case 'yyyy'  : return pad(date.getFullYear(), 4)
    case 'yy'    : return pad(date.getFullYear() % 100, 2)
    case 'h'     : return date.getHours() % 12 || 12
    case 'hh'    : return pad(date.getHours() % 12 || 12, 2)
    case 'H'     : return date.getHours()
    case 'HH'    : return pad(date.getHours(),2)
    case 'M'     : return date.getMinutes()
    case 'MM'    : return pad(date.getMinutes(), 2)
    case 'S'     : return date.getSeconds()
    case 'SS'    : return pad(date.getSeconds(),2)
    case 's'     : return date.getMilliseconds()
    case 'ss'    : return pad(date.getMilliseconds(), 3)
    case 't'     : return date.getHours() < 12 ? ' a' : ' p'
    case 'tt'    : return date.getHours() < 12 ? ' am' : ' pm'
    case 'T'     : return date.getHours() < 12 ? ' A' : ' P'
    case 'TT'    : return date.getHours() < 12 ? ' AM' : ' PM'
    case 'N'     : return dayOfTheYear(date)
    case 'W'     : return weekOfTheYear(date)
    case 'Q'     : return quarterOfTheYear(date)
    case 'Z'     : return timezoneOffset(date)
    case 'u'     : return totalDaysThisMonth(date)
    case 'uu'    : return totalDaysThisYear(date)
    case 'x'     : return daysLeftThisWeek(date)
    case 'xx'    : return daysLeftThisMonth(date)
    case 'xxx'   : return daysLeftThisYear(date)
    case 'v'     : return isLeapYear(date)
    case 'o'     : return ordinal(date.getDate())
    case 'O'     : return nameOfDay(date, 1)
    case 'OO'    : return nameOfDay(date, 2)
    default      : return ''
  }
}

function antiPattern (mask, token) {
  if (!token.test(mask)) return mask
  return false
}

function daysLeftThisWeek (date) {
  return 6 - date.getDay()
}

function daysLeftThisMonth (date) {
  return totalDaysThisMonth(date) - date.getDate()
}

function daysLeftThisYear (date) {
  return totalDaysThisYear(date) - dayOfTheYear(date)
}

module.exports = dateFormat
<|endoftext|>


<commit_before>(function(global, undef) {
    function isPrimitive(val) {
        return Object(val) !== val;
    }
    function isArrayLike(val) {
        return !isPrimitive(val) &&
            typeof val !== "function" &&
            val.length &&
            val.hasOwnProperty(0);
    }
    function makeArray(val) {
        return isArrayLike(val) ? val : val ? [val] : [];
    }
    function defaultFn() {
        return arguments.length > 1 ? arguments : arguments[0];
    }
    function each(obj, fn, reciever) {
        var i, len;
        var arr = typeof obj === "string" ? obj.split("") : obj;
        for (i = 0, len = arr.length; i < len; i += 1) {
            fn.call(reciever || arr, arr[i], i, arr);
        }
    }
    function Stack(fn, next) {
        if (isArrayLike(fn)) {
            var stack;
            each(fn, function (f) {
                stack = stack ? stack.push(f) : new Stack(f);
            });
            return stack;
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || defaultFn;
        this.next = next || undef;
    }
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    Stack.prototype.concat = function (arr) {
        var prev = this;
        each(arr, function (fn) {
            prev = prev.unshift(fn);
        });
        return this;
    };
    Stack.prototype.index = function (idx) {
        return !idx ? this : this.next && this.next.index(idx - 1);
    };
    Stack.prototype.priorNext = function (stack) {
        return this.next && this.next.next === stack ? this : this.next && this.next.priorNext(stack);
    };
    Stack.prototype.priorFn = function (fn) {
        return (this.next && this.next.fn === fn) ? this : this.next && this.next.prior(fn);
    };
    Stack.prototype.searchNext = function (stack) {
        return this.priorNext(stack).next;
    };
    Stack.prototype.searchFn = function (fn) {
        return this.priorFn(fn).next;
    };
    Stack.prototype.distribute = function (arg, reciever) {
        this.fn.call(reciever || this, arg);
        return this.next ? this.next.distribute(arg, reciever || this) : arg;
    };
    Stack.prototype.distributeAll = function (args, reciever) {
        this.fn.apply(reciever|| this, args);
        return this.next ? this.next.distributeAll(makeArray(args), reciever || this) : args;
    };
    Stack.prototype.call = function (arg, reciever) {
        var val = this.fn.call(reciever || this, arg);
        return this.next && val !== false ? this.next.call(val, reciever || this) : val;
    };
    Stack.prototype.apply = function (args, reciever) {
        var val = this.fn.apply(reciever|| this, args);
        return this.next && val !== false ? this.next.apply(makeArray(val), reciever || this) : val;
    };
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    Stack.prototype.tail = function () {
        var current = this;
        while(current.next) {
            current = current.next;
        }
        return current;
    };
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    Stack.prototype.after = function (match, fn) {
        var p = this.priorNext(match || undef);
        return p ? p.next.insert(fn) : this;
    };
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    global.Stack = Stack;
}(this));
<commit_msg>Update stack.js<commit_after>(function(global, undef) {
    function isPrimitive(val) {
        return Object(val) !== val;
    }
    function isArrayLike(val) {
        return !isPrimitive(val) &&
            typeof val !== "function" &&
            val.length &&
            val.hasOwnProperty(0);
    }
    function makeArray(val) {
        return isArrayLike(val) ? val : val ? [val] : [];
    }
    function defaultFn() {
        return arguments.length > 1 ? arguments : arguments[0];
    }
    function each(obj, fn, reciever) {
        var i, len;
        var arr = typeof obj === "string" ? obj.split("") : obj;
        for (i = 0, len = arr.length; i < len; i += 1) {
            fn.call(reciever || arr, arr[i], i, arr);
        }
    }
    function Stack(fn, next) {
        if (isArrayLike(fn)) {
            var stack;
            each(fn, function (f) {
                stack = stack ? stack.push(f) : new Stack(f);
            });
            return stack;
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || defaultFn;
        this.next = next || undef;
    }
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    Stack.prototype.concat = function (arr) {
        var prev = this;
        each(arr, function (fn) {
            prev = prev.unshift(fn);
        });
        return this;
    };
    Stack.prototype.index = function (idx) {
        return !idx ? this : this.next && this.next.index(idx - 1);
    };
    Stack.prototype.priorNext = function (stack) {
        return this.next && this.next.next === stack ? this : this.next && this.next.priorNext(stack);
    };
    Stack.prototype.priorFn = function (fn) {
        return (this.next && this.next.fn === fn) ? this : this.next && this.next.priorFn(fn);
    };
    Stack.prototype.searchNext = function (stack) {
        return this.priorNext(stack).next;
    };
    Stack.prototype.searchFn = function (fn) {
        return this.priorFn(fn).next;
    };
    Stack.prototype.distribute = function (arg, reciever) {
        this.fn.call(reciever || this, arg);
        return this.next ? this.next.distribute(arg, reciever || this) : arg;
    };
    Stack.prototype.distributeAll = function (args, reciever) {
        this.fn.apply(reciever|| this, args);
        return this.next ? this.next.distributeAll(makeArray(args), reciever || this) : args;
    };
    Stack.prototype.call = function (arg, reciever) {
        var val = this.fn.call(reciever || this, arg);
        return this.next && val !== false ? this.next.call(val, reciever || this) : val;
    };
    Stack.prototype.apply = function (args, reciever) {
        var val = this.fn.apply(reciever|| this, args);
        return this.next && val !== false ? this.next.apply(makeArray(val), reciever || this) : val;
    };
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    Stack.prototype.tail = function () {
        var current = this;
        while(current.next) {
            current = current.next;
        }
        return current;
    };
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    Stack.prototype.after = function (match, fn) {
        var p = this.priorNext(match || undef);
        return p ? p.next.insert(fn) : this;
    };
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    global.Stack = Stack;
}(this));
<|endoftext|>


<commit_before>/**
 * Stack - an implementation of singly-linked lists
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]           = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */

/**
 * @lends Stack
 */
(function (global, undef) {
    "use strict";
    function error() {
        throw new TypeError("Argument must be a function or Stack.");
    }

    function s4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    function guid() {
        return (s4() + s4() + "-" + s4() + s4() + "-" + s4() + "-" + s4() + s4() + s4()).toLowerCase();
    }

    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }

    function stackable(fn, stack) {
        return function (a, b) {
            return !a ?
                fn.apply(this, [identity, b]) :
                typeof a === "function" ?
                    fn.apply(this, arguments) :
                    a.isStack ?
                        stack.apply(this, arguments) :
                        error();
        };
    }

    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }

    function identity(val) {
        return arguments.length > 1 ? arguments : val;
    }

    function call(arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }

    function apply(args, receiver) {
        return this.fn.apply(receiver || this, args);
    }

    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }

    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ?
                        transformer.apply(this, args) :
                        args);
            };
        });
    }

    /**
     * @param fn {function}
     * @param receiver {Stack}
     * @param args {Array}
     * @constructor
     */
    function Continuation(fn, receiver, args) {
        this.fn = fn;
        this.receiver = receiver;
        this.args = args;
    }

    /**
     * help identify continuations without access to the constructor
     * @type {boolean}
     */
    Continuation.prototype.isContinuation = true;
    /**
     * complete the continued iteration
     * @param [args {Array}]
     * @param [receiver {Object}]
     * @returns {*}
     */
    Continuation.prototype.run = function (args, receiver) {
        return trampoline(this.fn).apply(receiver || this.receiver, args || this.args);
    };
    /**
     * value or state of a continuation
     * @returns {*}
     */
    Continuation.prototype.value = function () {
        return (this.args && this.args.length === 2 && this.args[1] === undef) ? this.args[0] : this.args;
    };
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            if (self.debug) {
                self.id = self.id || guid();
                self.debug(self, args, action, accumulator, limit);
            }
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                if (val && val.isStack) {
                    return iterating.apply(val, args);
                }
                if (val === Stack.pause) {
                    return new Continuation(function () {
                        return iterating.apply(this, arguments);
                    }, self.next, accumulator ? accumulator.apply(self, args) : args);
                }
                if (val && val.then && val.inspect().state === "pending") {
                    return val.then(function () {
                        return self.next ?
                            iterating.apply(self.next, accumulator ?
                                accumulator.apply(self, args) :
                                args)() :
                            args;
                    });
                }
                return self.next ?
                    iterating.apply(self.next, accumulator ?
                        accumulator.apply(self, merge([val], args)) :
                        args) :
                    val;
            };
        });
    }

    /**
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * Stack([a, [b[c]]]) => [b[c[a]]] // [b[c[a]]]
     * @param fn {function|array}
     * @param next [{?Stack}]
     * @returns {Stack}
     * @constructor
     *
     * to debug a stack while iterating, place a debug method on the stack
     * to debug all stacks, place a debug method on the prototype
     * debugging stacks will generate a guid if they have no id
     * @example Stack.prototype.debug = function () {console.log(arguments);};
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, Stack.create(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * the common pause object
     * @type {Object}
     */
    Stack.pause = {};
    /**
     * @param {Stack|function}
     * @static
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.create = stackable(Stack, identity);
    /**
     * @param prop {string}
     * @param rename {string}
     * @static
     * @returns {object}
     */
    Stack.alias = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * used to identify stack instances
     * @type {boolean}
     */
    Stack.prototype.isStack = true;
    /**
     * used to return a continuation from a stack iterator
     * @returns {Object}
     */
    Stack.prototype.pause = function () {
        return Stack.pause;
    };
    /**
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param [fn {function}]
     * @param [next {Stack}]
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.push = stackable(function (fn) {
        return new Stack(fn, this);
    }, function (stack) {
        stack.precedent().next = this;
        return stack;
    });
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.superPrecedent();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.unshift = function (fn) {
        return this.precedent().insert(fn);
    };
    /**
     * [a].drop() // undefined
     * [a[b]].drop() => [a], [b] // [b]
     */
    Stack.prototype.drop = function () {
        var next = this.next;
        this.next = undef;
        return next;
    };
    /**
     * [a[b[c]]].remove() => [a[c]] // [a[c]]
     * @returns {Stack}
     */
    Stack.prototype.remove = function () {
        if (this.next) {
            this.next = this.next.next;
        }
        return this;
    };
    /**
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * [a].insert([b]) => [a[b]] // [b].insert([c]) => [a[b[c]]] // [c]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.insert = stackable(function (fn) {
        return this.next = new Stack(fn, this.next);
    }, function (stack) {
        var next = this.next;
        this.next = stack;
        stack.next = next;
        return this;
    });
    /**
     * insert [a] before [b]
     * [a[b[c]]].before(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param [a {?Stack|function}]
     * @param [b {?Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.before = stackable(function (a, b) {
        return (this.using(a || undef) || this).insert(b);
    }, function (a, b) {
        return (this.precedent(a || undef) || this).insert(b);
    });
    /**
     * [a[b[c]]].index(1) // [b]
     * @param idx {number}
     * @returns {?Stack}
     */
    Stack.prototype.index = recur(function (val) {
        return val === 0;
    }, function (val) {
        return [--val];
    });
    /**
     * @param id {string}
     * @returns {?Stack}
     */
    Stack.prototype.find = recur(function (id) {
        return this.id === id;
    });
    /**
     * [a].uses(a) // true
     * @param [fn {function}]
     * @returns {boolean}
     */
    Stack.prototype.uses = function (fn) {
        return this.fn === fn;
    };
    /**
     * [a[b[c]]].using(b) // [b]
     * @param [fn {function}]
     * @returns {?Stack}
     */
    Stack.prototype.using = recur(Stack.prototype.uses);
    /**
     * [a[b[c]]].composedWith(b) // [a]
     * @param [fn {function}]
     * @returns {?Stack}
     */
    Stack.prototype.composedWith = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * [a[b]].precedes([b]) // true
     * @param [stack {Stack}]
     * @returns {boolean}
     */
    Stack.prototype.precedes = function (stack) {
        return this.next === stack;
    };
    /**
     * [a[b[c]]].precedent([c]) // [b[c]]
     * @param [stack {Stack}]
     * @returns {?Stack}
     */
    Stack.prototype.precedent = recur(Stack.prototype.precedes);
    /**
     * [a[b[c[d]]]].superPrecedent([d]) // [b]
     * @param [stack {Stack}]
     * @returns {?Stack}
     */
    Stack.prototype.superPrecedent = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    Stack.prototype.distribute = iterate(call);
    /**
     * [a[b[c]]].distributeAll([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distributeAll([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param [args {array}]
     * @param [receiver {object}]
     * @returns {undefined|Continuation}
     */
    Stack.prototype.distributeAll = iterate(apply);
    /**
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    Stack.prototype.call = iterate(call, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param [args {array}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    Stack.prototype.apply = iterate(apply, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {boolean|Continuation}
     */
    Stack.prototype.some = iterate(call, null, function (val) {
        return val === true;
    });
    /**
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {boolean|Continuation}
     */
    Stack.prototype.every = iterate(call, null, function (val) {
        return val === false;
    });
    /**
     * @borrows push as from
     */
    Stack.alias("push", "from")
    /**
     * @borrows insert as to
     */
        .alias("insert", "to")
    /**
     * @borrows insert as compose
     */
        .alias("insert", "compose")
    /**
     * @borrows precedent as tail
     */
        .alias("precedent", "tail");

    global.Stack = Stack;
}(this));
<commit_msg>notes<commit_after>/**
 * Stack - an implementation of singly-linked lists
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]           = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */

/**
 * @lends Stack
 */
(function (global, undef) {
    "use strict";
    function error() {
        throw new TypeError("Argument must be a function or Stack.");
    }

    function s4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    function guid() {
        return (s4() + s4() + "-" + s4() + s4() + "-" + s4() + "-" + s4() + s4() + s4()).toLowerCase();
    }

    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }

    function stackable(fn, stack) {
        return function (a, b) {
            return !a ?
                fn.apply(this, [identity, b]) :
                typeof a === "function" ?
                    fn.apply(this, arguments) :
                    a.isStack ?
                        stack.apply(this, arguments) :
                        error();
        };
    }

    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }

    function identity(val) {
        return arguments.length > 1 ? arguments : val;
    }

    function call(arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }

    function apply(args, receiver) {
        return this.fn.apply(receiver || this, args);
    }

    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }

    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ?
                        transformer.apply(this, args) :
                        args);
            };
        });
    }

    /**
     * @param fn {function}
     * @param receiver {Stack}
     * @param args {Array}
     * @constructor
     */
    function Continuation(fn, receiver, args) {
        this.fn = fn;
        this.receiver = receiver;
        this.args = args;
    }

    /**
     * help identify continuations without access to the constructor
     * @type {boolean}
     */
    Continuation.prototype.isContinuation = true;
    /**
     * complete the continued iteration
     * @param [args {Array}]
     * @param [receiver {Object}]
     * @returns {*}
     */
    Continuation.prototype.run = function (args, receiver) {
        return trampoline(this.fn).apply(receiver || this.receiver, args || this.args);
    };
    /**
     * value or state of a continuation
     * @returns {*}
     */
    Continuation.prototype.value = function () {
        return (this.args && this.args.length === 2 && this.args[1] === undef) ? this.args[0] : this.args;
    };
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            if (self.debug) {
                self.id = self.id || guid();
                self.debug(self, args, action, accumulator, limit);
            }
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                if (val && val.isStack) {
                    return iterating.apply(val, args);
                }
                if (val === Stack.pause) {
                    return new Continuation(function () {
                        return iterating.apply(this, arguments);
                    }, self.next, accumulator ? accumulator.apply(self, args) : args);
                }
                if (val && val.then && val.inspect().state === "pending") {
                    return val.then(function () {
                        return self.next ?
                            iterating.apply(self.next, accumulator ?
                                accumulator.apply(self, args) :
                                args)() :
                            args;
                    });
                }
                return self.next ?
                    iterating.apply(self.next, accumulator ?
                        accumulator.apply(self, merge([val], args)) :
                        args) :
                    val;
            };
        });
    }

    /**
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * Stack([a, [b[c]]]) => [b[c[a]]] // [b[c[a]]]
     * @param fn {function|array}
     * @param next [{?Stack}]
     * @returns {Stack}
     * @constructor
     *
     * to debug a stack while iterating, place a debug method on the stack
     * to debug all stacks, place a debug method on the prototype
     * debugging stacks will generate a guid if they have no id
     * @example Stack.prototype.debug = function () {console.log(arguments);};
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, Stack.create(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * the common pause object
     * @type {Object}
     */
    Stack.pause = {};
    /**
     * @param {Stack|function}
     * @static
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.create = stackable(Stack, identity);
    /**
     * @param prop {string}
     * @param rename {string}
     * @static
     * @returns {object}
     */
    Stack.alias = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * used to identify stack instances
     * @type {boolean}
     */
    Stack.prototype.isStack = true;
    /**
     * used to return a continuation from a stack iterator
     * @returns {Object}
     */
    Stack.prototype.pause = function () {
        return Stack.pause;
    };
    /**
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param [fn {function}]
     * @param [next {Stack}]
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.push = stackable(function (fn) {
        return new Stack(fn, this);
    }, function (stack) {
        stack.precedent().next = this;
        return stack;
    });
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.superPrecedent();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.unshift = function (fn) {
        return this.precedent().insert(fn);
    };
    /**
     * [a].drop() // undefined
     * [a[b]].drop() => [a], [b] // [b]
     */
    Stack.prototype.drop = function () {
        var next = this.next;
        this.next = undef;
        return next;
    };
    /**
     * [a[b[c]]].remove() => [a[c]] // [a[c]]
     * @returns {Stack}
     */
    Stack.prototype.remove = function () {
        if (this.next) {
            this.next = this.next.next;
        }
        return this;
    };
    /**
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * [a].insert([b]) => [a[b]] // [b].insert([c]) => [a[b[c]]] // [c]
     * @param [fn {Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.insert = stackable(function (fn) {
        return this.next = new Stack(fn, this.next);
    }, function (stack) {
        var next = this.next;
        this.next = stack;
        stack.next = next;
        return this;
    });
    /**
     * insert [a] before [b]
     * [a[b[c]]].before(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param [a {?Stack|function}]
     * @param [b {?Stack|function}]
     * @returns {Stack}
     * @throws {TypeError}
     */
    Stack.prototype.before = stackable(function (a, b) {
        return (this.using(a || undef) || this).insert(b);
    }, function (a, b) {
        return (this.precedent(a || undef) || this).insert(b);
    });
    /**
     * [a[b[c]]].index(1) // [b]
     * @param idx {number}
     * @returns {?Stack}
     */
    Stack.prototype.index = recur(function (val) {
        return val === 0;
    }, function (val) {
        return [--val];
    });
    /**
     * @param id {string}
     * @returns {?Stack}
     */
    Stack.prototype.find = recur(function (id) {
        return this.id === id;
    });
    /**
     * [a].uses(a) // true
     * @param [fn {function}]
     * @returns {boolean}
     */
    Stack.prototype.uses = function (fn) {
        return this.fn === fn;
    };
    /**
     * [a[b[c]]].using(b) // [b]
     * @param [fn {function}]
     * @returns {?Stack}
     */
    Stack.prototype.using = recur(Stack.prototype.uses);
    /**
     * [a[b[c]]].composedWith(b) // [a]
     * @param [fn {function}]
     * @returns {?Stack}
     */
    Stack.prototype.composedWith = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * [a[b]].precedes([b]) // true
     * @param [stack {Stack}]
     * @returns {boolean}
     */
    Stack.prototype.precedes = function (stack) {
        return this.next === stack;
    };
    /**
     * [a[b[c]]].precedent([c]) // [b[c]]
     * @param [stack {Stack}]
     * @returns {?Stack}
     */
    Stack.prototype.precedent = recur(Stack.prototype.precedes);
    /**
     * [a[b[c[d]]]].superPrecedent([d]) // [b]
     * @param [stack {Stack}]
     * @returns {?Stack}
     */
    Stack.prototype.superPrecedent = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    //TODO rename to assign
    Stack.prototype.distribute = iterate(call);
    /**
     * [a[b[c]]].distributeAll([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distributeAll([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param [args {array}]
     * @param [receiver {object}]
     * @returns {undefined|Continuation}
     */
    //TODO rename to spread
    Stack.prototype.distributeAll = iterate(apply);
    /**
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    //TODO rename to pipe
    Stack.prototype.call = iterate(call, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param [args {array}]
     * @param [receiver {object}]
     * @returns {*|Continuation}
     */
    //TODO rename to funnel
    Stack.prototype.apply = iterate(apply, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {boolean|Continuation}
     */
    Stack.prototype.some = iterate(call, null, function (val) {
        return val === true;
    });
    /**
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param [arg {*}]
     * @param [receiver {object}]
     * @returns {boolean|Continuation}
     */
    Stack.prototype.every = iterate(call, null, function (val) {
        return val === false;
    });
    /**
     * @borrows push as from
     */
    Stack.alias("push", "from")
    /**
     * @borrows insert as to
     */
        .alias("insert", "to")
    /**
     * @borrows insert as compose
     */
        .alias("insert", "compose")
    /**
     * @borrows precedent as tail
     */
        .alias("precedent", "tail");

    global.Stack = Stack;
}(this));
<|endoftext|>


<commit_before>const Backend = require('./api/structures/Server');
const express = require('express');
const compression = require('compression');
const ream = require('ream');
const config = require('../config');
const path = require('path');
const log = require('./api/utils/Log');
const dev = process.env.NODE_ENV !== 'production';
const oneliner = require('one-liner');
const jetpack = require('fs-jetpack');

function startProduction() {
	startAPI();
	startSite();
}

function startAPI() {
	new Backend().start();
}

function startSite() {
	/*
		Make sure the frontend has enough data to prepare the service
	*/
	writeFrontendConfig();

	/*
		Starting ream's custom server
	*/
	const server = express();
	const app = ream({
		dev,
		entry: path.join(__dirname, 'site', 'index.js')
	});

	app.getRequestHandler().then(handler => {
		server.use(compression());
		/*
			This option is mostly for development, since serving the files with nginx is better.
		*/
		if (config.serveFilesWithNode) {
			server.use('/', express.static(`./${config.uploads.uploadFolder}`));
		}
		server.get('*', handler);
		server.listen(config.server.ports.frontend, error => {
			if (error) log.error(error);
		});
	});

	app.on('renderer-ready', () => log.info(`> Frontend ready and listening on port ${config.server.ports.frontend}`));
}

function writeFrontendConfig() {
	/*
		Since ream can't execute getInitialData on non-routes we write a config file for it.
	*/
	const template = oneliner`
		module.exports = {
			version: '${process.env.npm_package_version}',
			baseURL: '${config.backendLocation}',
			serviceName: '${config.serviceName}',
			maxFileSize: '${config.uploads.uploadMaxSize}',
			chunkSize: '${config.uploads.chunkSize}'
		}`;
	jetpack.write(path.join(__dirname, 'site', 'config.js'), template);
	log.success('Frontend config file generated successfully');
}

/*
	Having multiple files for different scripts was mendokusai.
*/
const args = process.argv[2];
if (!args) startProduction();
else if (args === 'api') startAPI();
else if (args === 'site') startSite();
else process.exit(0);
<commit_msg>We need some more config stuff for the frontend<commit_after>const Backend = require('./api/structures/Server');
const express = require('express');
const compression = require('compression');
const ream = require('ream');
const config = require('../config');
const path = require('path');
const log = require('./api/utils/Log');
const dev = process.env.NODE_ENV !== 'production';
const oneliner = require('one-liner');
const jetpack = require('fs-jetpack');

function startProduction() {
	startAPI();
	startSite();
}

function startAPI() {
	new Backend().start();
}

function startSite() {
	/*
		Make sure the frontend has enough data to prepare the service
	*/
	writeFrontendConfig();

	/*
		Starting ream's custom server
	*/
	const server = express();
	const app = ream({
		dev,
		entry: path.join(__dirname, 'site', 'index.js')
	});

	app.getRequestHandler().then(handler => {
		server.use(compression());
		/*
			This option is mostly for development, since serving the files with nginx is better.
		*/
		if (config.serveFilesWithNode) {
			server.use('/', express.static(`./${config.uploads.uploadFolder}`));
		}
		server.get('*', handler);
		server.listen(config.server.ports.frontend, error => {
			if (error) log.error(error);
		});
	});

	app.on('renderer-ready', () => log.info(`> Frontend ready and listening on port ${config.server.ports.frontend}`));
}

function writeFrontendConfig() {
	/*
		Since ream can't execute getInitialData on non-routes we write a config file for it.
	*/
	const template = oneliner`
		module.exports = {
			version: '${process.env.npm_package_version}',
			URL: '${config.filesServeLocation}',
			baseURL: '${config.backendLocation}',
			serviceName: '${config.serviceName}',
			maxFileSize: '${config.uploads.uploadMaxSize}',
			chunkSize: '${config.uploads.chunkSize}',
			maxLinksPerAlbum: '${config.albums.maxLinksPerAlbum}'
		}`;
	jetpack.write(path.join(__dirname, 'site', 'config.js'), template);
	log.success('Frontend config file generated successfully');
}

/*
	Having multiple files for different scripts was mendokusai.
*/
const args = process.argv[2];
if (!args) startProduction();
else if (args === 'api') startAPI();
else if (args === 'site') startSite();
else process.exit(0);
<|endoftext|>


<commit_before>// Set up KnockoutApp appropriately for the environment
(function(root, factory) {
  // **Node/CommonJS**
  if (typeof exports !== 'undefined') {
    // This is intended for use with [browserify](https://github.com/substack/node-browserify) or similar tools
    factory(exports, require('knockout'), require('jquery'));

  // **AMD**
  } else if (typeof define === 'function' && define.amd) {
    define(['exports', 'knockout', 'jquery'], function(exports, ko, $){
      // Export global even in AMD case in case this script is loaded with
      // others that may still expect a global KnockoutApp
      //
      // This allow for non-amd modules to work
      root.KnockoutApp = factory(exports, ko, $);
    });

  // **Browser global**
  } else {
    root.KnockoutApp = factory({}, root.ko, root.jQuery);
  }
})(this, function(KnockoutApp, ko, $){ // this === window in browser

  // Check that KnockoutJS is loaded
  if(typeof ko === 'undefined') throw "KnockoutJS must be loaded to use KnockoutApp";

  // KnockoutApp's version, set by Grunt when KnockoutApp is built, the value is taken by *package.json*
  KnockoutApp.VERSION = "<%= pkg.version %>";
<commit_msg>exports for module.exports or exports<commit_after>// Set up KnockoutApp appropriately for the environment
(function(root, factory) {
  // **Node/CommonJS**
  if (typeof exports !== 'undefined') {
    // This is intended for use with [browserify](https://github.com/substack/node-browserify) or similar tools
    var target;
    if(typeof module !== undefined){
      target = module.exports;
    }else{
      target = exports;
    }

    factory(target, require('knockout'), require('jquery'));

  // **AMD**
  } else if (typeof define === 'function' && define.amd) {
    define(['exports', 'knockout', 'jquery'], function(exports, ko, $){
      // Export global even in AMD case in case this script is loaded with
      // others that may still expect a global KnockoutApp
      //
      // This allow for non-amd modules to work
      root.KnockoutApp = factory(exports, ko, $);
    });

  // **Browser global**
  } else {
    root.KnockoutApp = factory({}, root.ko, root.jQuery);
  }
})(this, function(KnockoutApp, ko, $){ // this === window in browser

  // Check that KnockoutJS is loaded
  if(typeof ko === 'undefined') throw "KnockoutJS must be loaded to use KnockoutApp";

  // KnockoutApp's version, set by Grunt when KnockoutApp is built, the value is taken by *package.json*
  KnockoutApp.VERSION = "<%= pkg.version %>";
<|endoftext|>


<commit_before>(function (exports) {
  var Stash = exports.Stash || {};
  var isNode = typeof require !== 'undefined';

  if (isNode) {
    Q = require('q');
  }

  Stash.Item = (function () {
    function Item(key, pool) {
      this.key = key;
      this.pool = pool;

      this._unload_();
    }

    Item.SP_NONE = 1;
    Item.SP_OLD = 2;
    Item.SP_PRECOMPUTE = 4;
    Item.SP_VALUE = 8;

    Item.prototype._unload_ = function () {
      this.value = null;
      this.expiration = false;
    };

    Item.prototype._load_ = function (callback) {
      var that = this;

      var value = this.pool.drivers.reduce(function (a, b) {
        return a || b.get(that.key, function (data) {
          if (that && data) {
            that.value = data.value;
            that.expiration = data.expiration;
            that.locked = data.locked;
            callback && callback(that);
            that = false;
          }
        });
      }, false);

      return this;
    };

    Item.prototype._write_ = function (callback) {
      var that = this;

      this.pool.drivers.reverse().forEach(function (driver) {
        driver.put(that.key, that.value, that.expiration, function (err) {
          callback && callback(err);
          callback = null;
        });
      });
    };

    Item._calculateExpiration_ = function (expiration) {
      if (typeof(expiration) === 'number') {
        expiration *= 1000;
        expiration += Date.now();
      } else if (expiration instanceof Date) {
        expiration = expiration.getTime();
      }

      return expiration;
    };

    Item.prototype.get = function (cachePolicy, policyData) {
      this.cachePolicy = cachePolicy || Stash.Item.SP_NONE;
      this.policyData = policyData;

      if ((cachePolicy & Stash.Item.SP_VALUE) && this.locked) {
        return policyData;
      }

      return this._load_(function (item) {
        callback && callback(item.value);
      }).value;
    };

    Item.prototype.set = function (value, expiration, callback) {
      if (typeof expiration === 'function') {
        callback = expiration;
        expiration = null;
      }

      this._unload_();

      this.expiration = Item._calculateExpiration_(expiration);
      this.value = value;

      this._write_(callback);
    };

    Item.prototype.isMiss = function (callback) {
      this.isLocked(function (locked) {
        if (locked && (this.cachePolicy & Stash.Item.SP_OLD)) {
          return false;
        } else if (!locked &&
                   (this.cachePolicy & Stash.Item.SP_PRECOMPUTE) &&
                   this.policyData * 1000 >= this.expiration - Date.now()) {
          return true;
        }

        var miss = typeof(this.expiration) === 'number' && this.expiration < Date.now();
        callback(miss);
      }.bind(this));
    };

    Item.prototype.clear = function () {
      var that = this;

      this._unload_();

      this.pool.drivers.forEach(function (driver) {
        driver.delete(that.key);
      });
    };

    Item.prototype.lock = function () {
      this.pool.drivers.forEach(function (driver) {
        driver.lock(this.key)
      }.bind(this));
    };

    return Item;
  })();

  Stash.Pool = (function () {
    function Pool(drivers) {
      if (!drivers) {
        this.drivers = [new Stash.Drivers.Ephemeral()];
      } else if (Object.prototype.toString.call(drivers) !== '[object Array]') {
        this.drivers = [drivers];
      } else {
        this.drivers = drivers;
      }
    }

    Pool.prototype.getItem = function (key) {
      var item = new Stash.Item(key, this);

      return item;
    };

    Pool.prototype.flush = function () {
      this.drivers.forEach(function (driver) {
        driver.flush();
      });
    };

    return Pool;
  })();

  Stash.Drivers = {};
  Stash.Drivers.Utils = {
    assemble: function (value, expiration) {
      if (typeof value === 'function') {
        throw new TypeError('Only serializables values can be cached');
      }

      return JSON.stringify({ value: value, expiration: expiration });
    },
    key: function (namespace, key) {
      if (key instanceof Array) {
        key.unshift(namespace);
        return key.filter(String).join('/');
      } else {
       key = key.toString()
        .trim()
        .replace(/^\/+/g, '')
        .replace(/\/+$/g, '');
       return namespace + '/' + key;
      }
    }
  };

  Stash.Drivers.Ephemeral = (function () {
    var cache = {};
    function Ephemeral () {}

    Ephemeral.prototype.get = function (key) {
      key = Stash.Drivers.Utils.key('', key);
      var data = cache[key] || null;

      if (data) {
        data = JSON.parse(data);
      }

      return Q(data);
    };

    Ephemeral.prototype.put = function (key, value, expiration) {
      key = Stash.Drivers.Utils.key('', key);
      var data = Stash.Drivers.Utils.assemble(value, expiration);
      cache[key] = data;
      return Q();
    };

    Ephemeral.prototype.delete = function (key) {
      key = Stash.Drivers.Utils.key('', key);
      var length = key.length;

      Object.keys(cache).forEach(function (_key) {
        if (_key.substr(0, length) === key) {
          cache[_key] = null;
        }
      });

      cache[key] = null;
      return Q();
    };

    Ephemeral.prototype.flush = function () {
      cache = {};
      return Q();
    };

    Ephemeral.prototype.lock = function (key) {
      var key = Stash.Drivers.Utils.key('', key) + '_lock';
      cache[key] = 1;
      return Q();
    };

    Ephemeral.prototype.isLocked = function (key) {
      key = Stash.Drivers.Utils.key('', key) + '_lock';
      return Q(Boolean(cache[key]));
    }

    return Ephemeral;
  })();

  Stash.Drivers.LocalStorage = (function () {
    function LocalStorage (namespace) {
      this.namespace = namespace || 'stash';
    }

    LocalStorage.prototype.get = function (key) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var data = localStorage.getItem(key);

      if (data) {
        data = JSON.parse(data);
      }

      return Q(data);
    }

    LocalStorage.prototype.put = function (key, value, expiration) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var data = Stash.Drivers.Utils.assemble(value, expiration);

      return this.putRaw(key, data);
    };

    LocalStorage.prototype.putRaw = function (key, value) {
      localStorage.setItem(key, value);
      return Q();
    }

    LocalStorage.prototype.delete = function (key) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var length = key.length;

      for (var i = 0, l = localStorage.length; i < l; i++) {
        var _key = localStorage.key(i);
        if (_key && _key.substr(0, length) === key) {
          localStorage.removeItem(_key);
        }
      }

      localStorage.removeItem(key);
      return Q();
    };

    LocalStorage.prototype.flush = function () {
      return this.delete('');
    };

    return LocalStorage;
  })();

  exports.Stash = Stash;
})(typeof(window) === 'undefined' ? module.exports : window);
<commit_msg>add LocalStorage #lock and #isLocked<commit_after>(function (exports) {
  var Stash = exports.Stash || {};
  var isNode = typeof require !== 'undefined';

  if (isNode) {
    Q = require('q');
  }

  Stash.Item = (function () {
    function Item(key, pool) {
      this.key = key;
      this.pool = pool;

      this._unload_();
    }

    Item.SP_NONE = 1;
    Item.SP_OLD = 2;
    Item.SP_PRECOMPUTE = 4;
    Item.SP_VALUE = 8;

    Item.prototype._unload_ = function () {
      this.value = null;
      this.expiration = false;
    };

    Item.prototype._load_ = function (callback) {
      var that = this;

      var value = this.pool.drivers.reduce(function (a, b) {
        return a || b.get(that.key, function (data) {
          if (that && data) {
            that.value = data.value;
            that.expiration = data.expiration;
            that.locked = data.locked;
            callback && callback(that);
            that = false;
          }
        });
      }, false);

      return this;
    };

    Item.prototype._write_ = function (callback) {
      var that = this;

      this.pool.drivers.reverse().forEach(function (driver) {
        driver.put(that.key, that.value, that.expiration, function (err) {
          callback && callback(err);
          callback = null;
        });
      });
    };

    Item._calculateExpiration_ = function (expiration) {
      if (typeof(expiration) === 'number') {
        expiration *= 1000;
        expiration += Date.now();
      } else if (expiration instanceof Date) {
        expiration = expiration.getTime();
      }

      return expiration;
    };

    Item.prototype.get = function (cachePolicy, policyData) {
      this.cachePolicy = cachePolicy || Stash.Item.SP_NONE;
      this.policyData = policyData;

      if ((cachePolicy & Stash.Item.SP_VALUE) && this.locked) {
        return policyData;
      }

      return this._load_(function (item) {
        callback && callback(item.value);
      }).value;
    };

    Item.prototype.set = function (value, expiration, callback) {
      if (typeof expiration === 'function') {
        callback = expiration;
        expiration = null;
      }

      this._unload_();

      this.expiration = Item._calculateExpiration_(expiration);
      this.value = value;

      this._write_(callback);
    };

    Item.prototype.isMiss = function (callback) {
      this.isLocked(function (locked) {
        if (locked && (this.cachePolicy & Stash.Item.SP_OLD)) {
          return false;
        } else if (!locked &&
                   (this.cachePolicy & Stash.Item.SP_PRECOMPUTE) &&
                   this.policyData * 1000 >= this.expiration - Date.now()) {
          return true;
        }

        var miss = typeof(this.expiration) === 'number' && this.expiration < Date.now();
        callback(miss);
      }.bind(this));
    };

    Item.prototype.clear = function () {
      var that = this;

      this._unload_();

      this.pool.drivers.forEach(function (driver) {
        driver.delete(that.key);
      });
    };

    Item.prototype.lock = function () {
      this.pool.drivers.forEach(function (driver) {
        driver.lock(this.key)
      }.bind(this));
    };

    return Item;
  })();

  Stash.Pool = (function () {
    function Pool(drivers) {
      if (!drivers) {
        this.drivers = [new Stash.Drivers.Ephemeral()];
      } else if (Object.prototype.toString.call(drivers) !== '[object Array]') {
        this.drivers = [drivers];
      } else {
        this.drivers = drivers;
      }
    }

    Pool.prototype.getItem = function (key) {
      var item = new Stash.Item(key, this);

      return item;
    };

    Pool.prototype.flush = function () {
      this.drivers.forEach(function (driver) {
        driver.flush();
      });
    };

    return Pool;
  })();

  Stash.Drivers = {};
  Stash.Drivers.Utils = {
    assemble: function (value, expiration) {
      if (typeof value === 'function') {
        throw new TypeError('Only serializables values can be cached');
      }

      return JSON.stringify({ value: value, expiration: expiration });
    },
    key: function (namespace, key) {
      if (key instanceof Array) {
        key.unshift(namespace);
        return key.filter(String).join('/');
      } else {
       key = key.toString()
        .trim()
        .replace(/^\/+/g, '')
        .replace(/\/+$/g, '');
       return namespace + '/' + key;
      }
    }
  };

  Stash.Drivers.Ephemeral = (function () {
    var cache = {};
    function Ephemeral () {}

    Ephemeral.prototype.get = function (key) {
      key = Stash.Drivers.Utils.key('', key);
      var data = cache[key] || null;

      if (data) {
        data = JSON.parse(data);
      }

      return Q(data);
    };

    Ephemeral.prototype.put = function (key, value, expiration) {
      key = Stash.Drivers.Utils.key('', key);
      var data = Stash.Drivers.Utils.assemble(value, expiration);
      cache[key] = data;
      return Q();
    };

    Ephemeral.prototype.delete = function (key) {
      key = Stash.Drivers.Utils.key('', key);
      var length = key.length;

      Object.keys(cache).forEach(function (_key) {
        if (_key.substr(0, length) === key) {
          cache[_key] = null;
        }
      });

      cache[key] = null;
      return Q();
    };

    Ephemeral.prototype.flush = function () {
      cache = {};
      return Q();
    };

    Ephemeral.prototype.lock = function (key) {
      var key = Stash.Drivers.Utils.key('', key) + '_lock';
      cache[key] = 1;
      return Q();
    };

    Ephemeral.prototype.isLocked = function (key) {
      key = Stash.Drivers.Utils.key('', key) + '_lock';
      return Q(Boolean(cache[key]));
    }

    return Ephemeral;
  })();

  Stash.Drivers.LocalStorage = (function () {
    function LocalStorage (namespace) {
      this.namespace = namespace || 'stash';
    }

    LocalStorage.prototype.get = function (key) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var data = localStorage.getItem(key);

      if (data) {
        data = JSON.parse(data);
      }

      return Q(data);
    }

    LocalStorage.prototype.put = function (key, value, expiration) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var data = Stash.Drivers.Utils.assemble(value, expiration);

      return this.putRaw(key, data);
    };

    LocalStorage.prototype.putRaw = function (key, value) {
      localStorage.setItem(key, value);
      return Q();
    }

    LocalStorage.prototype.delete = function (key) {
      key = Stash.Drivers.Utils.key(this.namespace, key);
      var length = key.length;

      for (var i = 0, l = localStorage.length; i < l; i++) {
        var _key = localStorage.key(i);
        if (_key && _key.substr(0, length) === key) {
          localStorage.removeItem(_key);
        }
      }

      localStorage.removeItem(key);
      return Q();
    };

    LocalStorage.prototype.flush = function () {
      return this.delete('');
    };

    LocalStorage.prototype.lock = function (key) {
      key = Stash.Drivers.Utils.key(this.namespace, key) + '_lock';
      return this.putRaw(key, 1);
    };

    LocalStorage.prototype.isLocked = function (key) {
      var deferred = Q.defer();
      this.get(key + '_lock').then(function (data) {
        deferred.resolve(Boolean(data));
      });

      return deferred.promise;

    }

    return LocalStorage;
  })();

  exports.Stash = Stash;
})(typeof(window) === 'undefined' ? module.exports : window);
<|endoftext|>


<commit_before>// issues: 'create' listeners will continue
// to reside in memmory after firing

function State(obj){
	var self = this;

	self.actions = {};

	self.index = 0;
	self.bufferLength = 2;
	self.buffer = [];
	self.buffer.error = null;
	// self.data = [];
	// self.data.error = null;

	extend(self, obj);

	if(self.default) self.set(self.default);
}

State.prototype = {

	// ACCESSORS

	get: function(idx, ret){
		idx = idx || this.index;
		ret = this.buffer[idx];

		return ret[0] || ret[1];
	},

	set: function(data, err){
		if(!this.validator(data)) return false;

		data = this.mutator(data);

  	this.setState(err, data);

  	return true;
	},

	// FALLBACKS

	validator: function(){
		return true;
	},

	mutator: function(data){
		return data;
	},

	complete: function(){
		return true;
	},

	// STATES

	isNew: function(){
		return (this.state == null);
	},

	isUnset: function(){
		return (this.state == null);
	},

	isSet: function(){
		return (this.state == 'set');
	},

	isTransitioning: function(){
		return (this.state == 'transition');
	},

	hasError: function(){
		return (this.get() instanceof Error);
	},

	// TRIGGERS

	onAll: function(func){
		this.each(func);
		this.onNext(func);
	},

	onNext: function(func){
		this.on('change', func);
	},

	onCreate: function(func){
		if( this.isUnset() ){
			this.once('create', func);
		}
		else{
			var args = this.buffer.initial;
			func(args[0], args[1]);
		}
	},

	each: function(func){
		var buffer, i, args;
		for(i = 0, il = buffer.length; i < il; i++){
			args = buffer[i];

			func(args[0], args[1]);
		}

		return this;
	},

	error: function(err, data){
		data = data || null;
		err  = new Error(err);

		this.setState(err, data);

		return this;
	}

	// fire: function(type, data){
	// 	var acts, data, i;

	// 	acts = this.getActions(type);
	// 	i    = acts.length;
	// 	data = data || this.get();
	// 	err  = this.buffer.error;

	// 	while(i--) acts[i](err, data);

	// 	return this;
	// },

	// error: function(opts){
	// 	var err;

	// 	opts = !opts.message ? {message: opts} : opts;

	// 	err = extend(new Error(), opts);

	// 	this.buffer.error = err;
	// 	this.state = 'error';

	// 	this.fire('error');
	// 	this.fire('change');

	// 	return this;
	// },

	// transition: function(){
	// 	this.state = 'transition';
	// 	this.fire('transition');

	// 	return this;
	// },

	// EVENTS

	// on: function(type, func, stateful){
	// 	if(type == 'create' || stateful == null) stateful = true;

	// 	if(stateful) this.checkState(type, func);

	// 	this.getActions(type).push(func);

	// 	return this;
	// },

	// once: function(type, func, stateful){
	// 	var self = this;

	// 	return self.on(type, function once(err, data){
	// 		func(err, data);
	// 		self.off(type, once);
	// 	}, stateful);
	// },

	// off: function(type, func){
	// 	var actions, idx;

	// 	actions = this.getActions(type);
	// 	idx = actions.indexOf(func);

	// 	actions.splice(idx, 1);

	// 	return this;
	// },

	// HELPERS

	setState: function(err, data){
		var idx, dataSet;

		dataSet = [err, data];

		idx = this.buffer.push(dataSet);

		if(idx > this.bufferLength){
			this.buffer.shift();
		}
		else{
			this.index = --idx;
		}

  	if( this.isUnset() ){
  		this.buffer.initial = dataSet;
  		this.state = 'set';
  		this.fire('create', err, data);
  	}

  	if(err) this.fire('error', err, data);

  	this.fire('change', err, data);

  	return this;
	},

	timeout: function(state, delay){
		var self, resolver;

		self = this;

		if(typeof state == 'number'){
			delay = state;
			state = new State();
			state.set(true);
		}

		if(delay){
			resolver = function(){
				setTimeout(function(){
					self.error({
						message: 'Timeout: ' + delay + 'ms',
						type: 'timeout'
					});
					self.fire('timeout');
				}, delay);
			}
		}
		else{
			resolver = function(){
				self.error('Timeout: condition met');
			}
		}

		state.onCreate(resolver);

		return self;
	}

	// checkState: function(type, func){
	// 	if(!this.isNew()){
	// 		var data = (type == 'create') ? this.buffer.initial : this.get();
	// 		func(this.buffer.error, data);
	// 	}
	// },

	// getActions: function(type){
	// 	return this.actions[type] || (this.actions[type] = []);
	// },

	// SUGAR

	// onChange: function(func, stateful){
	// 	return this.on('change', func, stateful);
	// },

	// onTransition: function(func, stateful){
	// 	return this.on('transition', func, stateful)
	// },

	// onCreate: function(func){
	// 	return this.on('create', func);
	// },

	// onError: function(func){
	// 	return this.on('error', func);
	// },

	// onTimeout: function(func){
	// 	return this.on('timeout', func);
	// }
};

addEvents(State);<commit_msg>cleaned up constructor<commit_after>// issues: 'create' listeners will continue
// to reside in memmory after firing

function State(obj){
	var self = this;

	self.index = 0;
	self.bufferLength = 2;
	self.buffer = [];
	// self.data = [];
	// self.data.error = null;

	extend(self, obj);

	if(self.default) self.set(self.default);
}

State.prototype = {

	// ACCESSORS

	get: function(idx, ret){
		idx = idx || this.index;
		ret = this.buffer[idx];

		return ret[0] || ret[1];
	},

	set: function(data, err){
		if(!this.validator(data)) return false;

		data = this.mutator(data);

  	this.setState(err, data);

  	return true;
	},

	// FALLBACKS

	validator: function(){
		return true;
	},

	mutator: function(data){
		return data;
	},

	complete: function(){
		return true;
	},

	// STATES

	isNew: function(){
		return (this.state == null);
	},

	isUnset: function(){
		return (this.state == null);
	},

	isSet: function(){
		return (this.state == 'set');
	},

	isTransitioning: function(){
		return (this.state == 'transition');
	},

	hasError: function(){
		return (this.get() instanceof Error);
	},

	// TRIGGERS

	onAll: function(func){
		this.each(func);
		this.onNext(func);
	},

	onNext: function(func){
		this.on('change', func);
	},

	onCreate: function(func){
		if( this.isUnset() ){
			this.once('create', func);
		}
		else{
			var args = this.buffer.initial;
			func(args[0], args[1]);
		}
	},

	each: function(func){
		var buffer, i, args;
		for(i = 0, il = buffer.length; i < il; i++){
			args = buffer[i];

			func(args[0], args[1]);
		}

		return this;
	},

	error: function(err, data){
		data = data || null;
		err  = new Error(err);

		this.setState(err, data);

		return this;
	}

	// fire: function(type, data){
	// 	var acts, data, i;

	// 	acts = this.getActions(type);
	// 	i    = acts.length;
	// 	data = data || this.get();
	// 	err  = this.buffer.error;

	// 	while(i--) acts[i](err, data);

	// 	return this;
	// },

	// error: function(opts){
	// 	var err;

	// 	opts = !opts.message ? {message: opts} : opts;

	// 	err = extend(new Error(), opts);

	// 	this.buffer.error = err;
	// 	this.state = 'error';

	// 	this.fire('error');
	// 	this.fire('change');

	// 	return this;
	// },

	// transition: function(){
	// 	this.state = 'transition';
	// 	this.fire('transition');

	// 	return this;
	// },

	// EVENTS

	// on: function(type, func, stateful){
	// 	if(type == 'create' || stateful == null) stateful = true;

	// 	if(stateful) this.checkState(type, func);

	// 	this.getActions(type).push(func);

	// 	return this;
	// },

	// once: function(type, func, stateful){
	// 	var self = this;

	// 	return self.on(type, function once(err, data){
	// 		func(err, data);
	// 		self.off(type, once);
	// 	}, stateful);
	// },

	// off: function(type, func){
	// 	var actions, idx;

	// 	actions = this.getActions(type);
	// 	idx = actions.indexOf(func);

	// 	actions.splice(idx, 1);

	// 	return this;
	// },

	// HELPERS

	setState: function(err, data){
		var idx, dataSet;

		dataSet = [err, data];

		idx = this.buffer.push(dataSet);

		if(idx > this.bufferLength){
			this.buffer.shift();
		}
		else{
			this.index = --idx;
		}

  	if( this.isUnset() ){
  		this.buffer.initial = dataSet;
  		this.state = 'set';
  		this.fire('create', err, data);
  	}

  	if(err) this.fire('error', err, data);

  	this.fire('change', err, data);

  	return this;
	},

	timeout: function(state, delay){
		var self, resolver;

		self = this;

		if(typeof state == 'number'){
			delay = state;
			state = new State();
			state.set(true);
		}

		if(delay){
			resolver = function(){
				setTimeout(function(){
					self.error({
						message: 'Timeout: ' + delay + 'ms',
						type: 'timeout'
					});
					self.fire('timeout');
				}, delay);
			}
		}
		else{
			resolver = function(){
				self.error('Timeout: condition met');
			}
		}

		state.onCreate(resolver);

		return self;
	}

	// checkState: function(type, func){
	// 	if(!this.isNew()){
	// 		var data = (type == 'create') ? this.buffer.initial : this.get();
	// 		func(this.buffer.error, data);
	// 	}
	// },

	// getActions: function(type){
	// 	return this.actions[type] || (this.actions[type] = []);
	// },

	// SUGAR

	// onChange: function(func, stateful){
	// 	return this.on('change', func, stateful);
	// },

	// onTransition: function(func, stateful){
	// 	return this.on('transition', func, stateful)
	// },

	// onCreate: function(func){
	// 	return this.on('create', func);
	// },

	// onError: function(func){
	// 	return this.on('error', func);
	// },

	// onTimeout: function(func){
	// 	return this.on('timeout', func);
	// }
};

addEvents(State);<|endoftext|>