<commit_before>var vec2 = require('../math/vec2')
var Body = require('../objects/Body')

module.exports = Broadphase;

/**
 * Base class for broadphase implementations.
 * @class Broadphase
 * @constructor
 */
function Broadphase(type){

    this.type = type;

    /**
     * The resulting overlapping pairs. Will be filled with results during .getCollisionPairs().
     * @property result
     * @type {Array}
     */
    this.result = [];

    /**
     * The world to search for collision pairs in. To change it, use .setWorld()
     * @property world
     * @type {World}
     * @readOnly
     */
    this.world = null;

    /**
     * The bounding volume type to use in the broadphase algorithms.
     * @property {Number} boundingVolumeType
     */
    this.boundingVolumeType = Broadphase.AABB;
}

/**
 * Axis aligned bounding box type.
 * @static
 * @property {Number} AABB
 */
Broadphase.AABB = 1;

/**
 * Bounding circle type.
 * @static
 * @property {Number} BOUNDING_CIRCLE
 */
Broadphase.BOUNDING_CIRCLE = 2;

/**
 * Set the world that we are searching for collision pairs in
 * @method setWorld
 * @param  {World} world
 */
Broadphase.prototype.setWorld = function(world){
    this.world = world;
};

/**
 * Get all potential intersecting body pairs.
 * @method getCollisionPairs
 * @param  {World} world The world to search in.
 * @return {Array} An array of the bodies, ordered in pairs. Example: A result of [a,b,c,d] means that the potential pairs are: (a,b), (c,d).
 */
Broadphase.prototype.getCollisionPairs = function(world){
    throw new Error("getCollisionPairs must be implemented in a subclass!");
};

var dist = vec2.create();

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.boundingRadiusCheck = function(bodyA, bodyB){
    vec2.sub(dist, bodyA.position, bodyB.position);
    var d2 = vec2.squaredLength(dist),
        r = bodyA.boundingRadius + bodyB.boundingRadius;
    return d2 <= r*r;
};

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.aabbCheck = function(bodyA, bodyB){
    if(bodyA.aabbNeedsUpdate) bodyA.updateAABB();
    if(bodyB.aabbNeedsUpdate) bodyB.updateAABB();
    return bodyA.aabb.overlaps(bodyB.aabb);
};

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.prototype.boundingVolumeCheck = function(bodyA, bodyB){
    var result;

    switch(this.boundingVolumeType){
    case Broadphase.BOUNDING_CIRCLE:
        result =  Broadphase.boundingRadiusCheck(bodyA,bodyB);
        break;
    case Broadphase.AABB:
        result = Broadphase.aabbCheck(bodyA,bodyB);
        break;
    default:
        throw new Error('Bounding volume type not recognized: '+this.boundingVolumeType);
    }
    return result;
};

/**
 * Check whether two bodies are allowed to collide at all.
 * @method  canCollide
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.canCollide = function(bodyA, bodyB){

    // Cannot collide static bodies
    if(bodyA.motionState == Body.STATIC && bodyB.motionState == Body.STATIC)
        return false;

    // Cannot collide static vs kinematic bodies
    if( (bodyA.motionState == Body.KINEMATIC && bodyB.motionState == Body.STATIC) ||
        (bodyA.motionState == Body.STATIC    && bodyB.motionState == Body.KINEMATIC))
        return false;

    // Cannot collide kinematic vs kinematic
    if(bodyA.motionState == Body.KINEMATIC && bodyB.motionState == Body.KINEMATIC)
        return false;

    // Cannot collide both sleeping bodies
    if(bodyA.sleepState == Body.SLEEPING && bodyB.sleepState == Body.SLEEPING)
        return false;

    // Cannot collide if one is static and the other is sleeping
    if( (bodyA.sleepState == Body.SLEEPING && bodyB.motionState == Body.STATIC) ||
        (bodyB.sleepState == Body.SLEEPING && bodyA.motionState == Body.STATIC)){
        return false;
    }

    return true;
};

Broadphase.NAIVE = 1;
Broadphase.SAP = 2;
<commit_msg>cleaner code<commit_after>var vec2 = require('../math/vec2')
var Body = require('../objects/Body')

module.exports = Broadphase;

/**
 * Base class for broadphase implementations.
 * @class Broadphase
 * @constructor
 */
function Broadphase(type){

    this.type = type;

    /**
     * The resulting overlapping pairs. Will be filled with results during .getCollisionPairs().
     * @property result
     * @type {Array}
     */
    this.result = [];

    /**
     * The world to search for collision pairs in. To change it, use .setWorld()
     * @property world
     * @type {World}
     * @readOnly
     */
    this.world = null;

    /**
     * The bounding volume type to use in the broadphase algorithms.
     * @property {Number} boundingVolumeType
     */
    this.boundingVolumeType = Broadphase.AABB;
}

/**
 * Axis aligned bounding box type.
 * @static
 * @property {Number} AABB
 */
Broadphase.AABB = 1;

/**
 * Bounding circle type.
 * @static
 * @property {Number} BOUNDING_CIRCLE
 */
Broadphase.BOUNDING_CIRCLE = 2;

/**
 * Set the world that we are searching for collision pairs in
 * @method setWorld
 * @param  {World} world
 */
Broadphase.prototype.setWorld = function(world){
    this.world = world;
};

/**
 * Get all potential intersecting body pairs.
 * @method getCollisionPairs
 * @param  {World} world The world to search in.
 * @return {Array} An array of the bodies, ordered in pairs. Example: A result of [a,b,c,d] means that the potential pairs are: (a,b), (c,d).
 */
Broadphase.prototype.getCollisionPairs = function(world){
    throw new Error("getCollisionPairs must be implemented in a subclass!");
};

var dist = vec2.create();

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.boundingRadiusCheck = function(bodyA, bodyB){
    vec2.sub(dist, bodyA.position, bodyB.position);
    var d2 = vec2.squaredLength(dist),
        r = bodyA.boundingRadius + bodyB.boundingRadius;
    return d2 <= r*r;
};

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.aabbCheck = function(bodyA, bodyB){
    if(bodyA.aabbNeedsUpdate){
        bodyA.updateAABB();
    }
    if(bodyB.aabbNeedsUpdate){
        bodyB.updateAABB();
    }
    return bodyA.aabb.overlaps(bodyB.aabb);
};

/**
 * Check whether the bounding radius of two bodies overlap.
 * @method  boundingRadiusCheck
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.prototype.boundingVolumeCheck = function(bodyA, bodyB){
    var result;

    switch(this.boundingVolumeType){
    case Broadphase.BOUNDING_CIRCLE:
        result =  Broadphase.boundingRadiusCheck(bodyA,bodyB);
        break;
    case Broadphase.AABB:
        result = Broadphase.aabbCheck(bodyA,bodyB);
        break;
    default:
        throw new Error('Bounding volume type not recognized: '+this.boundingVolumeType);
    }
    return result;
};

/**
 * Check whether two bodies are allowed to collide at all.
 * @method  canCollide
 * @param  {Body} bodyA
 * @param  {Body} bodyB
 * @return {Boolean}
 */
Broadphase.canCollide = function(bodyA, bodyB){

    // Cannot collide static bodies
    if(bodyA.motionState === Body.STATIC && bodyB.motionState === Body.STATIC){
        return false;
    }

    // Cannot collide static vs kinematic bodies
    if( (bodyA.motionState === Body.KINEMATIC && bodyB.motionState === Body.STATIC) ||
        (bodyA.motionState === Body.STATIC    && bodyB.motionState === Body.KINEMATIC)){
        return false;
    }

    // Cannot collide kinematic vs kinematic
    if(bodyA.motionState === Body.KINEMATIC && bodyB.motionState === Body.KINEMATIC){
        return false;
    }

    // Cannot collide both sleeping bodies
    if(bodyA.sleepState === Body.SLEEPING && bodyB.sleepState === Body.SLEEPING){
        return false;
    }

    // Cannot collide if one is static and the other is sleeping
    if( (bodyA.sleepState === Body.SLEEPING && bodyB.motionState === Body.STATIC) ||
        (bodyB.sleepState === Body.SLEEPING && bodyA.motionState === Body.STATIC)){
        return false;
    }

    return true;
};

Broadphase.NAIVE = 1;
Broadphase.SAP = 2;
<|endoftext|>


<commit_before>// Copyright (c) 2011, Centrum Cyfrowe
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Centrum Cyfrowe nor the names of its contributors
//     may be used to endorse or promote products derived from this software
//     without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var _algorithms = (function () {
    var that = {};

//  P U B L I C   I N T E R F A C E

    // sorts part of an array data with a hybrid sorting algorithm
    // which uses merge sort for dividing big part of an array and mergin them
    // and bubble sort for sorting small arrays. Uses setting sorting_setting.
    that.sort = function ( data, sorting_setting, start, end, border ) {
        var start = start || 0;
        var end = end || data.length - 1;
        var border = border || 2;
        var middle;

        // an array is small enough to use bubble sort
        if ( start > end - border )
            bubble_sort( data, sorting_setting, start, end);
        else {
            middle = get_middle( start, end );

            // sort two arrays separately
            that.sort( data, sorting_setting, start, middle, border );
            that.sort( data, sorting_setting, middle + 1, end, border );

            // merge sorted arrays
            merge( data, sorting_setting, start, middle, end);
        }
    };

    // filters collection
    that.filter = function ( data, filter_mask ) {
        var i;
        var result = [ ];
        var passed_filter_object = {};

        prepare_mask( filter_mask );

        // for each element in collection
        for ( i = 0; i < data.length; i += 1 ) {
            // checks if the object passes through the filter
            if ( check_obj( data[i]['data'], filter_mask ) ) {
                $.extend( true, passed_filter_object, data[ i ] );
                result.push( passed_filter_object );
                passed_filter_object = {};
            }
        }
        return result;
    };

    that.prepare_sorting_setting = function( sorting_setting, key ) {
        var hidden_attribute = {
            "pref": -1,
            "name": key
        };

        sorting_setting.push( hidden_attribute );
    };

//  P R I V A T E   I N T E R F A C E

//   S O R T I N G   H E L P E R   F U N C T I O N S

    // sorts data in range [start; end] with bubble_sort algorithm
    // with setting sorting_setting, which decides when an object is bigger than another
    var bubble_sort = function( data, sorting_setting, start, end ) {
        var start = start || 0;
        var end = end || data.length - 1;

        var i;
        var j;
        var sorted;

        for ( i = start, sorted = 0; i < end; i += 1, sorted += 1 ) {
            for ( j = start; j < end - sorted; j += 1 ) {
                if ( compare_obj( data[j]['data'], data[j+1]['data'], sorting_setting ) == -1 ) {
                    swap( data, j, j+1 );
                }
            }
        }
    };

    // sorts part of an array data with merge sort algorithm using setting sett
    var merge_sort = function( data, sorting_setting, start, end ) {
        var start = start || 0;
        var end = end || data.lenght - 1;
        var middle;

        if ( start > end - 1 ) {
            return;
        }

        middle = get_middle( start, end );

        // sort two arrays separately
        merge_sort( data, sorting_setting, start, middle );
        merge_sort( data, sorting_setting, middle + 1, end );

        // merge sorted arrays
        merge( data, sorting_setting, start, middle, end);
    };

    // merges two subarrays, 1st: data[start, middle], 2nd: data[middle+1, end]
    // result is that data[start, end] is sorted
    var merge = function( data, sorting_setting, start, middle, end ) {
        var i = 0;
        var j = 0;
        var ind = start;

        var subarray1 = data.slice(start, middle + 1);
        var subarray2 = data.slice(middle + 1, end + 1);

        // put the smallest actually element in the first available place in data
        while ( i < subarray1.length && j < subarray2.length ) {

            if ( compare_obj( subarray1[i]['data'], subarray2[j]['data'], sorting_setting ) == 1 ) {
                data[ind] = subarray1[i];
                i += 1;
            } else {
                data[ind] = subarray2[j];
                j += 1;
            }
            ind += 1;
        }

        if ( i < subarray1.length ) {
            // put last elements from subarray1 in the last spots in data
            while ( i < subarray1.length ) {
                data[ind] = subarray1[i];
                ind += 1;
                i += 1;
            }
        } else {
            // put last elements from subarray2 in the last spots in data
            while ( j < subarray2.length ) {
                data[ind] = subarray2[j];
                ind += 1;
                j += 1;
            }
        }
    };

    // changes elements in array
    var swap = function( data, i, j) {
        var tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    };

    // gets middle point between start and end
     var get_middle = function( start, end ) {
        var length = start + end;
        var rest = length % 2;
        var temp = length - rest;

        return ( temp / 2 );
    }

    // compares values of specified attribute of two objects, returned value depends on preference
    var compare_atr = function( ob1, ob2, attr, pref ) {
        var compare_value;
        var alphabet;

        if ( typeof ob1[attr] === "number" ) {
            if ( ob1[attr] < ob2[attr] ) {
                compare_value = -1;
            } else if ( ob1[attr] > ob2[attr] ) {
                compare_value = 1;
            } else {
                return 0;
            }
        } else {
            alphabet = "0123456789a\u0105bc\u0107de\u0119fghijkl\u0142mn\u0144o\u00f3pqrs\u015btuvwxyz\u017a\u017c";
            return alpha( alphabet, pref, false )( ob1[ attr ], ob2[ attr ] );
        }

        // changes value to return basing on value of pref
        return compare_value * pref;
    }

    // alpha is slighlty modified function from
    // http://stackoverflow.com/questions/3630645/how-to-compare-utf-8-strings-in-javascript/3633725#3633725
    // written by Mic and Tomasz Wysocki
    var alpha = function( alphabet, dir, case_sensitive ) {
        dir = dir || 1;
        function compare_letters( a, b ) {
            var ia = alphabet.indexOf( a );
            var ib = alphabet.indexOf( b );
            if ( ia === -1 || ib === -1 ) {
                if ( ib !== -1 )
                    return a > 'a';
                if ( ia !== -1 )
                    return 'a' > b;
                return a > b;
            }
            return ia > ib;
        }

        return function( a, b ) {
            var pos = 0;
            var min = Math.min( a.length, b.length );
            case_sensitive = case_sensitive || false;
            if ( !case_sensitive ) {
                a = a.toLowerCase();
                b = b.toLowerCase();
            }
            while( a.charAt( pos ) === b.charAt( pos ) && pos < min ) {
                pos++;
            }

            return compare_letters( a.charAt(pos), b.charAt(pos)) ? dir : -dir;
        };
    };

    // compares two objects, compares their attributes mentioned in sorting_setting
    var compare_obj = function( ob1, ob2, sorting_setting ) {
        var i;
        var result = 0;
        var key;
        var pref;

        // for each attribute in sorting_setting
        for ( i = 0; i < sorting_setting.length; i += 1 ) {
            key = sorting_setting[i].name;
            pref = sorting_setting[i].pref;

            if ( i !== sorting_setting.length - 1 ) {
                result = compare_atr( ob1, ob2, key, pref );
            } else {
                result = id_comparison( ob1, ob2, sorting_setting );
            }

            if ( result !== 0 ) {
                break;
            }
        }

        return result;
    };

    var id_comparison = function( ob1, ob2, sorting_setting ) {
        var key;
        var pref;
        var sett_length = sorting_setting.length;
        var id1_tokenized;
        var id2_tokenized;
        var min_length;
        var i;
        var result;
        var token_to_int1;
        var token_to_int2;

        key = sorting_setting[ sett_length - 1 ].name;
        pref = sorting_setting[ sett_length - 1 ].pref;

        id1_tokenized = ob1[key].split("-");
        id2_tokenized = ob2[key].split("-");

        min_length = (id1_tokenized.length < id2_tokenized.length) ?
                            id1_tokenized.length : id2_tokenized.length;

        result = 1;
        for ( i = 0; i < min_length; i += 1 ) {
            token_to_int1 = parseInt( id1_tokenized[i] );
            token_to_int2 = parseInt( id2_tokenized[i] );

            if ( token_to_int1 < token_to_int2 ) {
                result = -1;
            } else if ( token_to_int1 > token_to_int2 ) {
                result = 1;
            }
        }

        return result * pref;
    }

//   F I L T E R I N G   H E L P E R   F U N C T I O N S

    // looks for every criterion that is string value and
    // changes it to lower case
    var prepare_mask = function( mask ) {
        var i;
        var value;
        var type;

        for ( i = 0; i < mask.length; i += 1 ) {
            type = typeof mask[ i ];
            if ( type === "string" ) {
                value = mask[ i ].value;
                mask[ i ].value = value.toLowerCase();
            }
        }
    };

    // checks if an object passes through a filter
    var check_obj = function( obj, filter_mask ) {
        var i;
        var key;
        var pref;
        var value;

        // for each attribute of an object which is also in filter_mask
        for ( i = 0; i < filter_mask.length; i += 1 ) {
            key = filter_mask[i].name;
            pref = filter_mask[i].pref;
            value = filter_mask[i].value;
            // one of attributes does not pass through a filter
            if ( !check_attr( obj, key, pref, value ) ) {
                return false;
            }
        }
        return true;
    };

    // checks if specfied attribute of an object passes a filter
    var check_attr = function( obj, attr, pref, value ) {
        var obj_val = obj[attr];
        var type = typeof obj_val;

        if ( type === "number" ) {
            if ( pref === 'lt' && obj_val < value) {
                return true;
            } else if ( pref === 'gt' && obj_val > value ) {
                return true;
            } else if ( pref === 'eq' && obj_val === value ) {
                return true;
            }
        } else {
            // is string
            var str = obj[attr].toLowerCase();

            if ( pref === 'nst' && !starts_with( str, value ) ||
                 pref === 'ncnt' && !contains( str, value ) ||
                 pref === 'cnt' && contains( str, value ) ||
                 pref === 'st' && starts_with( str, value ) ) {
                 return true;
            } else {
                return false;
            }
        }

        return false;
    };

    var starts_with = function( str, value ) {
        return ( str.indexOf( value ) === 0 );
    };

    var contains = function( str, value ) {
        return ( str.indexOf( value ) !== -1 );
    };

    return that;
})();
<commit_msg>Case insensivity added to filter<commit_after>// Copyright (c) 2011, Centrum Cyfrowe
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Centrum Cyfrowe nor the names of its contributors
//     may be used to endorse or promote products derived from this software
//     without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var _algorithms = (function () {
    var that = {};

//  P U B L I C   I N T E R F A C E

    // sorts part of an array data with a hybrid sorting algorithm
    // which uses merge sort for dividing big part of an array and mergin them
    // and bubble sort for sorting small arrays. Uses setting sorting_setting.
    that.sort = function ( data, sorting_setting, start, end, border ) {
        var start = start || 0;
        var end = end || data.length - 1;
        var border = border || 2;
        var middle;

        // an array is small enough to use bubble sort
        if ( start > end - border )
            bubble_sort( data, sorting_setting, start, end);
        else {
            middle = get_middle( start, end );

            // sort two arrays separately
            that.sort( data, sorting_setting, start, middle, border );
            that.sort( data, sorting_setting, middle + 1, end, border );

            // merge sorted arrays
            merge( data, sorting_setting, start, middle, end);
        }
    };

    // filters collection
    that.filter = function ( data, filter_mask ) {
        var i;
        var result = [ ];
        var passed_filter_object = {};

        prepare_mask( filter_mask );

        // for each element in collection
        for ( i = 0; i < data.length; i += 1 ) {
            // checks if the object passes through the filter
            if ( check_obj( data[i]['data'], filter_mask ) ) {
                $.extend( true, passed_filter_object, data[ i ] );
                result.push( passed_filter_object );
                passed_filter_object = {};
            }
        }
        return result;
    };

    that.prepare_sorting_setting = function( sorting_setting, key ) {
        var hidden_attribute = {
            "pref": -1,
            "name": key
        };

        sorting_setting.push( hidden_attribute );
    };

//  P R I V A T E   I N T E R F A C E

//   S O R T I N G   H E L P E R   F U N C T I O N S

    // sorts data in range [start; end] with bubble_sort algorithm
    // with setting sorting_setting, which decides when an object is bigger than another
    var bubble_sort = function( data, sorting_setting, start, end ) {
        var start = start || 0;
        var end = end || data.length - 1;

        var i;
        var j;
        var sorted;

        for ( i = start, sorted = 0; i < end; i += 1, sorted += 1 ) {
            for ( j = start; j < end - sorted; j += 1 ) {
                if ( compare_obj( data[j]['data'], data[j+1]['data'], sorting_setting ) == -1 ) {
                    swap( data, j, j+1 );
                }
            }
        }
    };

    // sorts part of an array data with merge sort algorithm using setting sett
    var merge_sort = function( data, sorting_setting, start, end ) {
        var start = start || 0;
        var end = end || data.lenght - 1;
        var middle;

        if ( start > end - 1 ) {
            return;
        }

        middle = get_middle( start, end );

        // sort two arrays separately
        merge_sort( data, sorting_setting, start, middle );
        merge_sort( data, sorting_setting, middle + 1, end );

        // merge sorted arrays
        merge( data, sorting_setting, start, middle, end);
    };

    // merges two subarrays, 1st: data[start, middle], 2nd: data[middle+1, end]
    // result is that data[start, end] is sorted
    var merge = function( data, sorting_setting, start, middle, end ) {
        var i = 0;
        var j = 0;
        var ind = start;

        var subarray1 = data.slice(start, middle + 1);
        var subarray2 = data.slice(middle + 1, end + 1);

        // put the smallest actually element in the first available place in data
        while ( i < subarray1.length && j < subarray2.length ) {

            if ( compare_obj( subarray1[i]['data'], subarray2[j]['data'], sorting_setting ) == 1 ) {
                data[ind] = subarray1[i];
                i += 1;
            } else {
                data[ind] = subarray2[j];
                j += 1;
            }
            ind += 1;
        }

        if ( i < subarray1.length ) {
            // put last elements from subarray1 in the last spots in data
            while ( i < subarray1.length ) {
                data[ind] = subarray1[i];
                ind += 1;
                i += 1;
            }
        } else {
            // put last elements from subarray2 in the last spots in data
            while ( j < subarray2.length ) {
                data[ind] = subarray2[j];
                ind += 1;
                j += 1;
            }
        }
    };

    // changes elements in array
    var swap = function( data, i, j) {
        var tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    };

    // gets middle point between start and end
     var get_middle = function( start, end ) {
        var length = start + end;
        var rest = length % 2;
        var temp = length - rest;

        return ( temp / 2 );
    }

    // compares values of specified attribute of two objects, returned value depends on preference
    var compare_atr = function( ob1, ob2, attr, pref ) {
        var compare_value;
        var alphabet;

        if ( typeof ob1[attr] === "number" ) {
            if ( ob1[attr] < ob2[attr] ) {
                compare_value = -1;
            } else if ( ob1[attr] > ob2[attr] ) {
                compare_value = 1;
            } else {
                return 0;
            }
        } else {
            alphabet = "0123456789a\u0105bc\u0107de\u0119fghijkl\u0142mn\u0144o\u00f3pqrs\u015btuvwxyz\u017a\u017c";
            return alpha( alphabet, pref, false )( ob1[ attr ], ob2[ attr ] );
        }

        // changes value to return basing on value of pref
        return compare_value * pref;
    }

    // alpha is slighlty modified function from
    // http://stackoverflow.com/questions/3630645/how-to-compare-utf-8-strings-in-javascript/3633725#3633725
    // written by Mic and Tomasz Wysocki
    var alpha = function( alphabet, dir, case_sensitive ) {
        dir = dir || 1;
        function compare_letters( a, b ) {
            var ia = alphabet.indexOf( a );
            var ib = alphabet.indexOf( b );
            if ( ia === -1 || ib === -1 ) {
                if ( ib !== -1 )
                    return a > 'a';
                if ( ia !== -1 )
                    return 'a' > b;
                return a > b;
            }
            return ia > ib;
        }

        return function( a, b ) {
            var pos = 0;
            var min = Math.min( a.length, b.length );
            case_sensitive = case_sensitive || false;
            if ( !case_sensitive ) {
                a = a.toLowerCase();
                b = b.toLowerCase();
            }
            while( a.charAt( pos ) === b.charAt( pos ) && pos < min ) {
                pos++;
            }

            return compare_letters( a.charAt(pos), b.charAt(pos)) ? dir : -dir;
        };
    };

    // compares two objects, compares their attributes mentioned in sorting_setting
    var compare_obj = function( ob1, ob2, sorting_setting ) {
        var i;
        var result = 0;
        var key;
        var pref;

        // for each attribute in sorting_setting
        for ( i = 0; i < sorting_setting.length; i += 1 ) {
            key = sorting_setting[i].name;
            pref = sorting_setting[i].pref;

            if ( i !== sorting_setting.length - 1 ) {
                result = compare_atr( ob1, ob2, key, pref );
            } else {
                result = id_comparison( ob1, ob2, sorting_setting );
            }

            if ( result !== 0 ) {
                break;
            }
        }

        return result;
    };

    var id_comparison = function( ob1, ob2, sorting_setting ) {
        var key;
        var pref;
        var sett_length = sorting_setting.length;
        var id1_tokenized;
        var id2_tokenized;
        var min_length;
        var i;
        var result;
        var token_to_int1;
        var token_to_int2;

        key = sorting_setting[ sett_length - 1 ].name;
        pref = sorting_setting[ sett_length - 1 ].pref;

        id1_tokenized = ob1[key].split("-");
        id2_tokenized = ob2[key].split("-");

        min_length = (id1_tokenized.length < id2_tokenized.length) ?
                            id1_tokenized.length : id2_tokenized.length;

        result = 1;
        for ( i = 0; i < min_length; i += 1 ) {
            token_to_int1 = parseInt( id1_tokenized[i] );
            token_to_int2 = parseInt( id2_tokenized[i] );

            if ( token_to_int1 < token_to_int2 ) {
                result = -1;
            } else if ( token_to_int1 > token_to_int2 ) {
                result = 1;
            }
        }

        return result * pref;
    }

//   F I L T E R I N G   H E L P E R   F U N C T I O N S

    // looks for every criterion that is string value and
    // changes it to lower case
    var prepare_mask = function( mask ) {
        var i;
        var value;
        var type;

        for ( i = 0; i < mask.length; i += 1 ) {
            type = typeof mask[ i ];
            if ( type === "string" ) {
                value = mask[ i ].value;
                mask[ i ].value = value.toLowerCase();
            }
        }
    };

    // checks if an object passes through a filter
    var check_obj = function( obj, filter_mask ) {
        var i;
        var key;
        var pref;
        var value;

        // for each attribute of an object which is also in filter_mask
        for ( i = 0; i < filter_mask.length; i += 1 ) {
            key = filter_mask[i].name;
            pref = filter_mask[i].pref;
            value = filter_mask[i].value;
            // one of attributes does not pass through a filter
            if ( !check_attr( obj, key, pref, value ) ) {
                return false;
            }
        }
        return true;
    };

    // checks if specfied attribute of an object passes a filter
    var check_attr = function( obj, attr, pref, value ) {
        var obj_val = obj[attr];
        var type = typeof obj_val;
        var str = obj_val.toLowerCase()
        var value = value.toLowerCase();

        if ( type === "number" ) {
            if ( pref === 'lt' && obj_val < value) {
                return true;
            } else if ( pref === 'gt' && obj_val > value ) {
                return true;
            } else if ( pref === 'eq' && obj_val === value ) {
                return true;
            }
        } else {
            // is string

            if ( pref === 'nst' && !starts_with( str, value ) ||
                 pref === 'ncnt' && !contains( str, value ) ||
                 pref === 'cnt' && contains( str, value ) ||
                 pref === 'st' && starts_with( str, value ) ) {
                 return true;
            } else {
                return false;
            }
        }

        return false;
    };

    var starts_with = function( str, value ) {
        return ( str.indexOf( value ) === 0 );
    };

    var contains = function( str, value ) {
        return ( str.indexOf( value ) !== -1 );
    };

    return that;
})();
<|endoftext|>


<commit_before>
var commandListEN = [
  // Motion commands. Can be used alone, or used with operator.
  { type:'motion', commands:[
    { keys:['h'],       help:'to left' },
    { keys:['j'],       help:'to down' },
    { keys:['k'],       help:'to up' },
    { keys:['l'],       help:'to right' },
    { keys:['<Left>'],  help:'to left' },
    { keys:['<Down>'],  help:'to down' },
    { keys:['<Up>'],    help:'to up' },
    { keys:['<Right>'], help:'to right' },

    { keys:['w'],       help:'a word' },
    { keys:['b'],       help:'a word backward' },

    { keys:['0'],       help:'to start of line' },
    { keys:['$'],       help:'to end of line' },

    { keys:['g','g'],   help:'to start of file' },
  ]},
  // Operator commands. Always used with either (i) motion,
  // (ii) a modifier + text-object (iii) itself, meaning linewise operation.
  { type:'operator', commands:[
    { keys:['d'],     help:'Delete' },
    { keys:['y'],     help:'Yank (copy)' },
    { keys:['c'],     help:'Change' },
    { keys:['p'],     help:'Paste' },
    { keys:['>'],     help:'Indent' },
    { keys:['<'],     help:'Unindent' },
  ]},
  // Action commands. Always used alone. Each one is complete as itself.
  { type:'action', commands:[
    { keys:['i'],     help:'Switch to insert mode' },
    { keys:['v'],     help:'Switch to visual mode' },
    { keys:['x'],     help:'Delete a character' },
    { keys:['u'],     help:'Undo' },
    { keys:['<C-r>'], help:'Redo' },
  ]},
  // Modifiers. Used before text object.
  { type:'modifier', commands:[
    { keys:['a'],     help:'Around' },
    { keys:['i'],     help:'Inside' },
  ]},
  // Text objects. Used after a modifier.
  { type:'textobj', commands:[
    { keys:['w'],     help:'Word' },
    { keys:['"'],     help:'Dobule quote' },
    { keys:['\''],    help:'Single quote' },
    { keys:['('],     help:'Parenthesis' },
    { keys:[')'],     help:'Parenthesis' },
    { keys:['{'],     help:'Braces' },
    { keys:['}'],     help:'Braces' },
    { keys:['['],     help:'Brackets' },
    { keys:[']'],     help:'Brackets' },
  ]},
  // Search commands.
  { type:'search', commands:[
    { keys:['/'],     help:'Search forward' },
  ]},
  // Ex commands.
  { type:'ex', commands:[
    { keys:[':'],     help:'Use ex command' },
  ]},
  // Esc is treated specially.
  { type:'done', commands:[
    { keys:['<Esc>'], help:'Cancel command' },
  ]},
];

// Interface to manipulate current command help at the bottom.
function HelpViewer(context) {

  var display = $("#helps-display", context);

  var append = function(keys, help) {
    keys = keys.join('');
    keys = keys.replace("<","<");
    keys = keys.replace(">",">");

    var kbd = $("
"+keys+"
");
    var txt = $("
"+help+"
");
    display.append(kbd).append(txt);
  };

  var clear = function() {
    display.html("");
  };

  return {
    append: append,
    clear: clear,
  };
}

// Interface to suggested keys help at the right.
function KeysViewer(context) {
  var display = $("#keys-display");

  var appendType = function(bundle) {
    var div = $("

").addClass(bundle.type);
    var title = $("
"+bundle.type+"
");
    div.append(title);
    display.append(div);
    return div;
  };

  var appendCommand = function(container, cmd) {
    var keys = cmd.keys;
    keys = keys.join('').replace('<','<').replace('>','>');

    var div = $("

");
    var kbd = $(""+keys+"");
    var txt = $("  "+cmd.help+"");
    div.append(kbd).append(txt);
    container.append(div);
  };

  var init = function(commandList) {

    for (var i=0; i<commandList.length; i++) {
      var bundle = commandList[i];
      var container = appendType(bundle);

      for (var j=0; j<bundle.commands.length; j++) {
        var cmd = bundle.commands[j];
        appendCommand(container, cmd);
      }
    }
  };

  var update = function(filter) {
    for (var type in filter) {
      if (filter[type])
        $("."+type, display).show();
      else
        $("."+type, display).hide();
    }
  };

  return {
    init: init,
    update: update,
  };
}

// Simple model for vim command grammar.
function VimFSM(context) {
  var fsm = StateMachine.create({
    initial:'_none',
    events: [
      { name:'motion',   from:'_none',       to:'_simpleMotion'    },
      { name:'motion',   from:'_noneRepeat', to:'_simpleMotion'    },
      { name:'motion',   from:'_operator',   to:'_operatorsMotion' },

      { name:'operator', from:'_none',       to:'_operator'        },
      { name:'operator', from:'_noneRepeat', to:'_operator'        },
      { name:'operator', from:'_operator',   to:'_operatorLinewise'},

      { name:'action',   from:'_none',       to:'_action'          },
      { name:'action',   from:'_noneRepeat', to:'_action'          },

      { name:'modifier', from:'_operator',   to:'_modifier'        },
      { name:'textobj',  from:'_modifier',   to:'_textobj'         },

      { name:'search',   from:'_none',       to:'_search'          },
      { name:'ex',       from:'_none',       to:'_ex'              },

      { name:'done',     from:'*',           to:'_none'            },

      { name:'nonzero',  from:'_none',       to:'_noneRepeat'      },
      { name:'nonzero',  from:'_noneRepeat', to:'_noneRepeat'      },
  ]});
  fsm.events = ['motion','operator','action','modifier','textobj','search','ex'];
  return fsm;
}

// Outermost interface to overall help functionality.
function CommandHelper (commandList_, context) {

  var commandList = commandList_;
  var fsm = VimFSM(context);

  var helpViewer = HelpViewer(context);
  var keysViewer = KeysViewer(context);

  var keyBuf = [];
  var numBuf = [];
  var matchCommand = function () {
    var match;
    for (var i=0; i<commandList.length; i++) {
      var bundle = commandList[i];

      if (fsm.can(bundle.type)) {
        for (var j=0; j<bundle.commands.length; j++) {
          var cmd = bundle.commands[j];

          if (compareKeys(cmd.keys, keyBuf)) {
            if (match)
              throw ("Duplicate command: " + keys.join());
            match = { type:bundle.type, keys:cmd.keys, help:cmd.help };
          }
        }
      }
    }
    return match;
  };

  var compareKeys = function (a, b) {
    if (a.length != b.length)
      return false;
    for (var i=0; i<a.length; i++) {
      if (a[i] != b[i])
        return false;
    }
    return true;
  };

  var showHelp = function(cmd) {
    switch (fsm.current) {
      case '_simpleMotion':
        helpViewer.clear();
        helpViewer.append(cmd.keys, "Move "+cmd.help);
        break;
      case '_operatorLinewise':
        helpViewer.append(cmd.keys, "This line");
        break;
      case '_operator':
      case '_action':
      case '_search':
      case '_ex':
        helpViewer.clear();
        helpViewer.append(cmd.keys, cmd.help);
        break;
      case '_operatorsMotion':
      case '_modifier':
      case '_textobj':
        helpViewer.append(cmd.keys, cmd.help);
        break;
      case '_none':
        helpViewer.clear();
        break;
      default:
        throw "no such state.";
    }
  };

  var showRepeat = function() {
    helpViewer.append(numBuf, "Repeat "+numBuf.join('')+" times.");
  };

  var showKeys = function() {
    filter = [];
    for (var i=0; i<fsm.events.length; i++) {
      var e = fsm.events[i];
      if (fsm.can(e))
        filter[e] = true;
      else
        filter[e] = false;
    }
    keysViewer.update(filter);
  };

  var onKey = function(key) {
    keyBuf.push(key);
    var match = matchCommand();
    if (match) {
      keyBuf = [];
      fsm[match.type]();
      showHelp(match);
      showKeys();
    }
    else {
      if (isNonzero(key) && fsm.can('nonzero')) {
        numBuf.push(keyBuf.pop());
        fsm.nonzero();
        showRepeat();
      }
    }
  };

  var isNonzero = function(key) {
    return (key.charCodeAt(0) >= '1'.charCodeAt(0)
         && key.charCodeAt(0) <= '9'.charCodeAt(0));
  };

  var init = function() {
    keysViewer.init(commandList);
  };

  var done = function() {
    fsm.done();
    showKeys();
  };

  return {
    onKey: onKey,
    init: init,
    done: done,
  };
}

var commandHelper = CommandHelper(commandListEN, window.body);

<commit_msg>[help] Add support to 0 key as repeat count.<commit_after>
var commandListEN = [
  // Motion commands. Can be used alone, or used with operator.
  { type:'motion', commands:[
    { keys:['h'],       help:'to left' },
    { keys:['j'],       help:'to down' },
    { keys:['k'],       help:'to up' },
    { keys:['l'],       help:'to right' },
    { keys:['<Left>'],  help:'to left' },
    { keys:['<Down>'],  help:'to down' },
    { keys:['<Up>'],    help:'to up' },
    { keys:['<Right>'], help:'to right' },

    { keys:['w'],       help:'a word' },
    { keys:['b'],       help:'a word backward' },

    { keys:['0'],       help:'to start of line' },
    { keys:['$'],       help:'to end of line' },

    { keys:['g','g'],   help:'to start of file' },
  ]},
  // Operator commands. Always used with either (i) motion,
  // (ii) a modifier + text-object (iii) itself, meaning linewise operation.
  { type:'operator', commands:[
    { keys:['d'],     help:'Delete' },
    { keys:['y'],     help:'Yank (copy)' },
    { keys:['c'],     help:'Change' },
    { keys:['p'],     help:'Paste' },
    { keys:['>'],     help:'Indent' },
    { keys:['<'],     help:'Unindent' },
  ]},
  // Action commands. Always used alone. Each one is complete as itself.
  { type:'action', commands:[
    { keys:['i'],     help:'Switch to insert mode' },
    { keys:['v'],     help:'Switch to visual mode' },
    { keys:['x'],     help:'Delete a character' },
    { keys:['u'],     help:'Undo' },
    { keys:['<C-r>'], help:'Redo' },
  ]},
  // Modifiers. Used before text object.
  { type:'modifier', commands:[
    { keys:['a'],     help:'Around' },
    { keys:['i'],     help:'Inside' },
  ]},
  // Text objects. Used after a modifier.
  { type:'textobj', commands:[
    { keys:['w'],     help:'Word' },
    { keys:['"'],     help:'Dobule quote' },
    { keys:['\''],    help:'Single quote' },
    { keys:['('],     help:'Parenthesis' },
    { keys:[')'],     help:'Parenthesis' },
    { keys:['{'],     help:'Braces' },
    { keys:['}'],     help:'Braces' },
    { keys:['['],     help:'Brackets' },
    { keys:[']'],     help:'Brackets' },
  ]},
  // Search commands.
  { type:'search', commands:[
    { keys:['/'],     help:'Search forward' },
  ]},
  // Ex commands.
  { type:'ex', commands:[
    { keys:[':'],     help:'Use ex command' },
  ]},
  // Esc is treated specially.
  { type:'done', commands:[
    { keys:['<Esc>'], help:'Cancel command' },
  ]},
];

// Interface to manipulate current command help at the bottom.
function HelpViewer(context) {

  var display = $("#helps-display", context);

  var append = function(keys, help) {
    keys = keys.join('');
    keys = keys.replace("<","<");
    keys = keys.replace(">",">");

    var kbd = $("
"+keys+"
");
    var txt = $("
"+help+"
");
    display.append(kbd).append(txt);
  };

  var clear = function() {
    display.html("");
  };

  return {
    append: append,
    clear: clear,
  };
}

// Interface to suggested keys help at the right.
function KeysViewer(context) {
  var display = $("#keys-display");

  var appendType = function(bundle) {
    var div = $("

").addClass(bundle.type);
    var title = $("
"+bundle.type+"
");
    div.append(title);
    display.append(div);
    return div;
  };

  var appendCommand = function(container, cmd) {
    var keys = cmd.keys;
    keys = keys.join('').replace('<','<').replace('>','>');

    var div = $("

");
    var kbd = $(""+keys+"");
    var txt = $("  "+cmd.help+"");
    div.append(kbd).append(txt);
    container.append(div);
  };

  var init = function(commandList) {

    for (var i=0; i<commandList.length; i++) {
      var bundle = commandList[i];
      var container = appendType(bundle);

      for (var j=0; j<bundle.commands.length; j++) {
        var cmd = bundle.commands[j];
        appendCommand(container, cmd);
      }
    }
  };

  var update = function(filter) {
    for (var type in filter) {
      if (filter[type])
        $("."+type, display).show();
      else
        $("."+type, display).hide();
    }
  };

  return {
    init: init,
    update: update,
  };
}

// Simple model for vim command grammar.
function VimFSM(context) {
  var fsm = StateMachine.create({
    initial:'_none',
    events: [
      { name:'motion',   from:'_none',       to:'_simpleMotion'    },
      { name:'motion',   from:'_noneRepeat', to:'_simpleMotion'    },
      { name:'motion',   from:'_operator',   to:'_operatorsMotion' },

      { name:'operator', from:'_none',       to:'_operator'        },
      { name:'operator', from:'_noneRepeat', to:'_operator'        },
      { name:'operator', from:'_operator',   to:'_operatorLinewise'},

      { name:'action',   from:'_none',       to:'_action'          },
      { name:'action',   from:'_noneRepeat', to:'_action'          },

      { name:'modifier', from:'_operator',   to:'_modifier'        },
      { name:'textobj',  from:'_modifier',   to:'_textobj'         },

      { name:'search',   from:'_none',       to:'_search'          },
      { name:'ex',       from:'_none',       to:'_ex'              },

      { name:'done',     from:'*',           to:'_none'            },

      { name:'nonzero',  from:'_none',       to:'_noneRepeat'      },
      { name:'nonzero',  from:'_noneRepeat', to:'_noneRepeat'      },
      { name:'zero',     from:'_noneRepeat', to:'_noneRepeat'      },
  ]});
  fsm.events = ['motion','operator','action','modifier','textobj','search','ex'];
  return fsm;
}

// Outermost interface to overall help functionality.
function CommandHelper (commandList_, context) {

  var commandList = commandList_;
  var fsm = VimFSM(context);

  var helpViewer = HelpViewer(context);
  var keysViewer = KeysViewer(context);

  var keyBuf = [];
  var numBuf = [];
  var matchCommand = function () {
    var match;
    for (var i=0; i<commandList.length; i++) {
      var bundle = commandList[i];

      if (fsm.can(bundle.type)) {
        for (var j=0; j<bundle.commands.length; j++) {
          var cmd = bundle.commands[j];

          if (compareKeys(cmd.keys, keyBuf)) {
            if (match)
              throw ("Duplicate command: " + keys.join());
            match = { type:bundle.type, keys:cmd.keys, help:cmd.help };
          }
        }
      }
    }
    return match;
  };

  var compareKeys = function (a, b) {
    if (a.length != b.length)
      return false;
    for (var i=0; i<a.length; i++) {
      if (a[i] != b[i])
        return false;
    }
    return true;
  };

  var showHelp = function(cmd) {
    switch (fsm.current) {
      case '_simpleMotion':
        helpViewer.clear();
        helpViewer.append(cmd.keys, "Move "+cmd.help);
        break;
      case '_operatorLinewise':
        helpViewer.append(cmd.keys, "This line");
        break;
      case '_operator':
      case '_action':
      case '_search':
      case '_ex':
        helpViewer.clear();
        helpViewer.append(cmd.keys, cmd.help);
        break;
      case '_operatorsMotion':
      case '_modifier':
      case '_textobj':
        helpViewer.append(cmd.keys, cmd.help);
        break;
      case '_none':
        helpViewer.clear();
        break;
      default:
        throw "no such state.";
    }
  };

  var showRepeat = function() {
    helpViewer.append(numBuf, "Repeat "+numBuf.join('')+" times.");
  };

  var showKeys = function() {
    filter = [];
    for (var i=0; i<fsm.events.length; i++) {
      var e = fsm.events[i];
      if (fsm.can(e))
        filter[e] = true;
      else
        filter[e] = false;
    }
    keysViewer.update(filter);
  };

  var onKey = function(key) {

    keyBuf.push(key);
    var match;

    // '0' key is special case since it belongs
    // in both command and repeat.
    if (key != '0' || numBuf.length == 0)
      match = matchCommand();

    if (match) {
      keyBuf = [];
      fsm[match.type](match);
      showKeys();
    }
    else {
      if (isNonzero(key) && fsm.can('nonzero') ||
          key == '0' && fsm.can('zero')) {

        // keyBuf is for command sequences, no repeat counts.
        numBuf.push(keyBuf.pop());
        fsm.nonzero();
        showRepeat();
      }
    }
  };

  var isNonzero = function(key) {
    return (key.charCodeAt(0) >= '1'.charCodeAt(0)
         && key.charCodeAt(0) <= '9'.charCodeAt(0));
  };

  var init = function() {
    keysViewer.init(commandList);
  };

  var done = function() {
    fsm.done();
    showKeys();
  };

  return {
    onKey: onKey,
    init: init,
    done: done,
  };
}

var commandHelper = CommandHelper(commandListEN, window.body);

<|endoftext|>


<commit_before>// Copyright 2014 Technical Machine, Inc. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

var http = require('http');

// This reuses the http module, setting a private "_secure" flag.
// Could be done better.

for (var key in http) {
  exports[key] = http[key];
}

exports._secure = true;<commit_msg>bindings creating fun new errors<commit_after>// Copyright 2014 Technical Machine, Inc. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

var http = require('http');

// This reuses the http module, setting a private "_secure" flag.
// Could be done better.

for (var key in http) {
  exports[key] = http[key].bind(exports);
}

exports._secure = true;<|endoftext|>


<commit_before>var path = require('path');
var p = require('pfork');
var fs = require('fs');
var fse = require('fs-extra');
var EventEmitter = require('events').EventEmitter;
var pluginMgr = new EventEmitter();
var colors = require('colors/safe');
var comUtil = require('../util');
var util = require('./util');
var config = require('../config');
var getPluginsSync = require('./get-plugins-sync');
var getPlugin = require('./get-plugins');
var rulesMgr = require('../rules');
var properties = require('../rules/util').properties;
var RulesMgr = rulesMgr.Rules;
var PLUGIN_MAIN = path.join(__dirname, './load-plugin');
var PLUGIN_URL_RE = /^(?:http|ws)s?:\/\/([\da-z]+)\.local\.whistlejs\.com\//i;
var RULE_VALUE_HEADER = 'x-whistle-rule-value';
var SSL_FLAG_HEADER = 'x-whistle-https';
var INTERVAL = 6000;
var UTF8_OPTIONS = {encoding: 'utf8'};
var plugins = getPluginsSync();
var rules = plugins.rules;
var conf = {};
plugins = plugins.plugins;

Object.keys(config).forEach(function(name) {
	var value = config[name];
	if (typeof value == 'string' || typeof value == 'number') {
		conf[name] = value;
	}
});

pluginMgr.on('updateRules', function() {
	rulesMgr.clearAppend();
	Object.keys(rules).sort(function(a, b) {
		return a > b ? 1 : -1;
	}).forEach(function(name) {
		if (pluginsRulesIsDisabled(name.slice(0, -1))) {
			return;
		}
		var plugin = rules[name];
		if (plugin._rules && !plugin.rulesMgr) {
			plugin.rulesMgr = new RulesMgr();
			plugin.rulesMgr.parse(plugin._rules, plugin.path);
		}
		rulesMgr.append(plugin.rules, plugin.path);
	});
});
parsePluginRules();
pluginMgr.emit('updateRules', rules);

pluginMgr.updateRules = function() {
	pluginMgr.emit('updateRules');
};

function parsePluginRules() {
	Object.keys(plugins).forEach(function(name) {
		var plugin = plugins[name];
		if (plugin._rules && !plugin.rulesMgr) {
			plugin.rulesMgr = new RulesMgr();
			plugin.rulesMgr.parse(plugin._rules, plugin.path);
		}
	});
}

function pluginsRulesIsDisabled(name) {
	var disabledPluginsRules = properties.get('disabledPluginsRules') || {};
	return disabledPluginsRules[name];
}

function showVerbose(tag, oldData, newData) {
	if (!config.debugMode) {
		return;
	}
	var uninstallData, installData, updateData;
	Object.keys(oldData).forEach(function(name) {
		var oldItem = oldData[name];
		var newItem = newData[name];
		if (!newItem) {
			uninstallData = uninstallData || {};
			uninstallData[name] = oldItem;
		} else if (newItem.path != oldItem.path || newItem.mtime != oldItem.mtime) {
			updateData = updateData || {};
			updateData[name] = newItem;
		}
	});

	Object.keys(newData).forEach(function(name) {
		if (!oldData[name]) {
			installData = installData || {};
			installData[name] = newData[name];
		}
	});

	if (uninstallData || installData || updateData) {
		console.log('\n***********[%s] %s has changed***********', comUtil.formatDate(), tag + 's');
	}

	uninstallData && Object.keys(uninstallData).forEach(function(name) {
		console.log(colors.red('[' + comUtil.formatDate(new Date(uninstallData[name].mtime)) + '] [uninstall ' + tag + '] ' + name.slice(0, -1)));
	});
	installData && Object.keys(installData).forEach(function(name) {
		console.log(colors.green('[' + comUtil.formatDate(new Date(installData[name].mtime)) + '] [install ' + tag + '] ' + name.slice(0, -1)));
	});
	updateData && Object.keys(updateData).forEach(function(name) {
		console.log(colors.yellow('[' + comUtil.formatDate(new Date(updateData[name].mtime)) + '] [update ' + tag + '] ' + name.slice(0, -1)));
	});
}

function readPackages(obj, callback) {
	var _plugins = {};
	var _rules = {};
	var count = 0;
	Object.keys(obj).forEach(function(name) {
		var pkg = plugins[name] || rules[name];
		var newPkg = obj[name];
		if (!pkg || pkg.path != newPkg.path || pkg.mtime != newPkg.mtime) {
			++count;
			fse.readJson(newPkg.pkgPath, function(err, pkg) {
				if (pkg && pkg.version) {
					newPkg.version = pkg.version;
					newPkg.homepage = util.getHomePageFromPackage(pkg);
					var pureRules = !!pkg.pureRules;
					newPkg.pureRules = pureRules;
					if (!pureRules) {
						_plugins[name] = newPkg;
					}
					fs.readFile(path.join(path.join(newPkg.path, 'rules.txt')), UTF8_OPTIONS, function(err, rulesText) {
						rulesText = comUtil.trim(rulesText);
						newPkg.rules = rulesText;
						if (rulesText) {
							_rules[name] = newPkg;
						}
						fs.readFile(path.join(path.join(newPkg.path, '_rules.txt')), UTF8_OPTIONS, function(err, rulesText) {
							newPkg._rules = comUtil.trim(rulesText);
							if (--count <= 0) {
								callback(_plugins, _rules);
							}
						});
					});
				}

			});

		} else {
			if (pkg.pureRules || pkg.rules) {
				_rules[name] = pkg;
			}

			if (!pkg.pureRules) {
				_plugins[name] = pkg;
			}
		}
	});

	if (count <= 0) {
		callback(_plugins, _rules);
	}
}

(function update() {
	setTimeout(function() {
		getPlugin(function(result) {
			readPackages(result, function(_plugins, _rules) {
				var hasUpdateRules;
				var rulesKeys = Object.keys(rules);
				var _rulesKeys = Object.keys(_rules);
				hasUpdateRules = rulesKeys.length != _rulesKeys.length;

				if (!hasUpdateRules) {
					for (var i = 0, len = rulesKeys.length; i < len; i++) {
						var name = rulesKeys[i];
						var rule = rules[name];
						var _rule = _rules[name];
						if (!rule || !_rule || rule.rules != _rule.rules) {
							hasUpdateRules = true;
							break;
						}
					}
				}

				showVerbose('rule', rules, _rules);
				rules = _rules;
				hasUpdateRules && pluginMgr.emit('updateRules', rules);

				var updatePlugins, uninstallPlugins;
				Object.keys(plugins).forEach(function(name) {
					var plugin = plugins[name];
					var newPlugin = _plugins[name];
					if (!newPlugin) {
						uninstallPlugins = uninstallPlugins || {};
						uninstallPlugins[name] = plugin;
					} else if (newPlugin.path != plugin.path || newPlugin.mtime != plugin.mtime) {
						updatePlugins = updatePlugins || {};
						updatePlugins[name] = newPlugin;
					}
				});
				showVerbose('plugin', plugins, _plugins);
				plugins = _plugins;
				uninstallPlugins && pluginMgr.emit('uninstall', uninstallPlugins);
				updatePlugins && pluginMgr.emit('update', updatePlugins);
				parsePluginRules();
				update();
			});
		});
	}, INTERVAL);
})();

pluginMgr.RULE_VALUE_HEADER = RULE_VALUE_HEADER;
pluginMgr.SSL_FLAG_HEADER = SSL_FLAG_HEADER;

pluginMgr.loadPlugin = function(plugin, callback) {
	config.debugMode && console.log(colors.cyan('[' + comUtil.formatDate() + '] [access plugin] ' + plugin.path));
	p.fork({
		script: PLUGIN_MAIN,
		value: plugin.path,
		RULE_VALUE_HEADER: RULE_VALUE_HEADER,
		SSL_FLAG_HEADER: SSL_FLAG_HEADER,
		debugMode: config.debugMode,
		config: conf
	}, function(err, ports, child) {
		callback && callback(err, ports, child);
		if (config.debugMode) {
			if (err) {
				console.log(colors.red(err));
			} else if (!child.debugMode) {
				child.debugMode = true;
				child.on('data', function(data) {
					if (data && data.type == 'console.log') {
						console.log('[' + comUtil.formatDate() + '] [plugin] [' + plugin.path.substring(plugin.path.lastIndexOf('.') + 1) + ']', data.message);
					}
				});
				child.sendData({
					type: 'console.log',
					status: 'ready'
				});
			}
		}
	});
};

pluginMgr.stopPlugin = function(plugin) {
	p.kill({
		script: PLUGIN_MAIN,
		value: plugin.path
	}, 10000);
};

pluginMgr.getPlugins = function() {
	return plugins;
};

function pluginIsDisabled(name) {
	var disabledPlugins = properties.get('disabledPlugins') || {};
	return disabledPlugins[name];
}

pluginMgr.getPlugin = function(protocol) {
	return pluginIsDisabled(protocol.slice(0, -1)) ? null : plugins[protocol];
};

pluginMgr.getPluginByRuleUrl = function(ruleUrl) {
	if (!ruleUrl || typeof ruleUrl != 'string') {
		return;
	}
	var index = ruleUrl.indexOf(':');
	if (index == -1) {
		return null;
	}
	var protocol = ruleUrl.substring(0, index + 1);
	return pluginIsDisabled(protocol.slice(0, -1)) ? null : plugins[protocol];
};

pluginMgr.getPluginByHomePage = function(url) {
	return PLUGIN_URL_RE.test(url)
				&& plugins[RegExp.$1 + ':'];
};

pluginMgr.getRules = function() {
	return rules;
};

module.exports = pluginMgr;

<commit_msg>fix: Error reading package.json  will cause the plugin can not be loaded<commit_after>var path = require('path');
var p = require('pfork');
var fs = require('fs');
var fse = require('fs-extra');
var EventEmitter = require('events').EventEmitter;
var pluginMgr = new EventEmitter();
var colors = require('colors/safe');
var comUtil = require('../util');
var util = require('./util');
var config = require('../config');
var getPluginsSync = require('./get-plugins-sync');
var getPlugin = require('./get-plugins');
var rulesMgr = require('../rules');
var properties = require('../rules/util').properties;
var RulesMgr = rulesMgr.Rules;
var PLUGIN_MAIN = path.join(__dirname, './load-plugin');
var PLUGIN_URL_RE = /^(?:http|ws)s?:\/\/([\da-z]+)\.local\.whistlejs\.com\//i;
var RULE_VALUE_HEADER = 'x-whistle-rule-value';
var SSL_FLAG_HEADER = 'x-whistle-https';
var INTERVAL = 6000;
var UTF8_OPTIONS = {encoding: 'utf8'};
var plugins = getPluginsSync();
var rules = plugins.rules;
var conf = {};
plugins = plugins.plugins;

Object.keys(config).forEach(function(name) {
	var value = config[name];
	if (typeof value == 'string' || typeof value == 'number') {
		conf[name] = value;
	}
});

pluginMgr.on('updateRules', function() {
	rulesMgr.clearAppend();
	Object.keys(rules).sort(function(a, b) {
		return a > b ? 1 : -1;
	}).forEach(function(name) {
		if (pluginsRulesIsDisabled(name.slice(0, -1))) {
			return;
		}
		var plugin = rules[name];
		if (plugin._rules && !plugin.rulesMgr) {
			plugin.rulesMgr = new RulesMgr();
			plugin.rulesMgr.parse(plugin._rules, plugin.path);
		}
		rulesMgr.append(plugin.rules, plugin.path);
	});
});
parsePluginRules();
pluginMgr.emit('updateRules', rules);

pluginMgr.updateRules = function() {
	pluginMgr.emit('updateRules');
};

function parsePluginRules() {
	Object.keys(plugins).forEach(function(name) {
		var plugin = plugins[name];
		if (plugin._rules && !plugin.rulesMgr) {
			plugin.rulesMgr = new RulesMgr();
			plugin.rulesMgr.parse(plugin._rules, plugin.path);
		}
	});
}

function pluginsRulesIsDisabled(name) {
	var disabledPluginsRules = properties.get('disabledPluginsRules') || {};
	return disabledPluginsRules[name];
}

function showVerbose(tag, oldData, newData) {
	if (!config.debugMode) {
		return;
	}
	var uninstallData, installData, updateData;
	Object.keys(oldData).forEach(function(name) {
		var oldItem = oldData[name];
		var newItem = newData[name];
		if (!newItem) {
			uninstallData = uninstallData || {};
			uninstallData[name] = oldItem;
		} else if (newItem.path != oldItem.path || newItem.mtime != oldItem.mtime) {
			updateData = updateData || {};
			updateData[name] = newItem;
		}
	});

	Object.keys(newData).forEach(function(name) {
		if (!oldData[name]) {
			installData = installData || {};
			installData[name] = newData[name];
		}
	});

	if (uninstallData || installData || updateData) {
		console.log('\n***********[%s] %s has changed***********', comUtil.formatDate(), tag + 's');
	}

	uninstallData && Object.keys(uninstallData).forEach(function(name) {
		console.log(colors.red('[' + comUtil.formatDate(new Date(uninstallData[name].mtime)) + '] [uninstall ' + tag + '] ' + name.slice(0, -1)));
	});
	installData && Object.keys(installData).forEach(function(name) {
		console.log(colors.green('[' + comUtil.formatDate(new Date(installData[name].mtime)) + '] [install ' + tag + '] ' + name.slice(0, -1)));
	});
	updateData && Object.keys(updateData).forEach(function(name) {
		console.log(colors.yellow('[' + comUtil.formatDate(new Date(updateData[name].mtime)) + '] [update ' + tag + '] ' + name.slice(0, -1)));
	});
}

function readPackages(obj, callback) {
	var _plugins = {};
	var _rules = {};
	var count = 0;
	var callbackHandler = function() {
		if (--count <= 0) {
			callback(_plugins, _rules);
		}
	};
	Object.keys(obj).forEach(function(name) {
		var pkg = plugins[name] || rules[name];
		var newPkg = obj[name];
		if (!pkg || pkg.path != newPkg.path || pkg.mtime != newPkg.mtime) {
			++count;
			fse.readJson(newPkg.pkgPath, function(err, pkg) {
				if (pkg && pkg.version) {
					newPkg.version = pkg.version;
					newPkg.homepage = util.getHomePageFromPackage(pkg);
					var pureRules = !!pkg.pureRules;
					newPkg.pureRules = pureRules;
					if (!pureRules) {
						_plugins[name] = newPkg;
					}
					fs.readFile(path.join(path.join(newPkg.path, 'rules.txt')), UTF8_OPTIONS, function(err, rulesText) {
						rulesText = comUtil.trim(rulesText);
						newPkg.rules = rulesText;
						if (rulesText) {
							_rules[name] = newPkg;
						}
						fs.readFile(path.join(path.join(newPkg.path, '_rules.txt')), UTF8_OPTIONS, function(err, rulesText) {
							newPkg._rules = comUtil.trim(rulesText);
							callbackHandler();
						});
					});
				} else {
					callbackHandler();
				}

			});

		} else {
			if (pkg.pureRules || pkg.rules) {
				_rules[name] = pkg;
			}

			if (!pkg.pureRules) {
				_plugins[name] = pkg;
			}
		}
	});

	if (count <= 0) {
		callback(_plugins, _rules);
	}
}

(function update() {
	setTimeout(function() {
		getPlugin(function(result) {
			readPackages(result, function(_plugins, _rules) {
				var hasUpdateRules;
				var rulesKeys = Object.keys(rules);
				var _rulesKeys = Object.keys(_rules);
				hasUpdateRules = rulesKeys.length != _rulesKeys.length;

				if (!hasUpdateRules) {
					for (var i = 0, len = rulesKeys.length; i < len; i++) {
						var name = rulesKeys[i];
						var rule = rules[name];
						var _rule = _rules[name];
						if (!rule || !_rule || rule.rules != _rule.rules) {
							hasUpdateRules = true;
							break;
						}
					}
				}

				showVerbose('rule', rules, _rules);
				rules = _rules;
				hasUpdateRules && pluginMgr.emit('updateRules', rules);

				var updatePlugins, uninstallPlugins;
				Object.keys(plugins).forEach(function(name) {
					var plugin = plugins[name];
					var newPlugin = _plugins[name];
					if (!newPlugin) {
						uninstallPlugins = uninstallPlugins || {};
						uninstallPlugins[name] = plugin;
					} else if (newPlugin.path != plugin.path || newPlugin.mtime != plugin.mtime) {
						updatePlugins = updatePlugins || {};
						updatePlugins[name] = newPlugin;
					}
				});
				showVerbose('plugin', plugins, _plugins);
				plugins = _plugins;
				uninstallPlugins && pluginMgr.emit('uninstall', uninstallPlugins);
				updatePlugins && pluginMgr.emit('update', updatePlugins);
				parsePluginRules();
				update();
			});
		});
	}, INTERVAL);
})();

pluginMgr.RULE_VALUE_HEADER = RULE_VALUE_HEADER;
pluginMgr.SSL_FLAG_HEADER = SSL_FLAG_HEADER;

pluginMgr.loadPlugin = function(plugin, callback) {
	config.debugMode && console.log(colors.cyan('[' + comUtil.formatDate() + '] [access plugin] ' + plugin.path));
	p.fork({
		script: PLUGIN_MAIN,
		value: plugin.path,
		RULE_VALUE_HEADER: RULE_VALUE_HEADER,
		SSL_FLAG_HEADER: SSL_FLAG_HEADER,
		debugMode: config.debugMode,
		config: conf
	}, function(err, ports, child) {
		callback && callback(err, ports, child);
		if (config.debugMode) {
			if (err) {
				console.log(colors.red(err));
			} else if (!child.debugMode) {
				child.debugMode = true;
				child.on('data', function(data) {
					if (data && data.type == 'console.log') {
						console.log('[' + comUtil.formatDate() + '] [plugin] [' + plugin.path.substring(plugin.path.lastIndexOf('.') + 1) + ']', data.message);
					}
				});
				child.sendData({
					type: 'console.log',
					status: 'ready'
				});
			}
		}
	});
};

pluginMgr.stopPlugin = function(plugin) {
	p.kill({
		script: PLUGIN_MAIN,
		value: plugin.path
	}, 10000);
};

pluginMgr.getPlugins = function() {
	return plugins;
};

function pluginIsDisabled(name) {
	var disabledPlugins = properties.get('disabledPlugins') || {};
	return disabledPlugins[name];
}

pluginMgr.getPlugin = function(protocol) {
	return pluginIsDisabled(protocol.slice(0, -1)) ? null : plugins[protocol];
};

pluginMgr.getPluginByRuleUrl = function(ruleUrl) {
	if (!ruleUrl || typeof ruleUrl != 'string') {
		return;
	}
	var index = ruleUrl.indexOf(':');
	if (index == -1) {
		return null;
	}
	var protocol = ruleUrl.substring(0, index + 1);
	return pluginIsDisabled(protocol.slice(0, -1)) ? null : plugins[protocol];
};

pluginMgr.getPluginByHomePage = function(url) {
	return PLUGIN_URL_RE.test(url)
				&& plugins[RegExp.$1 + ':'];
};

pluginMgr.getRules = function() {
	return rules;
};

module.exports = pluginMgr;

<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
import sendRequest from './send-request';

/**
 * Expose `Request` module
 * @param {WPCOM} wpcom - wpcom instance
 */
export default function Req( wpcom ) {
	this.wpcom = wpcom;
}

/**
 * Request methods
 *
 * @param {Object|String} params - params object
 * @param {Object} [query] - query object parameter
 * @param {Function} fn - callback function
 * @return {Function} request handler
 */
Req.prototype.get = function( params, query, fn ) {
	// `query` is optional
	if ( 'function' === typeof query ) {
		fn = query;
		query = {};
	}

	return sendRequest.call( this.wpcom, params, query, null, fn );
};

/**
 * Make `update` request
 *
 * @param {Object|String} params
 * @param {Object} [query] - query object parameter
 * @param {Object} body - body object parameter
 * @param {Function} fn - callback function
 */
Req.prototype.post =
Req.prototype.put = function( params, query, body, fn ) {
	if ( undefined === fn ) {
		if ( undefined === body ) {
			body = query;
			query = {};
		} else if ( 'function' === typeof body ) {
			fn = body;
			body = query;
			query = {};
		}
	}

	// params can be a string
	params = 'string' === typeof params ? { path: params } : params;

	// request method
	params.method = 'post';

	return sendRequest.call( this.wpcom, params, query, body, fn );
};

/**
 * Make a `delete` request
 *
 * @param {Object|String} params - params object
 * @param {Object} [query] - query object parameter
 * @param {Function} fn - callback function
 * @return {Function} request handler
 */
Req.prototype.del = function( params, query, fn ) {
	if ( 'function' === typeof query ) {
		fn = query;
		query = {};
	}

	return this.post( params, query, null, fn );
};
<commit_msg>Allow overriding request http verb in post/put/del<commit_after>/**
 * Module dependencies.
 */
import sendRequest from './send-request';

/**
 * Expose `Request` module
 * @param {WPCOM} wpcom - wpcom instance
 */
export default function Req( wpcom ) {
	this.wpcom = wpcom;
}

/**
 * Request methods
 *
 * @param {Object|String} params - params object
 * @param {Object} [query] - query object parameter
 * @param {Function} fn - callback function
 * @return {Function} request handler
 */
Req.prototype.get = function( params, query, fn ) {
	// `query` is optional
	if ( 'function' === typeof query ) {
		fn = query;
		query = {};
	}

	return sendRequest.call( this.wpcom, params, query, null, fn );
};

/**
 * Make `update` request
 *
 * @param {Object|String} params
 * @param {Object} [query] - query object parameter
 * @param {Object} body - body object parameter
 * @param {Function} fn - callback function
 */
Req.prototype.post =
Req.prototype.put = function( params, query, body, fn ) {
	if ( undefined === fn ) {
		if ( undefined === body ) {
			body = query;
			query = {};
		} else if ( 'function' === typeof body ) {
			fn = body;
			body = query;
			query = {};
		}
	}

	// params can be a string
	params = 'string' === typeof params ? { path: params } : params;

	// in v1 endpoints, DELETE and PUT operations use http POST, but for v2 endpoints we must allow this to be overridden
	params.method = params.method || 'post';

	return sendRequest.call( this.wpcom, params, query, body, fn );
};

/**
 * Make a `delete` request
 *
 * @param {Object|String} params - params object
 * @param {Object} [query] - query object parameter
 * @param {Function} fn - callback function
 * @return {Function} request handler
 */
Req.prototype.del = function( params, query, fn ) {
	if ( 'function' === typeof query ) {
		fn = query;
		query = {};
	}

	return this.post( params, query, null, fn );
};
<|endoftext|>


<commit_before>const Discord = require("discord.js");
const config = require("./../../config.json");
const MSS = require("./../../functions/");
const request = require("request");

module.exports = function place(message) {
	let input = message.content.replace (/\n/g, "").split(" ");
	var user = encodeURI(input[1]);

	request('http://moustacheminer.com/place/searchapi.php?username=' + user, function(error, response, body) {
		if(error) {
			message.reply("An error occured while retrieving the data: " + error);
		}

		var data = JSON.parse(body);
		var response = "/r/place info for " + input[1] + "\n";
		var overflow = false;

		data.info.forEach(function(element) {
			var colour;
			switch(element.colour) {
				case 1:
					colour = "Light Grey";
					break;
				case 2:
					colour = "Grey";
					break;
				case 3:
					colour = "Black";
					break;
				case 4:
					colour = "Pink";
					break;
				case 5:
					colour = "Red";
					break;
				case 6:
					colour = "Orange";
					break;
				case 7:
					colour = "Brown";
					break;
				case 8:
					colour = "Yellow";
					break;
				case 9:
					colour = "Lime";
					break;
				case 10:
					colour = "Green";
					break;
				case 11:
					colour = "Cyan";
					break;
				case 12:
					colour = "Blue";
					break;
				case 13:
					colour = "Dark Blue";
					break;
				case 14:
					colour = "Magenta";
					break;
				case 15:
					colour = "Purple";
					break;
				default:
					colour = "Invalid Colour ID";
					break;
			}

			if (response < 1800) {
				response += "Coloured (" + element.x + "," + element.y + ") " + colour + " at " + new Date(parseInt(element.time)) + "\n";
			} else {
				overflow = true;
			}
		});

		//Yes, false is a string. I'm so sorry
		if(data.error != "false") {
			message.reply(data.error);
		} else {
			if(overflow) {
				response += "The response is too large to display here: Please click the URL in the embed to view the rest.";
			}

			var embed = new Discord.RichEmbed()
				.setTitle(input[1])
				.setAuthor("/r/place", "http://moustacheminer.com/mss.png")
				.setColor("#00AE86")
				.setDescription(response)
				.setFooter("MSS-Discord, " + config.MSS.version, "")
				.setTimestamp()
				.setURL("http://moustacheminer.com/place/?username=" + user);

			message.channel.sendEmbed(embed, "", { disableEveryone: true });
		}
	});
}
<commit_msg>Reuse old code<commit_after>const Discord = require("discord.js");
const config = require("./../../config.json");
const MSS = require("./../../functions/");
const request = require("request");

module.exports = function place(message) {
	let input = message.content.replace (/\n/g, "").split(" ");
	var user = encodeURI(input[1]);

	request('http://moustacheminer.com/place/searchapi.php?username=' + user, function(error, response, body) {
		if(error) {
			message.reply("An error occured while retrieving the data: " + error);
		}

		var data = JSON.parse(body);
		var reply = "";
		var overflow = false;

		if(!data.info) {
			reply += "The user has not placed any dots down, or does not exist.";
		} else {
			data.info.forEach(function(element) {
				var colour;
				switch(parseInt(element.colour)) {
					case 1:
						colour = "Light Grey";
						break;
					case 2:
						colour = "Grey";
						break;
					case 3:
						colour = "Black";
						break;
					case 4:
						colour = "Pink";
						break;
					case 5:
						colour = "Red";
						break;
					case 6:
						colour = "Orange";
						break;
					case 7:
						colour = "Brown";
						break;
					case 8:
						colour = "Yellow";
						break;
					case 9:
						colour = "Lime";
						break;
					case 10:
						colour = "Green";
						break;
					case 11:
						colour = "Cyan";
						break;
					case 12:
						colour = "Blue";
						break;
					case 13:
						colour = "Dark Blue";
						break;
					case 14:
						colour = "Magenta";
						break;
					case 15:
						colour = "Purple";
						break;
					default:
						colour = "Invalid Colour ID";
						break;
				}

				if(reply.length < 1900) {
					reply += "Coloured (" + element.x + "," + element.y + ") " + colour + " at " + new Date(parseInt(element.time)) + "\n";
				} else {
					overflow = true;
				}

			});
		}

		//Yes, false is a string. I'm so sorry
		if(data.error != "false") {
			message.reply(data.error);
		} else {
			var embed = new Discord.RichEmbed()
				.setTitle(input[1])
				.setAuthor("/r/place info for " + input[1], "http://moustacheminer.com/mss.png")
				.setColor("#00AE86")
				.setDescription(reply)
				.setFooter("MSS-Discord, " + config.MSS.version, "")
				.setTimestamp()
				.setURL("http://moustacheminer.com/place/?username=" + user);

			if(overflow) {
				embed.addField("Overflow Error", "Please go to this URL to view the rest of the log. http://moustacheminer.com/place/?username=" + user);
			}

			message.channel.sendEmbed(embed, "", { disableEveryone: true });
		}
	});
}
<|endoftext|>


<commit_before>var util         = require("util")
  , EventEmitter = require("events").EventEmitter

module.exports = (function() {
  var CustomEventEmitter = function(fct) {
    this.fct = fct
  }
  util.inherits(CustomEventEmitter, EventEmitter)

  CustomEventEmitter.prototype.run = function() {
    var self = this

    // delay the function call and return the emitter
    setTimeout(function(){
      self.fct.call(self, self)
    }, 1)

    return this
  }

  CustomEventEmitter.prototype.success =
  CustomEventEmitter.prototype.ok =
  function(fct) {
    this.on('success', fct)
    return this
  }

  CustomEventEmitter.prototype.failure =
  CustomEventEmitter.prototype.fail =
  CustomEventEmitter.prototype.error =
  function(fct) {
    this.on('error', fct)
    return this
  }

  CustomEventEmitter.prototype.done =
  CustomEventEmitter.prototype.complete =
  function(fct) {
    this.on('error', function(err) { fct(err, null) })
        .on('success', function(result) { fct(null, result) })
    return this
  }

  return CustomEventEmitter
})()
<commit_msg>Remove setTimeout in favor of process.nextTick()<commit_after>var util         = require("util")
  , EventEmitter = require("events").EventEmitter

module.exports = (function() {
  var CustomEventEmitter = function(fct) {
    this.fct = fct;
    var self = this;
    process.nextTick(function() {
      if (self.fct) {
        self.fct.call(self, self)
      }
    }.bind(this));
  }
  util.inherits(CustomEventEmitter, EventEmitter)

  CustomEventEmitter.prototype.run = function() {
    var self = this
    return this
  }

  CustomEventEmitter.prototype.success =
  CustomEventEmitter.prototype.ok =
  function(fct) {
    this.on('success', fct)
    return this
  }

  CustomEventEmitter.prototype.failure =
  CustomEventEmitter.prototype.fail =
  CustomEventEmitter.prototype.error =
  function(fct) {
    this.on('error', fct)
    return this
  }

  CustomEventEmitter.prototype.done =
  CustomEventEmitter.prototype.complete =
  function(fct) {
    this.on('error', function(err) { fct(err, null) })
        .on('success', function(result) { fct(null, result) })
    return this
  }

  return CustomEventEmitter
})()
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var tty = require('tty');

var sprintf = require('sprintf').sprintf;

var dots = ['|', '/', '-', '\\'];

/**
 * Display a prompt followed by a little spinning character. Call tick
 * repeatedly to update.
 * @constructor
 * @param {String} prompter The prompt string.
 */
function Spinner(prompter) {
  this.ticks = 0;
  this.promptstr = prompter;
}

/**
 * Start the spinner.
 */
Spinner.prototype.start = function() {
  process.stdout.write('\n' + this.promptstr + '  ');
  this.tick();
};

/**
 * Update the spinner with the given character, internal use only.
 *
 * @param {String} c  The character to set.
 */
Spinner.prototype._update = function(c) {
  process.stdout.write('\b' + c);
};

/**
 * Call this repeatedly to spin the spinner.
 */
Spinner.prototype.tick = function() {
  this.ticks++;
  var c = dots[this.ticks % dots.length];
  this._update(c);
};

/**
 * End the spinner.
 */
Spinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Show a prompt followed by an updating percentage value.
 * @constructor
 * @param {String} prompter The prompt string.
 * @param {Number} max  The value to use for 100%.
 */
function PercentSpinner(prompter, max) {
  this.max = max;
  this.current = 0;
  this.promptstr = prompter;
}

/**
 * Start the spinner.
 */
PercentSpinner.prototype.start = function() {
  process.stdout.write('\n' + this.promptstr + '       ');
  this.tick(0);
};

/**
 * Set the given percentage string, internal use only.
 *
 * @param {String} c  The percentage string to set.
 */
PercentSpinner.prototype._update = function(c) {
  process.stdout.write('\b\b\b\b\b' + c);
};

/**
 * Update the spinner. Call this repeatedly with new values as they become
 * available.
 *
 * @param {Number} value  The current value to set the spinner to.
 */
PercentSpinner.prototype.tick = function(value) {
  this.current = value;
  var p = (this.current / this.max) * 100;
  this._update(sprintf('%4d%%', p));
};

/**
 * End the spinner.
 */
PercentSpinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Show prompt, and on the next line an updating percentage value and bar.
 * @constructor
 * @param {String} prompter The prompt string.
 * @param {Number} max  The value to use for 100%.
 */
function PercentBarSpinner(prompter, max) {
  this.current = 0;
  this.max = max;
  this.promptstr = prompter;
}

/**
 * Start the spinner.
 */
PercentBarSpinner.prototype.start = function() {
  process.stdout.write(this.promptstr + '\n');
  this.tick(0);
};

/**
 * Rewrite the current line, internal use only.
 *
 * @param {String} line The line to update to.
 */
PercentBarSpinner.prototype._update = function(line) {
  process.stdout.write('\r' + line);
};

/**
 * Update the spinner value.
 *
 * @param {Number} value  The new value to use.
 */
PercentBarSpinner.prototype.tick = function(value) {
  this.current = value;
  var bar = this.barstr();
  var val = this.percent();
  this._update(sprintf(' %4d%%', val) + ' [' + this.barstr() + '] ');
};

/**
 * End the spinner.
 */
PercentBarSpinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Get the width to use for the inside of the percentage bar.
 *
 * @return {Number} The width in columns.
 */
PercentBarSpinner.prototype.width = function() {
  var windowSize = tty.getWindowSize();
  var columns = windowSize[1];

  if (!columns || columns <= 0) {
    throw new Error('Unable to determine window size');
  }

  return columns - 10;
};

/**
 * Get the current percentage value.
 *
 * @return {Number} The percentage value.
 */
PercentBarSpinner.prototype.percent = function() {
  return (this.current / this.max) * 100;
};

/**
 * Get the string to use for the inside of the percentage bar.
 *
 * @return {String} The percentage bar string.
 */
PercentBarSpinner.prototype.barstr = function() {
  var width = this.width();
  var p = Math.floor((this.current / this.max) * width);
  if (p >= width) {
    return new Array(width + 1).join('=');
  }
  else {
    var offset = p === 0 ? -1 : 0;
    return new Array(p).join('=') + '>' + new Array(width - p + offset + 1).join(' ');
  }
};

exports.spinner = function(prompter) {
  return new Spinner(prompter);
};

exports.percent = function(prompter, max) {
  return new PercentSpinner(prompter, max);
};

exports.percentbar = function(prompter, max) {
  return new PercentBarSpinner(prompter, max);
};
<commit_msg>Refactor Spinner classes to inherit from the base Spinner class.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var util = require('util');
var tty = require('tty');

var sprintf = require('sprintf').sprintf;

var dots = ['|', '/', '-', '\\'];

/**
 * Display a prompt followed by a little spinning character. Call tick
 * repeatedly to update.
 * @constructor
 * @param {String} prompter The prompt string.
 */
function Spinner(prompter) {
  this.value = 0;
  this.promptstr = prompter;
}

/**
 * Start the spinner.
 */
Spinner.prototype.start = function() {
  process.stdout.write('\n' + this.promptstr + '  ');
  this.tick();
};

/**
 * Update the spinner with the given character, internal use only.
 *
 * @param {String} c  The character to set.
 */
Spinner.prototype._update = function(c) {
  process.stdout.write('\b' + c);
};

/**
 * Call this repeatedly to spin the spinner.
 */
Spinner.prototype.tick = function() {
  this.value++;
  var c = dots[this.value % dots.length];
  this._update(c);
};

/**
 * End the spinner.
 */
Spinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Show a prompt followed by an updating percentage value.
 * @constructor
 * @param {String} prompter The prompt string.
 * @param {Number} max  The value to use for 100%.
 */
function PercentSpinner(prompter, max) {
  Spinner.call(this, prompter);

  this.max = max;
}

util.inherits(PercentSpinner, Spinner);

/**
 * Start the spinner.
 */
PercentSpinner.prototype.start = function() {
  process.stdout.write('\n' + this.promptstr + '       ');
  this.tick(0);
};

/**
 * Set the given percentage string, internal use only.
 *
 * @param {String} c  The percentage string to set.
 */
PercentSpinner.prototype._update = function(c) {
  process.stdout.write('\b\b\b\b\b' + c);
};

/**
 * Update the spinner. Call this repeatedly with new values as they become
 * available.
 *
 * @param {Number} value  The current value to set the spinner to.
 */
PercentSpinner.prototype.tick = function(value) {
  this.value = value;
  var p = (this.value / this.max) * 100;
  this._update(sprintf('%4d%%', p));
};

/**
 * End the spinner.
 */
PercentSpinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Show prompt, and on the next line an updating percentage value and bar.
 * @constructor
 * @param {String} prompter The prompt string.
 * @param {Number} max  The value to use for 100%.
 */
function PercentBarSpinner(prompter, max) {
  Spinner.call(this, prompter);

  this.max = max;
}

util.inherits(PercentSpinner, Spinner);

/**
 * Start the spinner.
 */
PercentBarSpinner.prototype.start = function() {
  process.stdout.write(this.promptstr + '\n');
  this.tick(0);
};

/**
 * Rewrite the current line, internal use only.
 *
 * @param {String} line The line to update to.
 */
PercentBarSpinner.prototype._update = function(line) {
  process.stdout.write('\r' + line);
};

/**
 * Update the spinner value.
 *
 * @param {Number} value  The new value to use.
 */
PercentBarSpinner.prototype.tick = function(value) {
  this.value = value;
  var bar = this.barstr();
  var val = this.percent();
  this._update(sprintf(' %4d%%', val) + ' [' + this.barstr() + '] ');
};

/**
 * End the spinner.
 */
PercentBarSpinner.prototype.end = function() {
  process.stdout.write('\n');
};

/**
 * Get the width to use for the inside of the percentage bar.
 *
 * @return {Number} The width in columns.
 */
PercentBarSpinner.prototype.width = function() {
  var windowSize = tty.getWindowSize();
  var columns = windowSize[1];

  if (!columns || columns <= 0) {
    throw new Error('Unable to determine window size');
  }

  return columns - 10;
};

/**
 * Get the current percentage value.
 *
 * @return {Number} The percentage value.
 */
PercentBarSpinner.prototype.percent = function() {
  return (this.value / this.max) * 100;
};

/**
 * Get the string to use for the inside of the percentage bar.
 *
 * @return {String} The percentage bar string.
 */
PercentBarSpinner.prototype.barstr = function() {
  var width = this.width();
  var p = Math.floor((this.value / this.max) * width);
  if (p >= width) {
    return new Array(width + 1).join('=');
  }
  else {
    var offset = p === 0 ? -1 : 0;
    return new Array(p).join('=') + '>' + new Array(width - p + offset + 1).join(' ');
  }
};

exports.spinner = function(prompter) {
  return new Spinner(prompter);
};

exports.percent = function(prompter, max) {
  return new PercentSpinner(prompter, max);
};

exports.percentbar = function(prompter, max) {
  return new PercentBarSpinner(prompter, max);
};
<|endoftext|>


<commit_before>"use strict";

var commonmark = require("commonmark");

function markdownTransform(mimetype, data, document) {
    var div = document.createElement("div");

    let reader = new commonmark.Parser();
    let writer = new commonmark.HtmlRenderer({
        safe: true
    });

    var parsed = reader.parse(data);

    // TODO: Any other transformations on the parsed object
    // See https://github.com/jgm/commonmark.js#usage

    div.innerHTML = writer.render(parsed);

    return div;
}

markdownTransform.mimetype = 'text/markdown';

export default markdownTransform;
<commit_msg>Stick reader and writer in a closure.<commit_after>"use strict";

var commonmark = require("commonmark");

var markdownTransform = function(){
    let reader = new commonmark.Parser();
    let writer = new commonmark.HtmlRenderer({
        safe: true
    });

    return function(mimetype, data, document) {
        var div = document.createElement("div");

        var parsed = reader.parse(data);

        // TODO: Any other transformations on the parsed object
        // See https://github.com/jgm/commonmark.js#usage

        div.innerHTML = writer.render(parsed);

        return div;
    };
}();

markdownTransform.mimetype = 'text/markdown';

export default markdownTransform;
<|endoftext|>


<commit_before>'use strict';

var
  fs,
  tmp,
  path,
  shell,
  logger,
  readline,
  spawnSync,
  initFlagName;

fs = require('fs');
tmp = require('tmp');
path = require('path');
shell = require('shelljs');
readline = require('readline-sync');
spawnSync = require('child_process').spawnSync;

logger = require('./logger.js');

// Clean temp on exception.
tmp.setGracefulCleanup();

exports.checkRequirements = function () {
  var
    required,
    requirement;

  required = {
    'VBoxManage': "VirtualBox doesn't appear to be installed. Please see https://www.virtualbox.org/wiki/Downloads for installation instructions.",
    'brew': "Homebrew doesn't appear to be installed. Please see http://brew.sh/ for installation instructions.",
    'dinghy': "dinghy is not installed. Please see https://github.com/chinthakagodawita/homebrew-dh for more info."
  };

  // Make sure we have each requirement.
  for (requirement in required) {
    if (shell.which(requirement) === null) {
      throw new Error(required[requirement]);
    }
  }
};

exports.getYargsContainerInfo = function (yargs, cmd) {
  var
    name,
    subArgv,
    sources;

  subArgv = yargs.usage('dh soe ' + cmd + ' <container name> [options]')
  .option('s', {
    alias: 'sources',
    description: 'Directory to use for sources, defaults to the current directory'
  })
  .help('help')
  .argv;

  if (!subArgv._[1]) {
    name = null;
  }
  else {
    name = subArgv._[1];
  }

  if (!subArgv.s) {
    sources = shell.pwd();
  }

  return {
    'name': name,
    'sources': sources
  };
};

exports.runSubscript = function (scriptname, yargs) {
  var
    args,
    scriptPath;

  // Pass all other arguments to sub-script.
  args = yargs.argv._.slice(1);

  // Pass the help & debug flags through if it exists too.
  if (yargs.argv.help || yargs.argv.h) {
    args = ['--help'].concat(args);
  }
  if (yargs.argv.debug || yargs.argv.d) {
    args.push('-d');
  }

  scriptPath = path.resolve(__dirname, '..', '..', 'bin', scriptname + '.js');
  spawnSync(scriptPath, args, {
    cwd: process.cwd(),
    stdio: 'inherit'
  })
};

exports.shell = function (cmd, args, opts) {
  if (typeof args === 'undefined') {
    args = [];
  }
  if (typeof opts === 'undefined') {
    opts = {};
  }

  if (typeof args === 'string') {
    args = [args];
  }

  if (args) {
    cmd += ' ' + args.join(' ');
  }

  logger.debug('Executing: ' + cmd);

  // @TODO: check return code and throw Error with message if >0.
  return shell.exec(cmd, opts);
};

exports.getHomeDir = function () {
  return process.env.HOME || process.env.USERPROFILE;
};

exports.confirm = function (msg) {
  var
    confirm;

  confirm = null;

  // Prompt while we get valid output.
  while (confirm !== false && confirm !== true) {
    confirm = readline.question(msg, {
      trueValue: 'y',
      falseValue: 'n'
    });
  }

  return confirm;
};

exports.promptList = function (msg, opts) {
  var
    index;

  index = readline.keyInSelect(opts, msg);

  if (index === -1) {
    logger.error('User cancelled exection.');
    process.exit(1);
  }

  return opts[index];
};

exports.isEmptyObject = function (obj) {
  return !Object.keys(obj).length;
}

exports.writeTempFile = function (data) {
  var
    tempFile;

  tempFile = tmp.tmpNameSync();
  fs.writeFileSync(tempFile, data);
  return tempFile;
}

exports.getMacVersion = function () {
  var
    out,
    version,
    versionParts;

  out = this.shell('sw_vers', ['-productVersion'], {
    silent: true
  });

  if (out.code !== 0) {
    throw new Error('Could not determine OS X version.');
  }

  versionParts = out.output.trim().match(/([0-9]+).([0-9]+).([0-9]+)/);
  version = [
    parseInt(versionParts[1], 10),
    parseInt(versionParts[2], 10)
  ];
  if (versionParts[3])  {
    version.push(parseInt(versionParts[3], 10));
  }

  return version;
};
<commit_msg>Fixed bug where not all flags were being passed to sub-scripts.<commit_after>'use strict';

var
  fs,
  tmp,
  path,
  shell,
  logger,
  readline,
  spawnSync,
  initFlagName;

fs = require('fs');
tmp = require('tmp');
path = require('path');
shell = require('shelljs');
readline = require('readline-sync');
spawnSync = require('child_process').spawnSync;

logger = require('./logger.js');

// Clean temp on exception.
tmp.setGracefulCleanup();

exports.checkRequirements = function () {
  var
    required,
    requirement;

  required = {
    'VBoxManage': "VirtualBox doesn't appear to be installed. Please see https://www.virtualbox.org/wiki/Downloads for installation instructions.",
    'brew': "Homebrew doesn't appear to be installed. Please see http://brew.sh/ for installation instructions.",
    'dinghy': "dinghy is not installed. Please see https://github.com/chinthakagodawita/homebrew-dh for more info."
  };

  // Make sure we have each requirement.
  for (requirement in required) {
    if (shell.which(requirement) === null) {
      throw new Error(required[requirement]);
    }
  }
};

exports.getYargsContainerInfo = function (yargs, cmd) {
  var
    name,
    subArgv,
    sources;

  subArgv = yargs.usage('dh soe ' + cmd + ' <container name> [options]')
  .option('s', {
    alias: 'sources',
    description: 'Directory to use for sources, defaults to the current directory'
  })
  .help('help')
  .argv;

  if (!subArgv._[1]) {
    name = null;
  }
  else {
    name = subArgv._[1];
  }

  if (!subArgv.s) {
    sources = shell.pwd();
  }

  return {
    'name': name,
    'sources': sources
  };
};

exports.runSubscript = function (scriptname, yargs) {
  var
    args,
    scriptPath;

  // Pass all other arguments to sub-script.
  args = yargs.argv._.slice(1);

  // Pass help in as the first flag if set.
  if (yargs.argv.help || yargs.argv.h) {
    args = ['--help'].concat(args);

    if (yargs.argv.help) {
      delete yargs.argv.help;
    }
    if (yargs.argv.h) {
      delete yargs.argv.h;
    }
  }

  // Pass all other valid flags through to the sub-script too.
  for (var flag in yargs.argv) {
    var flagType = '-';
    if (flag.indexOf('$') > -1 || flag == '_' || flag == 'h' || flag == 'help') {
      continue;
    }

    if (flag.length > 1) {
      flagType = '--';
    }
    args.push(flagType + flag + '=' + yargs.argv[flag]);
  }

  scriptPath = path.resolve(__dirname, '..', '..', 'bin', scriptname + '.js');
  spawnSync(scriptPath, args, {
    cwd: process.cwd(),
    stdio: 'inherit'
  })
};

exports.shell = function (cmd, args, opts) {
  if (typeof args === 'undefined') {
    args = [];
  }
  if (typeof opts === 'undefined') {
    opts = {};
  }

  if (typeof args === 'string') {
    args = [args];
  }

  if (args) {
    cmd += ' ' + args.join(' ');
  }

  logger.debug('Executing: ' + cmd);

  // @TODO: check return code and throw Error with message if >0.
  return shell.exec(cmd, opts);
};

exports.getHomeDir = function () {
  return process.env.HOME || process.env.USERPROFILE;
};

exports.confirm = function (msg) {
  var
    confirm;

  confirm = null;

  // Prompt while we get valid output.
  while (confirm !== false && confirm !== true) {
    confirm = readline.question(msg, {
      trueValue: 'y',
      falseValue: 'n'
    });
  }

  return confirm;
};

exports.promptList = function (msg, opts) {
  var
    index;

  index = readline.keyInSelect(opts, msg);

  if (index === -1) {
    logger.error('User cancelled exection.');
    process.exit(1);
  }

  return opts[index];
};

exports.isEmptyObject = function (obj) {
  return !Object.keys(obj).length;
}

exports.writeTempFile = function (data) {
  var
    tempFile;

  tempFile = tmp.tmpNameSync();
  fs.writeFileSync(tempFile, data);
  return tempFile;
}

exports.getMacVersion = function () {
  var
    out,
    version,
    versionParts;

  out = this.shell('sw_vers', ['-productVersion'], {
    silent: true
  });

  if (out.code !== 0) {
    throw new Error('Could not determine OS X version.');
  }

  versionParts = out.output.trim().match(/([0-9]+).([0-9]+).([0-9]+)/);
  version = [
    parseInt(versionParts[1], 10),
    parseInt(versionParts[2], 10)
  ];
  if (versionParts[3])  {
    version.push(parseInt(versionParts[3], 10));
  }

  return version;
};
<|endoftext|>