<commit_before>/*
 *   vod packager playlist implementation.
 *   for details see https://github.com/kaltura/nginx-vod-module
 * */

var    _ = require('underscore');
var util = require('util');
var playlistUtils = require('./playlistGenrator-utils');
var PlaylistItem = require('./PlaylistItem');
var BroadcastEventEmitter = require('./BroadcastEventEmitter');
var MixFilterClip = require('./MixFilterClip');
var SourceClip = require('./SourceClip');

function Playlist(logger,serializationCtx) {

    PlaylistItem.prototype.constructor.call(this,logger,serializationCtx);

    var inner = this.inner;
    if(!Object.keys(inner).length) {
        inner.durations = [0];
        inner.sequences = [];
        inner.playlistType = 'live';
        inner.segmentBaseTime = 0;
        inner.firstClipTime = 0;
        inner.initialSegmentIndex = 1;
        inner.initialClipIndex = 1;
        inner.discontinuity = false;
        inner.flavor2SeqIndex = {};
    }
}

util.inherits(Playlist,PlaylistItem);

Playlist.prototype.getClipListForFlavor = function (flavor) {
    var that = this;

    if(flavor === undefined){
        that.logger.info("Playlist.getClipListForFlavor bad flavor=", flavor);
        return;
    }

    // sequenceId can be any identifier -> map to index in array of sequences
    if(that.inner.flavor2SeqIndex[flavor] === undefined){
        that.logger.info("Playlist.getClipListForFlavor add new sequence for flavor", flavor);
        that.inner.flavor2SeqIndex[flavor] = Object.keys(that.inner.flavor2SeqIndex).length;
        that.inner.sequences.push({clips:[]});
    }

    var sequenceIndex = that.inner.flavor2SeqIndex[flavor];
    return that.inner.sequences[sequenceIndex].clips;
};

Playlist.prototype.validate = function validate(opts) {
    var that = this;

    if( (typeof that.inner.playlistType !== 'string') || ['live','vod'].indexOf(that.inner.playlistType) < 0){
        that.logger.warn("Playlist.validate invalid that.inner.playlistType", that.inner.playlistType);
        return false;
    }

    if( (typeof that.inner.firstClipTime !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.firstClipTime type", that.inner.firstClipTime);
        return false;
    }

    if( (typeof that.inner.segmentBaseTime !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.segmentBaseTime type", that.inner.segmentBaseTime);
        return false;
    }

    if( (typeof that.inner.initialClipIndex !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.initialClipIndex type", that.inner.initialClipIndex);
        return false;
    }

    if( (typeof that.inner.initialClipIndex !== 'number')){
        that.logger.warn("invalid that.inner.initialClipIndex type", that.inner.initialClipIndex);
        return false;
    }

    if( !Array.isArray(that.inner.durations) ){
        that.logger.warn("Playlist.validate !that.inner.durations || typeof that.inner.durations !== 'Array'");
        return false;
    }

    if( !_.every(that.inner.durations,function(d){
            return d >= 0;
        })  )  {
        that.logger.warn("Playlist.validate that.inner.duration < 0");
        return false;
    }

    if( !Array.isArray(that.inner.sequences)   ) {
        that.logger.warn("Playlist.validate !that.inner.sequences || typeof that.inner.sequences !== 'Array'");
        return false;
    }

    for( var i in that.inner.sequences) {
        var seq = that.inner.sequences[i];
        if( !Array.isArray(seq.clips) ) {
            that.logger.warn("Playlist.validate !seq.clips !seq.clips instanceof Array ");
            return false;
        }
        if( seq.validate && !seq.validate(opts) ){
            return false;
        }
    }

    if( !_.every(that.inner.sequences,function(seq){
            for( var i in seq.clips ) {
                var clip = seq.clips[i];
                var clipD = clip.getTotalDuration(),
                    overallD = that.inner.durations[i];
                if(  clipD < overallD ){
                    return false;
                }
            }
            return true;
        } ) ) {
        that.logger.warn("Playlist.validate duration is greater than the sum of the durations array ");
        return false;
    }

    if(that.inner.firstClipTime <  that.inner.segmentBaseTime)  {
        that.logger.warn("Playlist.validate that.inner.firstClipTime <  that.inner.segmentBaseTime");
        return false;
    }

    return true;
};

var rangeCompare = function(dtsRange2){
    return this.min < dtsRange2.max && this.max > dtsRange2.min;
};

Playlist.prototype.recalculateOffsetsAndDuration = function recalculateOffsetsAndDuration (index){
    var that = this;

    var minDTS = Number.MIN_VALUE,
        maxDTS = Number.MAX_VALUE;

    // determine dts range

    // step # 1: fill out all clip ranges
   var ranges = _.map(that.inner.sequences,function(seq,index){
        if(seq.clips.length > index) {
            return seq.clips[index].getDTSRange();
        }
    });

    // step # 2: find sequences that have overlapping regions with other clip sequences
    ranges = _.filter(ranges, function(dtsRange){
       return _.every(ranges,rangeCompare,dtsRange);
    });

    _.each(ranges,function(dtsRange){
        minDTS = Math.max(dtsRange.min, minDTS);
        maxDTS = Math.min(maxDTS, dtsRange.max);
    });

    if(minDTS > Number.MIN_VALUE) {

        that.inner.firstClipTime = Math.max(that.inner.firstClipTime,Math.ceil(minDTS));
        that.inner.durations[index] =  Math.ceil(maxDTS-that.inner.firstClipTime);

        var date = new Date(that.inner.firstClipTime);
        that.logger.info("Playlist.recalculateOffsetsAndDuration set firstClipTime=",date);

        _.each(that.inner.sequences,function(seq) {
            seq.clips.forEach(function(c) {
                c.updateOffset(that.inner.firstClipTime);
            });
        });
        return {min:minDTS,max:maxDTS};
    }
};

var unserializeClip = function (c){
    var that = this;
    switch(c.type){
        case 'mixFilter':
            return new MixFilterClip(that.logger,c);
        case 'source':
            return new SourceClip(that.logger,c);
        default:
            throw new Error('unknown clip type ' + c.type);
    }
};

Playlist.prototype.onSerialize = function () {
    var that = this;

    _.each(that.inner.sequences,function (seq) {
        seq.clips = seq.clips.map( function(c) {
            return unserializeClip.call(that,c);
        });
    });
};

Playlist.prototype.addListener = function(listener){
    var that = this;

    BroadcastEventEmitter.prototype.addListener.call(this,listener);
    _.each(that.inner.sequences,function (seq) {
        _.each(seq.clips,function(c){
            c.addListener(listener);
        });
    });
};

Playlist.prototype.removeListener = function(listener){
    BroadcastEventEmitter.prototype.removeListener.call(this,listener);
    _.each(that.inner.sequences,function (seq) {
        _.each(seq.clips,function(c){
            c.removeListener(listener);
        });
    });
};

Playlist.prototype.serializeFrom = function (stream,logger,cbDone){

    var playlistJSON = '';
    stream.on('data', function (chunk) {
        playlistJSON += chunk;
    });
    stream.on('error', function (err) {
        that.logger.warn('failed to read from file error: %s', err);
        cbDone(new Playlist());
    });
    stream.on('end', function () {
        stream.close();
        var playlist = undefined;
        try {
            playlist = JSON.parse(playlistJSON);
        } catch (err) {
            that.logger.warn('unable to unserialize playlist. data loss is inevitable!');
        }
        playlist = new Playlist(logger,playlist);
        cbDone(playlist);
    });
    stream.resume();
};

Playlist.prototype.getDiagnostics = function (opts) {
    var that = this,
        clipDuration = (opts && opts.clipDuration) ? opts.clipDuration : 10000;

    that.recalculateOffsetsAndDuration(0);

    var totalDuration = playlistUtils.sum(that.inner.durations),
        minClip = Math.floor((that.inner.firstClipTime - that.inner.segmentBaseTime) / clipDuration);

    var diag =  {
        unitMs: clipDuration,
        discontinuityMode:  that.inner.discontinuity,
        now:Math.floor((Date.now() - that.inner.segmentBaseTime) / clipDuration),
        window: {
            low: minClip,
            high: Math.floor(totalDuration / clipDuration) + minClip
        },
        windowDurationMs: totalDuration
    };

    if(opts && opts.displayPlaylist) {
        diag.playlist = that;
    }
    if(totalDuration && that.minMax) {
        var overallDuration = Math.max(0,that.minMax.max - that.minMax.min);
        if(overallDuration > totalDuration){
            diag.gapsMsec = overallDuration - totalDuration;
        }
    }
    return diag;
};

Playlist.prototype.collapseGap = function(from,to) {
    var that = this;
    if(from < to) {
        _.each(that.inner.sequences,function (seq) {
            _.each(seq.clips,function (c) {
                c.collapseGap(from, to);
            });
        });
        //TODO: when packager is ready remove following line
        //that.inner.firstClipTime += to - from;
        that.logger.warn('Playlist.collapseGap. that.inner.firstClipTime=%s',new Date(that.inner.firstClipTime));
    }
};

// override
Playlist.prototype.toJSON = function(){
    var that = this;

    if(!that.minMax){
        return PlaylistItem.toJSON.call(that);
    }

    var obj = _.clone(that.inner);

    obj.sequences = _.filter(obj.sequences,function(seq){
        if(seq.clips.length) {
            var dtsRange = seq.clips[0].getDTSRange();
            return rangeCompare.call(that.minMax,dtsRange);
        }
    });

    that.logger.debug("Playlist.toJSON %d valid sequences",obj.sequences.length);

    return obj;
};

Playlist.prototype.getClipFromFileInfo = function (fileInfo,eventListener) {
    var that = this;

    var clips = that.getClipListForFlavor(fileInfo.flavor);

    var lastClip = clips.length > 0 ? clips[clips.length - 1] : null;

    if( !lastClip/*
     || lastClip.type === 'source'
     || (lastClip.type === 'mixFilter'
     && (lastClip.sources[0].paths.length > that.playListLimits.maxChunksPerClip
     || lastClip.getDuration(that.logger) + fileInfo.videoDuration > that.playListLimits.maxClipDuration))*/
    ) {
        var newClip = new MixFilterClip(that.logger);
        newClip.addListener(eventListener);
        clips.push(newClip);
    }
    return clips[clips.length - 1];
};

module.exports = Playlist;

<commit_msg>code cleanup<commit_after>/*
 *   vod packager playlist implementation.
 *   for details see https://github.com/kaltura/nginx-vod-module
 * */

var    _ = require('underscore');
var util = require('util');
var playlistUtils = require('./playlistGenrator-utils');
var PlaylistItem = require('./PlaylistItem');
var BroadcastEventEmitter = require('./BroadcastEventEmitter');
var MixFilterClip = require('./MixFilterClip');
var SourceClip = require('./SourceClip');

function Playlist(logger,serializationCtx) {

    PlaylistItem.prototype.constructor.call(this,logger,serializationCtx);

    var inner = this.inner;
    if(!Object.keys(inner).length) {
        inner.durations = [0];
        inner.sequences = [];
        inner.playlistType = 'live';
        inner.segmentBaseTime = 0;
        inner.firstClipTime = 0;
        inner.initialSegmentIndex = 1;
        inner.initialClipIndex = 1;
        inner.discontinuity = false;
        inner.flavor2SeqIndex = {};
    }
}

util.inherits(Playlist,PlaylistItem);

Playlist.prototype.getClipListForFlavor = function (flavor) {
    var that = this;

    if(flavor === undefined){
        that.logger.info("Playlist.getClipListForFlavor bad flavor=", flavor);
        return;
    }

    // sequenceId can be any identifier -> map to index in array of sequences
    if(that.inner.flavor2SeqIndex[flavor] === undefined){
        that.logger.info("Playlist.getClipListForFlavor add new sequence for flavor", flavor);
        that.inner.flavor2SeqIndex[flavor] = Object.keys(that.inner.flavor2SeqIndex).length;
        that.inner.sequences.push({clips:[]});
    }

    var sequenceIndex = that.inner.flavor2SeqIndex[flavor];
    return that.inner.sequences[sequenceIndex].clips;
};

Playlist.prototype.validate = function validate(opts) {
    var that = this;

    if( (typeof that.inner.playlistType !== 'string') || ['live','vod'].indexOf(that.inner.playlistType) < 0){
        that.logger.warn("Playlist.validate invalid that.inner.playlistType", that.inner.playlistType);
        return false;
    }

    if( (typeof that.inner.firstClipTime !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.firstClipTime type", that.inner.firstClipTime);
        return false;
    }

    if( (typeof that.inner.segmentBaseTime !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.segmentBaseTime type", that.inner.segmentBaseTime);
        return false;
    }

    if( (typeof that.inner.initialClipIndex !== 'number')){
        that.logger.warn("Playlist.validate invalid that.inner.initialClipIndex type", that.inner.initialClipIndex);
        return false;
    }

    if( (typeof that.inner.initialClipIndex !== 'number')){
        that.logger.warn("invalid that.inner.initialClipIndex type", that.inner.initialClipIndex);
        return false;
    }

    if( !Array.isArray(that.inner.durations) ){
        that.logger.warn("Playlist.validate !that.inner.durations || typeof that.inner.durations !== 'Array'");
        return false;
    }

    if( !_.every(that.inner.durations,function(d){
            return d >= 0;
        })  )  {
        that.logger.warn("Playlist.validate that.inner.duration < 0");
        return false;
    }

    if( !Array.isArray(that.inner.sequences)   ) {
        that.logger.warn("Playlist.validate !that.inner.sequences || typeof that.inner.sequences !== 'Array'");
        return false;
    }

    for( var i in that.inner.sequences) {
        var seq = that.inner.sequences[i];
        if( !Array.isArray(seq.clips) ) {
            that.logger.warn("Playlist.validate !seq.clips !seq.clips instanceof Array ");
            return false;
        }
        if( seq.validate && !seq.validate(opts) ){
            return false;
        }
    }

    if( !_.every(that.inner.sequences,function(seq){
            for( var i in seq.clips ) {
                var clip = seq.clips[i];
                var clipD = clip.getTotalDuration(),
                    overallD = that.inner.durations[i];
                if(  clipD < overallD ){
                    return false;
                }
            }
            return true;
        } ) ) {
        that.logger.warn("Playlist.validate duration is greater than the sum of the durations array ");
        return false;
    }

    if(that.inner.firstClipTime <  that.inner.segmentBaseTime)  {
        that.logger.warn("Playlist.validate that.inner.firstClipTime <  that.inner.segmentBaseTime");
        return false;
    }

    return true;
};

var rangeOverlap = function(dtsRange2){
    return this.min < dtsRange2.max && this.max > dtsRange2.min;
};

Playlist.prototype.recalculateOffsetsAndDuration = function recalculateOffsetsAndDuration (index){
    var that = this;

    var minDTS = Number.MIN_VALUE,
        maxDTS = Number.MAX_VALUE;

    // determine dts range

    // step # 1: fill out all clip ranges
   var ranges = _.map(that.inner.sequences,function(seq,index){
        if(seq.clips.length > index) {
            return seq.clips[index].getDTSRange();
        }
    });

    // step # 2: find sequences that have overlapping regions with other clip sequences
    ranges = _.filter(ranges, function(dtsRange){
       return _.every(ranges,rangeOverlap,dtsRange);
    });

    _.each(ranges,function(dtsRange){
        minDTS = Math.max(dtsRange.min, minDTS);
        maxDTS = Math.min(maxDTS, dtsRange.max);
    });

    if(minDTS > Number.MIN_VALUE) {

        that.inner.firstClipTime = Math.max(that.inner.firstClipTime,Math.ceil(minDTS));
        that.inner.durations[index] =  Math.ceil(maxDTS-that.inner.firstClipTime);

        var date = new Date(that.inner.firstClipTime);
        that.logger.info("Playlist.recalculateOffsetsAndDuration set firstClipTime=",date);

        _.each(that.inner.sequences,function(seq) {
            seq.clips.forEach(function(c) {
                c.updateOffset(that.inner.firstClipTime);
            });
        });
        return {min:minDTS,max:maxDTS};
    }
};

var unserializeClip = function (c){
    var that = this;
    switch(c.type){
        case 'mixFilter':
            return new MixFilterClip(that.logger,c);
        case 'source':
            return new SourceClip(that.logger,c);
        default:
            throw new Error('unknown clip type ' + c.type);
    }
};

Playlist.prototype.onSerialize = function () {
    var that = this;

    _.each(that.inner.sequences,function (seq) {
        seq.clips = seq.clips.map( function(c) {
            return unserializeClip.call(that,c);
        });
    });
};

Playlist.prototype.addListener = function(listener){
    var that = this;

    BroadcastEventEmitter.prototype.addListener.call(this,listener);
    _.each(that.inner.sequences,function (seq) {
        _.each(seq.clips,function(c){
            c.addListener(listener);
        });
    });
};

Playlist.prototype.removeListener = function(listener){
    BroadcastEventEmitter.prototype.removeListener.call(this,listener);
    _.each(that.inner.sequences,function (seq) {
        _.each(seq.clips,function(c){
            c.removeListener(listener);
        });
    });
};

Playlist.prototype.serializeFrom = function (stream,logger,cbDone){

    var playlistJSON = '';
    stream.on('data', function (chunk) {
        playlistJSON += chunk;
    });
    stream.on('error', function (err) {
        that.logger.warn('failed to read from file error: %s', err);
        cbDone(new Playlist());
    });
    stream.on('end', function () {
        stream.close();
        var playlist = undefined;
        try {
            playlist = JSON.parse(playlistJSON);
        } catch (err) {
            that.logger.warn('unable to unserialize playlist. data loss is inevitable!');
        }
        playlist = new Playlist(logger,playlist);
        cbDone(playlist);
    });
    stream.resume();
};

Playlist.prototype.getDiagnostics = function (opts) {
    var that = this,
        clipDuration = (opts && opts.clipDuration) ? opts.clipDuration : 10000;

    that.recalculateOffsetsAndDuration(0);

    var totalDuration = playlistUtils.sum(that.inner.durations),
        minClip = Math.floor((that.inner.firstClipTime - that.inner.segmentBaseTime) / clipDuration);

    var diag =  {
        unitMs: clipDuration,
        discontinuityMode:  that.inner.discontinuity,
        now:Math.floor((Date.now() - that.inner.segmentBaseTime) / clipDuration),
        window: {
            low: minClip,
            high: Math.floor(totalDuration / clipDuration) + minClip
        },
        windowDurationMs: totalDuration
    };

    if(opts && opts.displayPlaylist) {
        diag.playlist = that;
    }
    if(totalDuration && that.minMax) {
        var overallDuration = Math.max(0,that.minMax.max - that.minMax.min);
        if(overallDuration > totalDuration){
            diag.gapsMsec = overallDuration - totalDuration;
        }
    }
    return diag;
};

Playlist.prototype.collapseGap = function(from,to) {
    var that = this;
    if(from < to) {
        _.each(that.inner.sequences,function (seq) {
            _.each(seq.clips,function (c) {
                c.collapseGap(from, to);
            });
        });
        //TODO: when packager is ready remove following line
        //that.inner.firstClipTime += to - from;
        that.logger.warn('Playlist.collapseGap. that.inner.firstClipTime=%s',new Date(that.inner.firstClipTime));
    }
};

// override
Playlist.prototype.toJSON = function(){
    var that = this;

    if(!that.minMax){
        return PlaylistItem.toJSON.call(that);
    }

    var obj = _.clone(that.inner);

    obj.sequences = _.filter(obj.sequences,function(seq){
        if(seq.clips.length) {
            var dtsRange = seq.clips[0].getDTSRange();
            return rangeOverlap.call(that.minMax,dtsRange);
        }
    });

    that.logger.debug("Playlist.toJSON %d valid sequences",obj.sequences.length);

    return obj;
};

Playlist.prototype.getClipFromFileInfo = function (fileInfo,eventListener) {
    var that = this;

    var clips = that.getClipListForFlavor(fileInfo.flavor);

    var lastClip = clips.length > 0 ? clips[clips.length - 1] : null;

    if( !lastClip/*
     || lastClip.type === 'source'
     || (lastClip.type === 'mixFilter'
     && (lastClip.sources[0].paths.length > that.playListLimits.maxChunksPerClip
     || lastClip.getDuration(that.logger) + fileInfo.videoDuration > that.playListLimits.maxClipDuration))*/
    ) {
        var newClip = new MixFilterClip(that.logger);
        newClip.addListener(eventListener);
        clips.push(newClip);
    }
    return clips[clips.length - 1];
};

module.exports = Playlist;

<|endoftext|>


<commit_before>// const utils = require('../utils.js')

/**
 *
 * @param user - an username which indicates the user who uploaded the file
 * @param assignee - a list of assignees of the tasks
 * @return score - 1.0 or 0.0 which indicates whether the assin
 */
function isAssigneePlugin (user, assignees) {
  let found = false
  for (let x of assignees) {
    if (x === user) {
      found = true
      break
    } else {
      found = false
    }
  }

  return found ? 1.0 : 0.0
}

module.exports = isAssigneePlugin

/*
Bei der Konfiguration:
let plugin =
{ 'assignees':
  { use: 'is-in-set',
    inputs: ['file.user', 'tasks[].assignees']
  }
}
, und dem Input:
let file =
{
  user: 'a'
},
let tasks =
[
  {
    assignees: ['b', 'c']
  },
  {
    assignees: ['a', 'c']
  }
]
}
, soll das Ergebnis wie folgt aussehen:
let result =
[
  {
    'assignees': 0.0
  },
  {
    'assignees': 1.0
  }
]
*/
<commit_msg>clean up<commit_after>// const utils = require('../utils.js')

/**
 *
 * @param user - an username which indicates the user who uploaded the file
 * @param assignee - a list of assignees of the task
 * @return score - 1.0 or 0.0 which indicates whether the user is in the assignee list
 */
function isAssigneePlugin (user, assignees) {
  let found = false
  for (let x of assignees) {
    if (x === user) {
      found = true
      break
    } else {
      found = false
    }
  }

  return found ? 1.0 : 0.0
}

module.exports = isAssigneePlugin
<|endoftext|>


<commit_before>var _ = require('underscore'),
    lumbar = require('../lumbar');

function combineResources(context, outputData, callback) {
  var resources = context.resources || [];
  if (!resources.length) {
    return callback();
  }

  context.outputFile(function(callback) {
    lumbar.combine(
      resources,
      context.fileName,
      context.options.minimize && context.mode === 'scripts',
      context.mode === 'styles',
      function(err, data) {
        if (data) {
          _.extend(data, outputData, {
            fileConfig: context.fileConfig,
            platform: context.platform,
            mode: context.mode
          });
        }
        callback(err, data)
      });
    },
    callback);
}

module.exports = {
  module: function(context, next, complete) {
    next(function(err) {
      if (err) {
        return complete(err);
      }

      if (!context.combined) {
        context.resources = context.moduleResources;
        context.moduleResources = undefined;
        combineResources(context, {
            package: context.package,
            module: context.module.name
          },
          complete);
      } else {
        context.combineResources = context.combineResources || {};
        context.combineResources[context.module.name] = context.moduleResources;
        context.moduleResources = undefined;
        complete();
      }
    });
  }
};
<commit_msg>Implement combined many to one resource output<commit_after>var _ = require('underscore'),
    lumbar = require('../lumbar');

function combineResources(context, outputData, callback) {
  var resources = context.resources || [];
  if (!resources.length) {
    return callback();
  }

  context.outputFile(function(callback) {
    lumbar.combine(
      resources,
      context.fileName,
      context.options.minimize && context.mode === 'scripts',
      context.mode === 'styles',
      function(err, data) {
        if (data) {
          _.extend(data, outputData, {
            fileConfig: context.fileConfig,
            platform: context.platform,
            mode: context.mode
          });
        }
        callback(err, data)
      });
    },
    callback);
}

module.exports = {
  modeComplete: function(context, next, complete) {
    next(function(err) {
      if (err) {
        return complete(err);
      }

      if (context.combined) {
        // Build the resources array from each of the modules (Need to maintain proper ordering)
        var modules = context.config.moduleList(context.package);
        context.resources = [];
        modules.forEach(function(module) {
          context.resources.push.apply(context.resources, context.combineResources[module]);
        });
        combineResources(context, { package: context.package }, complete);
      } else {
        complete();
      }
    });
  },
  module: function(context, next, complete) {
    next(function(err) {
      if (err) {
        return complete(err);
      }

      if (!context.combined) {
        context.resources = context.moduleResources;
        context.moduleResources = undefined;
        combineResources(context, {
            package: context.package,
            module: context.module.name
          },
          complete);
      } else {
        context.combineResources = context.combineResources || {};
        context.combineResources[context.module.name] = context.moduleResources;
        context.moduleResources = undefined;
        complete();
      }
    });
  }
};
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

var _ = require('lodash');
var sortBy = require('../lib/sortBy');

module.exports = function(dust) {

  /*
   * @disclaimer - this is a temporary filter helper to separate a recommended hotel(s) from a list of hotels. This is temporary because it's written in dust, which will change soon.
   *
   * @description Augmented sorting method that orders a list of things based on a child node, and then filters the result based on an object and a value.
   * @param {object} parent Object to sort
   * @param {string} node Child node to sort object by
   * @param {object} filterArray - array to base the filter on
   * @param {string} filterValue - value to check against in the filter function
   * @param {boolean as string} exclude - if 'true', the filter function will exclude all items in the filterArray, based on the filterValue
   * @param {boolean as string} include - if 'true', the filter function will include all items in the filterArray, based on the filterValue
   * @example {@_sortByNumberWithFilter parent=packageRatesReply.packageRates node="grossPrice" filterArray=_brandConfig.featuredHotel filterValue="x.links.hotelProducts.ids[0]" include="true"} {/_sortByNumberWithFilter} output loop of parent object sorted by node and filtered by filterArray
   */

  dust.helpers._sortByNumberWithFilter = function(chunk, context, bodies, params) {
    var parent = params.parent;
    var node = params.node;
    var filterArray = params.filterArray;
    var filterValue = params.filterValue;
    var include = params.include;
    var exclude = params.exclude;

    var mappedObject = sortBy(parent, node);
    var newMappedObject = [];

    //if filterArray exists, filter out from mappedObject
    if (filterArray.length && filterValue) {
      newMappedObject = _.filter(mappedObject, function(x) {
        //filter mapped object, removing objects from filterArray
        if (exclude) {
          return filterArray.indexOf(eval(filterValue)) < 0;
        }
        else if (include) {
          return filterArray.indexOf(eval(filterValue)) > -1;
        }
      });
    }

    if (newMappedObject.length) {
      mappedObject = newMappedObject;
    }
    _.forEach(mappedObject, function(item) {
      chunk = chunk.render(bodies.block, context.push(item));
    });

    return chunk;
  };
};
<commit_msg>removed sortByNumberWithFilter.js as unnecessary<commit_after><|endoftext|>


<commit_before>'use strict'

/**
 * @fileoverview Missing wait timeout message in browser.wait() (missing-wait-message)
 * @author Alexander Afanasyev
 */

module.exports = function (context) {
  return {
    'CallExpression': function (node) {
      var objectName = node.callee.object.name
      var propertyName = node.callee.property.name

      if (propertyName === 'wait' && objectName === 'browser' && node.arguments.length < 3) {
        context.report(node, 'No timeout message provided for browser.wait()')
      }
    }
  }
}
<commit_msg>fix(rules): fixed 'missing-wait-message' object and property check<commit_after>'use strict'

/**
 * @fileoverview Missing wait timeout message in browser.wait() (missing-wait-message)
 * @author Alexander Afanasyev
 */

module.exports = function (context) {
  return {
    'CallExpression': function (node) {
      var object = node.callee.object
      var property = node.callee.property

      if (object && property && property.name === 'wait' && object.name === 'browser' && node.arguments.length < 3) {
        context.report(node, 'No timeout message provided for browser.wait()')
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
** Module dependencies
*/
var request = require('superagent');
var _ = require('lodash');
var util = require('util');
var config = require('../../config/config');
var moment = require('moment');
var mapSituation = require('./mapping').mapSituation;

var prestations = {
    aspa: Number,
    acs: {
        type: Number,
        montantAnnuel: true
    },
    cmu_c: Boolean,
    apl: Number,
    als: Number,
    alf: Number,
    af: Number,
    rsa: Number,
    asf: Number,
    cf: Number,
    ass: Number,
    paje_base: Number
};

function buildPeriod(situation) {
    return moment(situation.dateDeValeur || Date.now()).format('YYYY-MM');
}

function buildRequest(situation, debug) {
    return {
        intermediate_variables: debug,
        scenarios: [{
            test_case: mapSituation(situation),
            period: 'month:' + buildPeriod(situation)
        }],
        variables: _.keys(prestations)
    };
}

function calculate(situation, debug, callback) {
    request
        .post(config.openfiscaApi + '/api/1/calculate')
        .send(buildRequest(situation, debug))
        .end(function(err, response) {
            if (err) return callback(err);
            if (response.error) {
                console.log('Response body: ', util.inspect(response.body, { showHidden: true, depth: null }));
                return callback({ apiError: 'Communication error with OpenFisca' });
            }

            callback(null, response.body);
        });
}

function simulate(situation, callback) {
    calculate(situation, false, function(err, response) {
        if (err)  return callback(err);

        var result = _.mapValues(prestations, function(definition, name) {
            var type;
            var montantAnnuel = false;
            if ('type' in definition) {
                type = definition.type;
                montantAnnuel = !!definition.montantAnnuel;
            } else {
                type = definition;
            }
            var period = buildPeriod(situation);
            var key = response.value[0].familles[0][name];
            var value = typeof key === 'object' ? key[period] : key;
            if (type === Number) {
                if (montantAnnuel) {
                    value *= 12;
                }
                return Math.round(value * 100) / 100;
            }
            return value;
        });
        callback(null, result);
    });
}

/*
** Exports
*/
exports.calculate = calculate;
exports.simulate = simulate;
exports.buildRequest = buildRequest;
<commit_msg>ajout bourse college dans la liste des droits demandés à openfisca<commit_after>/*
** Module dependencies
*/
var request = require('superagent');
var _ = require('lodash');
var util = require('util');
var config = require('../../config/config');
var moment = require('moment');
var mapSituation = require('./mapping').mapSituation;

var prestations = {
    aspa: Number,
    acs: {
        type: Number,
        montantAnnuel: true
    },
    cmu_c: Boolean,
    apl: Number,
    als: Number,
    alf: Number,
    af: Number,
    rsa: Number,
    asf: Number,
    cf: Number,
    ass: Number,
    paje_base: Number,
    bourse_college: {
        type: Number,
        montantAnnuel: true
    }
};

function buildPeriod(situation) {
    return moment(situation.dateDeValeur || Date.now()).format('YYYY-MM');
}

function buildRequest(situation, debug) {
    return {
        intermediate_variables: debug,
        scenarios: [{
            test_case: mapSituation(situation),
            period: 'month:' + buildPeriod(situation)
        }],
        variables: _.keys(prestations)
    };
}

function calculate(situation, debug, callback) {
    request
        .post(config.openfiscaApi + '/api/1/calculate')
        .send(buildRequest(situation, debug))
        .end(function(err, response) {
            if (err) return callback(err);
            if (response.error) {
                console.log('Response body: ', util.inspect(response.body, { showHidden: true, depth: null }));
                return callback({ apiError: 'Communication error with OpenFisca' });
            }

            callback(null, response.body);
        });
}

function simulate(situation, callback) {
    calculate(situation, false, function(err, response) {
        if (err)  return callback(err);

        var result = _.mapValues(prestations, function(definition, name) {
            var type;
            var montantAnnuel = false;
            if ('type' in definition) {
                type = definition.type;
                montantAnnuel = !!definition.montantAnnuel;
            } else {
                type = definition;
            }
            var period = buildPeriod(situation);
            var key = response.value[0].familles[0][name];
            var value = typeof key === 'object' ? key[period] : key;
            if (type === Number) {
                if (montantAnnuel) {
                    value *= 12;
                }
                return Math.round(value * 100) / 100;
            }
            return value;
        });
        callback(null, result);
    });
}

/*
** Exports
*/
exports.calculate = calculate;
exports.simulate = simulate;
exports.buildRequest = buildRequest;
<|endoftext|>


<commit_before>function load_songs(textarea) {
    var encoded_uri = textarea.value;
    var decoded = decodeURIComponent(encoded_uri);
    var without_protocol = decoded.replace("irealb://", "");
    var unsplitted = without_protocol.split("==0=0===");
    for(i in unsplitted) {
        song = unsplitted[i].split("=");
        title = song[0];
        author = song[1];
        localStorage[title + " (" + author + ")"] = unsplitted[i]
    }
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49)
    }
    return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|");
}
function get_sheet(unwarbled) {
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
            bars += 1;
            if(bars < 4)
            {
                c += open_span
            }
        }
        else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
function play_mma(mma) {
  var worker = new Worker("//rawgit.com/yazgoo/pypyjs-mma/master/worker.js")
  worker.postMessage([mma]);
  console.log('Message posted to worker');
  worker.onmessage = function(e) {
    console.log('Message received from worker');
    console.log(btoa(e.data));
    data = e.data
      console.log("playing " + data);
    play(data);
  }
}
function play_song(unwarbled) {
    var previous = "";
    unwarbled = unwarbled.replace(/T../, '?Groove Swing\n')
        .replace(/\{/g, "\n?Repeat\n").replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\\2\n").replace("][", "")
        .replace("[", "\n")
        .replace(/N2/g, "").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "dim")
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n")
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    console.log(previous);
    play_mma(previous);
}
function show_song(title) {
    var song = localStorage[title];
    localStorage["last_song"] = song;
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1];
    var unwarbled = unwarble(splitted[6]);
    set_content(""+title+" ("+author+")"
            + "<input type=button value='>' onclick=\"play_song('"+unwarbled+"')\"/>

"
            + get_sheet(unwarbled));
}
function show_songs_list(div) {
    div.innerHTML = "";
    for(var i = 0; i < 100;/*localStorage.length*/ i++) {
        var title = localStorage.key(i);
        div.innerHTML += "" + title  + "
";
    }
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("<input type=text onchange='load_songs(this)'/>");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            +'')
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
    if(localStorage["last_song"] != null) {
        show_song("last_song");
    }
    else {
        show_songs();
    }
}

<commit_msg>writing song list gradually, replacing x in mma<commit_after>function load_songs(textarea) {
    var encoded_uri = textarea.value;
    var decoded = decodeURIComponent(encoded_uri);
    var without_protocol = decoded.replace("irealb://", "");
    var unsplitted = without_protocol.split("==0=0===");
    for(i in unsplitted) {
        song = unsplitted[i].split("=");
        title = song[0];
        author = song[1];
        localStorage[title + " (" + author + ")"] = unsplitted[i]
    }
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49)
    }
    return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|");
}
function get_sheet(unwarbled) {
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
            bars += 1;
            if(bars < 4)
            {
                c += open_span
            }
        }
        else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
function play_mma(mma) {
  var worker = new Worker("//rawgit.com/yazgoo/pypyjs-mma/master/worker.js")
  worker.postMessage([mma]);
  console.log('Message posted to worker');
  worker.onmessage = function(e) {
    console.log('Message received from worker');
    console.log(btoa(e.data));
    data = e.data
      console.log("playing " + data);
    play(data);
  }
}
function play_song(unwarbled) {
    var previous = "";
    unwarbled = unwarbled.replace(/T../, '?Groove Swing\n')
        .replace(/\{/g, "\n?Repeat\n").replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\\2\n").replace("][", "")
        .replace("[", "\n")
        .replace(/N2/g, "").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "dim")
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n").replace(/x/g, "")
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    console.log(previous);
    play_mma(previous);
}
function show_song(title) {
    var song = localStorage[title];
    localStorage["last_song"] = song;
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1];
    var unwarbled = unwarble(splitted[6]);
    set_content(""+title+" ("+author+")"
            + "<input type=button value='>' onclick=\"play_song('"+unwarbled+"')\"/>

"
            + get_sheet(unwarbled));
}
var songs_list_written;
var songs_list_div;
function add_songs_list() {
  var i;
  s = ""
    for(i = songs_list_written; i < (songs_list_written + 100) && i < localStorage.length; i++) {
        var title = localStorage.key(i);
        s += "" + title  + "
";
    }
  songs_list_div.innerHTML += s;
    songs_list_written += 100;
    if(i < localStorage.length) setTimeout(add_songs_list(), 500);
}
function show_songs_list(div) {
    songs_list_div = div;
    div.innerHTML = "";
    songs_list_written = 0;
    add_songs_list();
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("<input type=text onchange='load_songs(this)'/>");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            +'')
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
    if(localStorage["last_song"] != null) {
        show_song("last_song");
    }
    else {
        show_songs();
    }
}

<|endoftext|>


<commit_before>// Load in lib and dependencies
var trunkata = require('../lib/trunkata.js'),
    expect = require('chai').expect,
    fs = require('fs'),
    domify = require('domify'),
    $mocha = document.getElementById('mocha');

// Set up helper action
function fixtureNode() {
  before(function () {
    // Create our content
    var node = domify('
' + this.input + '
');
    document.body.insertBefore(node, $mocha);

    // Save for later
    this.node = node;
  });
  after(function () {
    // document.body.removeChild(this.node);
  });
}

// Basic tests
describe('A short string
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/short_string.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is unchanged', function () {
      expect(this.node.innerHTML).to.equal(this.input);
    });
  });
});

describe('A long string
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_string.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('ends with an ellipsis', function () {
      expect(this.node.innerHTML.slice(-1)).to.equal('…');
    });
  });
});

// Intermediate tests
describe('A short and long
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/short_long.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('removes the second child OR the second child is empty', function () {
      var childNodes = this.node.childNodes,
          secondChild = childNodes[1],
          passed = secondChild ? secondChild.innerHTML === '' : true;
      expect(passed).to.equal(true);
    });

    it('leaves first child alone', function () {
      expect(this.node.childNodes[0].innerHTML).to.equal('abc');
    });
  });
});

describe('A long and short
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_short.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('removes the second child', function () {
      expect(this.node.childNodes.length).to.equal(1);
    });

    it('is truncated', function () {
      var longInput = fs.readFileSync(__dirname + '/test_files/long_string.html', 'utf8');
      expect(this.node.innerHTML.length).to.be.lessThan(longInput.length);
    });
  });
});

describe('Linked text', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/linked.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('keeps the link intact', function () {
      expect(this.node.innerHTML).to.contain('Non amet');
    });
  });
});

describe('Long linked text', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_linked.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('keeps the link intact', function () {
      expect(this.node.innerHTML).to.contain('Non');
    });

    it('has no trailing non-link ellipsis', function () {
      // Verify the last node is a link node
      var childNodes = this.node.childNodes,
          nodeName = childNodes[childNodes.length - 1].nodeName.toUpperCase();
      expect(nodeName).to.equal('A');
    });
  });
});

describe('Three short texts', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/three_shorts.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('has at most 2 children', function () {
      expect(this.node.childNodes.length).to.be.lessThan(3);
    });
  });
});

describe('Text with line breaks', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/line_breaks.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('has the exclusively first line content', function () {
      expect(this.node.innerHTML).to.match(/^
abc(
)?<\/div>$/);
    });
  });
});

// Advanced tests
describe('Content with childNodes', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/linked.html', 'utf8');
  });
  fixtureNode();
  before(function () {
    // Save a reference to the child node
    this.childNode = this.node.childNodes[0];
  });

  it('has a childNode which is a link', function () {
    var nodeName = this.childNode.nodeName.toUpperCase();
    expect(nodeName).to.equal('A');
  });

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    // DEV: Alternatively, test event bindings of children are not lost
    it('the child node is the same', function () {
      expect(this.node.childNodes[0]).to.equal(this.childNode);
    });
  });
});

<commit_msg>Removing insertBefore which will have trouble with testling<commit_after>// Load in lib and dependencies
var trunkata = require('../lib/trunkata.js'),
    expect = require('chai').expect,
    fs = require('fs'),
    domify = require('domify');

// Set up helper action
function fixtureNode() {
  before(function () {
    // Create our content
    var node = domify('
' + this.input + '
');
    document.body.appendChild(node);

    // Save for later
    this.node = node;
  });
  after(function () {
    // document.body.removeChild(this.node);
  });
}

// Basic tests
describe('A short string
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/short_string.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is unchanged', function () {
      expect(this.node.innerHTML).to.equal(this.input);
    });
  });
});

describe('A long string
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_string.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('ends with an ellipsis', function () {
      expect(this.node.innerHTML.slice(-1)).to.equal('…');
    });
  });
});

// Intermediate tests
describe('A short and long
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/short_long.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('removes the second child OR the second child is empty', function () {
      var childNodes = this.node.childNodes,
          secondChild = childNodes[1],
          passed = secondChild ? secondChild.innerHTML === '' : true;
      expect(passed).to.equal(true);
    });

    it('leaves first child alone', function () {
      expect(this.node.childNodes[0].innerHTML).to.equal('abc');
    });
  });
});

describe('A long and short
', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_short.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('removes the second child', function () {
      expect(this.node.childNodes.length).to.equal(1);
    });

    it('is truncated', function () {
      var longInput = fs.readFileSync(__dirname + '/test_files/long_string.html', 'utf8');
      expect(this.node.innerHTML.length).to.be.lessThan(longInput.length);
    });
  });
});

describe('Linked text', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/linked.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('keeps the link intact', function () {
      expect(this.node.innerHTML).to.contain('Non amet');
    });
  });
});

describe('Long linked text', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/long_linked.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('keeps the link intact', function () {
      expect(this.node.innerHTML).to.contain('Non');
    });

    it('has no trailing non-link ellipsis', function () {
      // Verify the last node is a link node
      var childNodes = this.node.childNodes,
          nodeName = childNodes[childNodes.length - 1].nodeName.toUpperCase();
      expect(nodeName).to.equal('A');
    });
  });
});

describe('Three short texts', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/three_shorts.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('has at most 2 children', function () {
      expect(this.node.childNodes.length).to.be.lessThan(3);
    });
  });
});

describe('Text with line breaks', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/line_breaks.html', 'utf8');
  });
  fixtureNode();

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    it('has the exclusively first line content', function () {
      expect(this.node.innerHTML).to.match(/^
abc(
)?<\/div>$/);
    });
  });
});

// Advanced tests
describe('Content with childNodes', function () {
  before(function () {
    this.input = fs.readFileSync(__dirname + '/test_files/linked.html', 'utf8');
  });
  fixtureNode();
  before(function () {
    // Save a reference to the child node
    this.childNode = this.node.childNodes[0];
  });

  it('has a childNode which is a link', function () {
    var nodeName = this.childNode.nodeName.toUpperCase();
    expect(nodeName).to.equal('A');
  });

  describe('when truncated', function () {
    before(function () {
      trunkata(this.node);
    });

    it('is truncated', function () {
      expect(this.node.innerHTML.length).to.be.lessThan(this.input.length);
    });

    // DEV: Alternatively, test event bindings of children are not lost
    it('the child node is the same', function () {
      expect(this.node.childNodes[0]).to.equal(this.childNode);
    });
  });
});

<|endoftext|>


<commit_before>(function($) {

	/**
	 * @class Base edit form, provides ajaxified saving
	 * and reloading itself through the ajax return values.
	 * Takes care of resizing tabsets within the layout container.
	 * @name ss.Form_EditForm
	 */
	$('#Form_EditForm').concrete('ss',function($){
		return/** @lends ss.Form_EditForm */{

			/**
			 * @type String HTML text to show when the form has been deleted.
			 * @todo i18n
			 */
			RemoveHtml: 'Removed',

			onmatch: function() {
				// Don't bind any events here, as we dont replace the
				// full <form> tag by any ajax updates they won't automatically reapply

				_super();
			},

			/**
			 * Suppress submission unless it is handled through ajaxSubmit()
			 */
			onsubmit: function(e) {
				return false;
			},

			/**
			 * @param {DOMElement} button The pressed button (optional)
			 */
			ajaxSubmit: function(button) {
				// default to first button if none given - simulates browser behaviour
				if(!button) button = this.find(':submit:first');

				var self = this;

				this.trigger('ajaxsubmit', {button: button});

				// set button to "submitting" state
				$(button).addClass('loading');

				// @todo TinyMCE coupling
				if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();

				// validate if required
				if(!this.validate()) {
					// TODO Automatically switch to the tab/position of the first error
					statusMessage("Validation failed.", "bad");

					$(button).removeClass('loading');

					return false;
				}

				// get all data from the form
				var formData = this.serializeArray();
				// add button action
				formData.push({name: $(button).attr('name'), value:'1'});

				$.ajax({
					url: this.attr('action'),
					data: formData,
					type: 'POST',
					complete: function(xmlhttp, status) {
						$(button).removeClass('loading');
						// pass along original form data to enable old/new comparisons
						self._loadResponse(xmlhttp.responseText, status, xmlhttp, formData);
					},
					dataType: 'html'
				});

				return false;
			},

			/**
			 * Hook in (optional) validation routines.
			 * Currently clientside validation is not supported out of the box in the CMS.
			 *
			 * @todo Placeholder implementation
			 *
			 * @return {boolean}
			 */
			validate: function() {
				var isValid = true;
				this.trigger('validate', {isValid: isValid});

				return isValid;
			},

			/**
			 * @param String url
			 * @param Function callback (Optional)
			 */
			load: function(url, callback) {
				var self = this;
				$.ajax({
					url: url,
					complete: function(xmlhttp, status) {
						self._loadResponse(xmlhttp.responseText, status, xmlhttp);
						if(callback) callback.apply(self, arguments);
					},
					dataType: 'html'
				});
			},

			/**
			 * Remove everying inside the <form> tag
			 * with a custom HTML fragment. Useful e.g. for deleting a page in the CMS.
			 *
			 * @param {String} removeText Short note why the form has been removed, displayed in
 tags.
			 *  Falls back to the default RemoveText() option (Optional)
			 */
			removeForm: function(removeText) {
				if(!removeText) removeText = this.RemoveText();
				this.html('
' + removeText + '
');
			},

			/**
			 * Remove all the currently active TinyMCE editors.
			 * Note: Everything that calls this externally has an inappropriate coupling to TinyMCE.
			 */
			cleanup: function() {
				if((typeof tinymce != 'undefined') && tinymce.EditorManager) {
					var id;
					for(id in tinymce.EditorManager.editors) {
						tinymce.EditorManager.editors[id].remove();
					}
					tinymce.EditorManager.editors = {};
				}
			},

			/**
			 * @param {String} data Either HTML for straight insertion, or eval'ed JavaScript.
			 *  If passed as HTML, it is assumed that everying inside the <form> tag is replaced,
			 *  but the old <form> tag itself stays intact.
			 * @param {String} status
			 * @param {XMLHTTPRequest} xmlhttp
			 * @param {Array} origData The original submitted data, useful to do comparisons of changed
			 *  values in new form output, e.g. to detect a URLSegment being changed on the serverside.
			 *  Array in jQuery serializeArray() notation.
			 */
			_loadResponse: function(data, status, xmlhttp, origData) {
				if(status == 'success') {
					this.cleanup();

					var html = data;

					// Rewrite # links
					html = html.replace(/(]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');

					// Rewrite iframe links (for IE)
					html = html.replace(/(]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');

					// Prepare iframes for removal, otherwise we get loading bugs
					this.find('iframe').each(function() {
						this.contentWindow.location.href = 'about:blank';
						this.remove();
					});

					// update form content
					if(html) {
						this.html(html);
					} else {
						this.removeForm();
					}

					// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
					for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
						var el = this.find(':input[name='+ '_form_' + overrideAttr + ']');
						if(el) {
							this.attr(overrideAttr, el.val());
							el.remove();
						}
					}

					Behaviour.apply(); // refreshes ComplexTableField

					// focus input on first form element
					this.find(':input:visible:first').focus();

					this.trigger('loadnewpage', {data: data, origData: origData});
				}

				// set status message based on response
				var _statusMessage = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText;
				if(this.hasClass('validationerror')) {
					// TODO validation shouldnt need a special case
					statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
				} else {
					statusMessage(_statusMessage, (xmlhttp.status >= 400) ? 'bad' : 'good');
				}
			}
		};
	});

	/**
	 * @class All buttons in the right CMS form go through here by default.
	 * We need this onclick overloading because we can't get to the
	 * clicked button from a form.onsubmit event.
	 * @name ss.Form_EditForm.Actions.submit
	 */
	$('#Form_EditForm .Actions :submit').concrete('ss', function($){
		return/** @lends ss.Form_EditForm.Actions.submit */{
			onmatch: function() {
				var self = this;
				// TODO Fix once concrete library is updated
				this.bind('click', function(e) {return self.clickFake(e);});
			},
			clickFake: function(e) {
				$(this[0].form).concrete('ss').ajaxSubmit(this);
				return false;
			}
		};
	});
}(jQuery));<commit_msg>MINOR Syntax<commit_after>(function($) {

	/**
	 * @class Base edit form, provides ajaxified saving
	 * and reloading itself through the ajax return values.
	 * Takes care of resizing tabsets within the layout container.
	 * @name ss.Form_EditForm
	 */
	$('#Form_EditForm').concrete('ss',function($){
		return/** @lends ss.Form_EditForm */{

			/**
			 * @type String HTML text to show when the form has been deleted.
			 * @todo i18n
			 */
			RemoveText: 'Removed',

			onmatch: function() {
				// Don't bind any events here, as we dont replace the
				// full <form> tag by any ajax updates they won't automatically reapply

				_super();
			},

			/**
			 * Suppress submission unless it is handled through ajaxSubmit()
			 */
			onsubmit: function(e) {
				return false;
			},

			/**
			 * @param {DOMElement} button The pressed button (optional)
			 */
			ajaxSubmit: function(button) {
				// default to first button if none given - simulates browser behaviour
				if(!button) button = this.find(':submit:first');

				var self = this;

				this.trigger('ajaxsubmit', {button: button});

				// set button to "submitting" state
				$(button).addClass('loading');

				// @todo TinyMCE coupling
				if(typeof tinyMCE != 'undefined') tinyMCE.triggerSave();

				// validate if required
				if(!this.validate()) {
					// TODO Automatically switch to the tab/position of the first error
					statusMessage("Validation failed.", "bad");

					$(button).removeClass('loading');

					return false;
				}

				// get all data from the form
				var formData = this.serializeArray();
				// add button action
				formData.push({name: $(button).attr('name'), value:'1'});

				$.ajax({
					url: this.attr('action'),
					data: formData,
					type: 'POST',
					complete: function(xmlhttp, status) {
						$(button).removeClass('loading');
						// pass along original form data to enable old/new comparisons
						self._loadResponse(xmlhttp.responseText, status, xmlhttp, formData);
					},
					dataType: 'html'
				});

				return false;
			},

			/**
			 * Hook in (optional) validation routines.
			 * Currently clientside validation is not supported out of the box in the CMS.
			 *
			 * @todo Placeholder implementation
			 *
			 * @return {boolean}
			 */
			validate: function() {
				var isValid = true;
				this.trigger('validate', {isValid: isValid});

				return isValid;
			},

			/**
			 * @param String url
			 * @param Function callback (Optional)
			 */
			load: function(url, callback) {
				var self = this;
				$.ajax({
					url: url,
					complete: function(xmlhttp, status) {
						self._loadResponse(xmlhttp.responseText, status, xmlhttp);
						if(callback) callback.apply(self, arguments);
					},
					dataType: 'html'
				});
			},

			/**
			 * Remove everying inside the <form> tag
			 * with a custom HTML fragment. Useful e.g. for deleting a page in the CMS.
			 *
			 * @param {String} removeText Short note why the form has been removed, displayed in
 tags.
			 *  Falls back to the default RemoveText() option (Optional)
			 */
			removeForm: function(removeText) {
				if(!removeText) removeText = this.RemoveText();
				this.html('
' + removeText + '
');
			},

			/**
			 * Remove all the currently active TinyMCE editors.
			 * Note: Everything that calls this externally has an inappropriate coupling to TinyMCE.
			 */
			cleanup: function() {
				if((typeof tinymce != 'undefined') && tinymce.EditorManager) {
					var id;
					for(id in tinymce.EditorManager.editors) {
						tinymce.EditorManager.editors[id].remove();
					}
					tinymce.EditorManager.editors = {};
				}
			},

			/**
			 * @param {String} data Either HTML for straight insertion, or eval'ed JavaScript.
			 *  If passed as HTML, it is assumed that everying inside the <form> tag is replaced,
			 *  but the old <form> tag itself stays intact.
			 * @param {String} status
			 * @param {XMLHTTPRequest} xmlhttp
			 * @param {Array} origData The original submitted data, useful to do comparisons of changed
			 *  values in new form output, e.g. to detect a URLSegment being changed on the serverside.
			 *  Array in jQuery serializeArray() notation.
			 */
			_loadResponse: function(data, status, xmlhttp, origData) {
				if(status == 'success') {
					this.cleanup();

					var html = data;

					// Rewrite # links
					html = html.replace(/(]+href *= *")#/g, '$1' + window.location.href.replace(/#.*$/,'') + '#');

					// Rewrite iframe links (for IE)
					html = html.replace(/(]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');

					// Prepare iframes for removal, otherwise we get loading bugs
					this.find('iframe').each(function() {
						this.contentWindow.location.href = 'about:blank';
						this.remove();
					});

					// update form content
					if(html) {
						this.html(html);
					} else {
						this.removeForm();
					}

					// Optionally get the form attributes from embedded fields, see Form->formHtmlContent()
					for(var overrideAttr in {'action':true,'method':true,'enctype':true,'name':true}) {
						var el = this.find(':input[name='+ '_form_' + overrideAttr + ']');
						if(el) {
							this.attr(overrideAttr, el.val());
							el.remove();
						}
					}

					Behaviour.apply(); // refreshes ComplexTableField

					// focus input on first form element
					this.find(':input:visible:first').focus();

					this.trigger('loadnewpage', {data: data, origData: origData});
				}

				// set status message based on response
				var _statusMessage = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText;
				if(this.hasClass('validationerror')) {
					// TODO validation shouldnt need a special case
					statusMessage(ss.i18n._t('ModelAdmin.VALIDATIONERROR', 'Validation Error'), 'bad');
				} else {
					statusMessage(_statusMessage, (xmlhttp.status >= 400) ? 'bad' : 'good');
				}
			}
		};
	});

	/**
	 * @class All buttons in the right CMS form go through here by default.
	 * We need this onclick overloading because we can't get to the
	 * clicked button from a form.onsubmit event.
	 * @name ss.Form_EditForm.Actions.submit
	 */
	$('#Form_EditForm .Actions :submit').concrete('ss', function($){
		return/** @lends ss.Form_EditForm.Actions.submit */{
			onmatch: function() {
				var self = this;
				// TODO Fix once concrete library is updated
				this.bind('click', function(e) {return self.clickFake(e);});
			},
			clickFake: function(e) {
				$(this[0].form).concrete('ss').ajaxSubmit(this);
				return false;
			}
		};
	});
}(jQuery));<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Mixin.create({

    layoutName: 'sl-components/templates/modal',

    classNames: [ 'modal', 'fade' ],

    actions: {

        close: function() {

            if ( this.$() ) {
                this.$().modal( 'hide' );
            }
        }

    }

});<commit_msg>Changed path to support new export path<commit_after>import Ember from 'ember';

export default Ember.Mixin.create({

    layoutName: 'templates/modal',

    classNames: [ 'modal', 'fade' ],

    actions: {

        close: function() {

            if ( this.$() ) {
                this.$().modal( 'hide' );
            }
        }

    }

});<|endoftext|>


<commit_before>/* global $ */

$(document).ready(function () {
  $('#delete-roommate').click(deleteRoommate)
})

const deleteRoommate = function () {
  if (confirm('Delete this roommate request?')) {
    const roommateId = $(this).data('id')
    $.ajax({
      url: './properties/Roommate/' + roommateId,
      dataType: 'json',
      type: 'delete',
      success: function () {
        window.location.href('properties/Roommate/list')
      }.bind(this),
      error: function () {}.bind(this),
    })
  }
}
<commit_msg>Fixed href route<commit_after>/* global $ */

$(document).ready(function () {
  $('#delete-roommate').click(deleteRoommate)
})

const deleteRoommate = function () {
  if (confirm('Delete this roommate request?')) {
    const roommateId = $(this).data('id')
    $.ajax({
      url: './properties/Roommate/' + roommateId,
      dataType: 'json',
      type: 'delete',
      success: function () {
        window.location.href = 'properties/Roommate/list'
      }.bind(this),
      error: function () {}.bind(this),
    })
  }
}
<|endoftext|>


<commit_before>// Array Methods

// Joining multiple arrays

var zero = 0;
var positiveNumbers = [1,2,3];
var negativeNumbers = [-3,-2,-1];

var numbers = negativeNumbers.concat(zero, positiveNumbers);
console.log(numbers);

/* You can pass as many arrays and objects/elements to this array as you want
the arrays will be concatenated to the specified array in the order that the
arguments are passed to the method. In the above example, zero is concatenated
to the array negativeNumbers, and then the array positiveNumbers is concatenated
to the newly formed array.
*/

// Iterator functions

var isEven = function(x){
  console.log(x);
  return (x % 2 == 0) ? true : false;
  // can also be simplified to return (x % 2 == 0)
};

var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

/* first method we'll look at is the every method, which will iterate each
element of the array until the return of the function is false
*/

numbers.every(isEven);

/* Next we have the some method...it has the same behavior as the every method
but wit will iterate each element of the array until the return of the function
is true
*/

numbers.some(isEven);

/* If we need the array to be completely iterated we can use the forEach function
which has the same result as a for loop with the function's code inside
*/

numbers.forEach(function(x){
  console.log((x % 2 === 0));
});

/* javascript has two other iterator methods that return a new array with a
 result...the first one being the map method
*/

var myMap = numbers.map(isEven);
console.log(myMap);

/* the new array stores the result of the isEven function that was passed to
the map method
*/

/* the filter method returns a new array with the element that the function
returns as true
*/

var evenNumbers = numbers.filter(isEven);
console.log(evenNumbers);
console.log(numbers);

// Searching and sorting

// lets take our numbers array and put the elements out of order

numbers.reverse();
console.log(numbers);

numbers.sort();
console.log(numbers);

/* so that didn't work...the sort method sorts lexicographically and assumes
all elements are strings

we can also write our own comparison function and plug it into the sort method
*/

numbers.sort(function(a, b){
  return a - b;
});
console.log(numbers);

/* this comparison function will return a negative number if b is greater than
a, a positive number if a is greater than b, and zero if they are equal...if
a negative value is returned it implies that a is smaller than b, which is
further used by the sort function to arrange the elements
*/

// The comparison function could also look like this:

function compare(a, b){
  if(a < b){
    return -1;
  }
  if(a > b){
    return 1;
  }
  return 0;
}

numbers.reverse();
numbers.sort(compare);
console.log(numbers);

// Custom sorting

/* we can sort an array with any type of objecvt in it, and we can also
create a comparison function to compare the elements as we need to */

var friends = [
  {name: 'John', age: 30},
  {name: 'Ana', age: 20},
  {name: 'Chris', age: 25}
];

function comparePerson(a,b){
  if (a.age < b.age){
    return -1;
  }
  if (a.age > b.age){
    return 1;
  }
  return 0;
}

console.log(friends.sort(comparePerson));

// sorting strings

var names = ['Ana', 'ana', 'john', 'John'];
console.log(names.sort());

// write a comparison function that ignores the cases

names.sort(function(a,b){
  if(a.toLowerCase() < b.toLowerCase()){
    return -1;
  }
  if(a.toLowerCase() > b.toLowerCase()){
    return 1;
  }
  return 0;
});

console.log(names);
<commit_msg>review searching with indexOf and lastIndexOf, output array into a string w/ toString and join methods<commit_after>// Array Methods

// Joining multiple arrays

var zero = 0;
var positiveNumbers = [1,2,3];
var negativeNumbers = [-3,-2,-1];

var numbers = negativeNumbers.concat(zero, positiveNumbers);
console.log(numbers);

/* You can pass as many arrays and objects/elements to this array as you want
the arrays will be concatenated to the specified array in the order that the
arguments are passed to the method. In the above example, zero is concatenated
to the array negativeNumbers, and then the array positiveNumbers is concatenated
to the newly formed array.
*/

// Iterator functions

var isEven = function(x){
  console.log(x);
  return (x % 2 == 0) ? true : false;
  // can also be simplified to return (x % 2 == 0)
};

var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

/* first method we'll look at is the every method, which will iterate each
element of the array until the return of the function is false
*/

numbers.every(isEven);

/* Next we have the some method...it has the same behavior as the every method
but wit will iterate each element of the array until the return of the function
is true
*/

numbers.some(isEven);

/* If we need the array to be completely iterated we can use the forEach function
which has the same result as a for loop with the function's code inside
*/

numbers.forEach(function(x){
  console.log((x % 2 === 0));
});

/* javascript has two other iterator methods that return a new array with a
 result...the first one being the map method
*/

var myMap = numbers.map(isEven);
console.log(myMap);

/* the new array stores the result of the isEven function that was passed to
the map method
*/

/* the filter method returns a new array with the element that the function
returns as true
*/

var evenNumbers = numbers.filter(isEven);
console.log(evenNumbers);
console.log(numbers);

// Searching and sorting

// lets take our numbers array and put the elements out of order

numbers.reverse();
console.log(numbers);

numbers.sort();
console.log(numbers);

/* so that didn't work...the sort method sorts lexicographically and assumes
all elements are strings

we can also write our own comparison function and plug it into the sort method
*/

numbers.sort(function(a, b){
  return a - b;
});
console.log(numbers);

/* this comparison function will return a negative number if b is greater than
a, a positive number if a is greater than b, and zero if they are equal...if
a negative value is returned it implies that a is smaller than b, which is
further used by the sort function to arrange the elements
*/

// The comparison function could also look like this:

function compare(a, b){
  if(a < b){
    return -1;
  }
  if(a > b){
    return 1;
  }
  return 0;
}

numbers.reverse();
numbers.sort(compare);
console.log(numbers);

// Custom sorting

/* we can sort an array with any type of objecvt in it, and we can also
create a comparison function to compare the elements as we need to */

var friends = [
  {name: 'John', age: 30},
  {name: 'Ana', age: 20},
  {name: 'Chris', age: 25}
];

function comparePerson(a,b){
  if (a.age < b.age){
    return -1;
  }
  if (a.age > b.age){
    return 1;
  }
  return 0;
}

console.log(friends.sort(comparePerson));

// sorting strings

var names = ['Ana', 'ana', 'john', 'John'];
console.log(names.sort());

// write a comparison function that ignores the cases

names.sort(function(a,b){
  if(a.toLowerCase() < b.toLowerCase()){
    return -1;
  }
  if(a.toLowerCase() > b.toLowerCase()){
    return 1;
  }
  return 0;
});

console.log(names);

// Searching

/* Two options for searching: the indexOf method, which returns the index of
the first element that matches the argument passed, and lastIndex which returns
the index of the last element found that matches the argument passed
*/

console.log(numbers);
console.log(numbers.indexOf(10));
console.log(numbers.indexOf(100));

// Outputting the array into a string

console.log(numbers.toString());

/* If you would like to separate the elements with a different separator you
can use the join method
*/

var numbersString = numbers.join('-');
console.log(numbersString);
<|endoftext|>


<commit_before>import { App } from '../../src/app';

describe('the app', () => {
  it('should have an array with failed builds retrieved from the buildservice by initialization', (done) => {
    let failedBuildsPromise = Promise.resolve(['a', 'b', 'c']);
    let buildServiceStub = { getAllFailedBuilds: (done) => failedBuildsPromise }
    let app = new App(buildServiceStub);
    expectAtEndOfEventLoop(() => expect(app.builds).toEqual(['a', 'b', 'c']))

    function expectAtEndOfEventLoop(expectFunction) {
      setTimeout(() => {
        expectFunction();
        done();
      }, 0);
    }
  });
});

<commit_msg>small refactoring<commit_after>import { App } from '../../src/app';

describe('the app', () => {
  it('should have an array with failed builds retrieved from the buildservice by initialization', (done) => {
    let buildServiceStub = { getAllFailedBuilds: (done) => Promise.resolve(['a', 'b', 'c']) }
    let app = new App(buildServiceStub);
    expectAtEndOfEventLoop(() => expect(app.builds).toEqual(['a', 'b', 'c']))

    function expectAtEndOfEventLoop(expectFunction) {
      setTimeout(() => {
        expectFunction();
        done();
      }, 0);
    }
  });
});

<|endoftext|>