<commit_before>var Gettext = require("node-gettext")
  , plurals = require("./plurals")
  , flatten = require("./flatten")
  , fs = require("fs")
  , path = require("path")
  , colors = require("colors")
  , mkdirp = require('mkdirp');

var gt = new Gettext();

module.exports = {

    process: function(domain, source, target, options, callback) {
        var ext = path.extname(source);

        if (options.plurals) {
                var plurals_path = path.join(process.cwd(), options.plurals);
                plurals.rules = require(plurals_path);
                if (!options.quiet) console.log(('\nuse custom plural forms ' + plurals_path + '\n').blue);
        }

        if (ext === '.mo' || ext === '.po') {
            return this.gettextToI18next(domain, source, target, options, callback);
        }

        if (ext === '.json') {
            return this.i18nextToGettext(domain, source, target, options, callback);
        }
    },

    /***************************
    *
    * I18NEXT JSON --> GETTEXT
    *
    ***************************/
    i18nextToGettext: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        if(!fs.existsSync(target)){
            mkdirp.sync(path.dirname(target));
        }

        var dirname = path.dirname(source)
          , ext = path.extname(source)
          , filename = path.basename(source, ext);

        if(!fs.existsSync(target)){
          mkdirp.sync(path.dirname(target));
        }

        if (!target) {
            var dir;
            if (dirname.indexOf(domain) === dirname.length - domain.length) {
                dir = path.join(dirname);
                target = path.join(dirname, filename + '.po');
            } else {
                dir = path.join(dirname, domain);
                target = path.join(dirname, domain, filename + '.po');
            }

            if (!fs.statSync(dir)) fs.mkdirSync(dir);

        }

        self.i18nextToGettextData(domain, source, target, options, function(err, data) {
            self.writeFile(target, data, options, callback);
        });
    },

    i18nextToGettextData: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        self.flattenI18nextJSON(source, options, function(err, flat) {
            self.parseGettext(domain, flat, options, function(err, gt) {
                var data = path.extname(target) === '.po' ? gt.compilePO(domain) : gt.compileMO(domain);
                if (typeof callback === 'function') {
                    callback(err, data);
                }
            });
        });
    },

    /* i18next json --> flat json
     *
     */
    flattenI18nextJSON: function(source, options, callback) {
        if (!options.quiet) console.log(('\n    --> reading file from: ' + source));

        fs.readFile(source, function(err, body) {
            if(err) {
                if (typeof callback === 'function') {
                    callback(err);
                }
                return;
            }

            var flat = flatten.flatten(JSON.parse(body), options);
            if (typeof callback === 'function') {
                callback(null, flat);
            }
        });
    },

    /* flat json --> gettext
     *
     */
    parseGettext: function(domain, data, options, callback) {
        var gt = new Gettext();
        gt.addTextdomain(domain, '');

        var ext = plurals.rules[domain.split('-')[0]];

        if (!options.quiet) console.log('\n    <-> parsing data to gettext format'.cyan);

        for (var m in data) {
            var kv = data[m];

            if (kv.plurals) {
                var pArray = [];

                for (var i = 0, len = kv.plurals.length; i < len; i++) {
                    var plural = kv.plurals[i];
                    pArray.splice(this.getGettextPluralPosition(ext, plural.pluralNumber), 0, plural.value);

                }

                pArray.splice(this.getGettextPluralPosition(0,0), 0, kv.value);
                gt.setTranslation(domain, kv.context, kv.key, pArray);
            } else {
                gt.setTranslation(domain, kv.context, kv.key, kv.value);
            }
        }
        if (typeof callback === 'function') {
            callback(null, gt);
        }
    },

    /* helper to get plural suffix
     *
     */
    getGettextPluralPosition: function(ext, suffix) {
        if (ext) {
            if (ext.numbers.length === 2) {

                if (suffix === '-1') { // regular plural
                    suffix = '1';
                } else if (suffix === '1') { // singular
                    suffix = '2';

                }
            }

            for (var i = 0, len = ext.numbers.length; i < len; i++) {
                if (ext.numbers[i].toString() === suffix) {
                    return i;
                }
            }
        }

        return -1;
    },

    /***************************
    *
    * GETTEXT --> I18NEXT JSON
    *
    ***************************/
    gettextToI18next: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        var dirname = path.dirname(source)
          , ext = path.extname(source)
          , filename = path.basename(source, ext);

        if(!fs.existsSync(target)){
            mkdirp.sync(path.dirname(target));
        }

        if (!target) {
            var dir;
            if (dirname.indexOf(domain) === dirname.length - domain.length) {
                dir = path.join(dirname);
                target = path.join(dirname, filename + '.json');
            } else {
                dir = path.join(dirname, domain);
                target = path.join(dirname, domain, filename + '.json');
            }

            if (!fs.statSync(dir)) fs.mkdirSync(dir);
        }

        self.gettextToI18nextData(domain, source, options, function(err, data) {
            self.writeFile(target, data, options, callback);
        });
    },

    gettextToI18nextData: function(domain, source, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        self.addTextDomain(domain, source, options, function(err, data) {
            self.parseJSON(domain, data, options, function(err, json) {
                var jsonData = JSON.stringify(json, null, 4);
                if (typeof callback === 'function') {
                   callback(err, jsonData);
                }
            });
        });
    },

    /* gettext --> barebone json
     *
     */
    addTextDomain: function(domain, source, options, callback) {
        if (!options.quiet) console.log(('\n    --> reading file from: ' + source));

        fs.readFile(source, function(err, body) {
            if(err) {
                if (typeof callback === 'function') {
                    callback(err);
                }

                return;
            }

            gt.addTextdomain(domain, body);

            if (options.filter) {
                options.filter(gt, domain, callback);
            } else {
                if (typeof callback === 'function'){
                    callback(null, gt._domains[domain]._translationTable);
                }
            }
        });
    },

    /* barebone json --> i18next json
     *
     */
    parseJSON: function(domain, data, options, callback) {
        var separator = options.keyseparator || '##';

        if (!options.quiet) console.log('\n    <-> parsing data to i18next json format'.cyan);
        var json = {};

        var toArrayIfNeeded = function(value) {
            var ret = value;
            if (ret.indexOf('\n') > -1) ret = ret.split('\n');
            return ret;
        };

        for (var m in data) {
            var context = data[m];

            for (var key in context) {
                var appendTo = json
                  , targetKey = key;

                if (key.indexOf(separator) > -1) {
                    var keys = key.split(separator);

                    var x = 0;
                    while (keys[x]) {
                        if (x < keys.length - 1) {
                            appendTo[keys[x]] = appendTo[keys[x]] || {};
                            appendTo = appendTo[keys[x]];
                        } else {
                            targetKey = keys[x];
                        }
                        x++;
                    }
                }

                var values = context[key];

                if (m !== '') targetKey = targetKey + '_' + m;

                if (values.length === 1) {
                    appendTo[targetKey] = toArrayIfNeeded(values[0]);
                } else {
                    var ext = plurals.rules[domain.split('-')[0]];

                    for (var i = 0, len = values.length; i < len; i++) {
                        var pluralSuffix = this.getI18nextPluralExtension(ext, i);
                        var pkey = targetKey + pluralSuffix;

                        appendTo[pkey] = toArrayIfNeeded(values[i]);
                    }
                }
            }

        }
        if (typeof callback === 'function'){
            callback(null, json);
        }
    },

    /* helper to get plural suffix
     *
     */
    getI18nextPluralExtension: function(ext, i) {
        if (ext) {
            var number = ext.numbers[i];
            if (ext.numbers.length === 2) {
                if (ext.numbers.length === 2) {
                    // germanic like en
                    if (ext.numbers[0] === 2) {
                        if (number === 2) {
                            number = 1; // singular
                        } else if (number === 1) {
                            number = -1; // regular plural
                        }
                    }
                    // romanic like fr
                    else if (ext.numbers[0] === 1) {
                        if (number === 2) {
                            number = -1; // regular plural
                        } else if (number === 1) {
                            number = 1; // singular
                        }
                    }
                }
                return number > 0 ? '' : '_plural';
            } else {
                return number === 1 ? '' : '_plural_' + number; // suffix all but singular
            }
        } else {
            return i === 1 ? '' : '_plural';
        }
    },

    /***************************
    *
    * SHARED
    *
    ***************************/
    writeFile: function(target, data, options, callback) {
        if (!options.quiet) console.log(('\n    <-- writing file to: ' + target));
        fs.writeFile(target, data, function(err) {
            if (typeof callback === 'function') {
                callback(err);
            }
        });
    }
};
<commit_msg>fix wrong index when path name contains the domain<commit_after>var Gettext = require("node-gettext")
  , plurals = require("./plurals")
  , flatten = require("./flatten")
  , fs = require("fs")
  , path = require("path")
  , colors = require("colors")
  , mkdirp = require('mkdirp');

var gt = new Gettext();

module.exports = {

    process: function(domain, source, target, options, callback) {
        var ext = path.extname(source);

        if (options.plurals) {
                var plurals_path = path.join(process.cwd(), options.plurals);
                plurals.rules = require(plurals_path);
                if (!options.quiet) console.log(('\nuse custom plural forms ' + plurals_path + '\n').blue);
        }

        if (ext === '.mo' || ext === '.po') {
            return this.gettextToI18next(domain, source, target, options, callback);
        }

        if (ext === '.json') {
            return this.i18nextToGettext(domain, source, target, options, callback);
        }
    },

    /***************************
    *
    * I18NEXT JSON --> GETTEXT
    *
    ***************************/
    i18nextToGettext: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        if(!fs.existsSync(target)){
            mkdirp.sync(path.dirname(target));
        }

        var dirname = path.dirname(source)
          , ext = path.extname(source)
          , filename = path.basename(source, ext);

        if(!fs.existsSync(target)){
          mkdirp.sync(path.dirname(target));
        }

        if (!target) {
            var dir;
            if (dirname.lastIndexOf(domain) === dirname.length - domain.length) {
                dir = path.join(dirname);
                target = path.join(dirname, filename + '.po');
            } else {
                dir = path.join(dirname, domain);
                target = path.join(dirname, domain, filename + '.po');
            }

            if (!fs.statSync(dir)) fs.mkdirSync(dir);

        }

        self.i18nextToGettextData(domain, source, target, options, function(err, data) {
            self.writeFile(target, data, options, callback);
        });
    },

    i18nextToGettextData: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        self.flattenI18nextJSON(source, options, function(err, flat) {
            self.parseGettext(domain, flat, options, function(err, gt) {
                var data = path.extname(target) === '.po' ? gt.compilePO(domain) : gt.compileMO(domain);
                if (typeof callback === 'function') {
                    callback(err, data);
                }
            });
        });
    },

    /* i18next json --> flat json
     *
     */
    flattenI18nextJSON: function(source, options, callback) {
        if (!options.quiet) console.log(('\n    --> reading file from: ' + source));

        fs.readFile(source, function(err, body) {
            if(err) {
                if (typeof callback === 'function') {
                    callback(err);
                }
                return;
            }

            var flat = flatten.flatten(JSON.parse(body), options);
            if (typeof callback === 'function') {
                callback(null, flat);
            }
        });
    },

    /* flat json --> gettext
     *
     */
    parseGettext: function(domain, data, options, callback) {
        var gt = new Gettext();
        gt.addTextdomain(domain, '');

        var ext = plurals.rules[domain.split('-')[0]];

        if (!options.quiet) console.log('\n    <-> parsing data to gettext format'.cyan);

        for (var m in data) {
            var kv = data[m];

            if (kv.plurals) {
                var pArray = [];

                for (var i = 0, len = kv.plurals.length; i < len; i++) {
                    var plural = kv.plurals[i];
                    pArray.splice(this.getGettextPluralPosition(ext, plural.pluralNumber), 0, plural.value);

                }

                pArray.splice(this.getGettextPluralPosition(0,0), 0, kv.value);
                gt.setTranslation(domain, kv.context, kv.key, pArray);
            } else {
                gt.setTranslation(domain, kv.context, kv.key, kv.value);
            }
        }
        if (typeof callback === 'function') {
            callback(null, gt);
        }
    },

    /* helper to get plural suffix
     *
     */
    getGettextPluralPosition: function(ext, suffix) {
        if (ext) {
            if (ext.numbers.length === 2) {

                if (suffix === '-1') { // regular plural
                    suffix = '1';
                } else if (suffix === '1') { // singular
                    suffix = '2';

                }
            }

            for (var i = 0, len = ext.numbers.length; i < len; i++) {
                if (ext.numbers[i].toString() === suffix) {
                    return i;
                }
            }
        }

        return -1;
    },

    /***************************
    *
    * GETTEXT --> I18NEXT JSON
    *
    ***************************/
    gettextToI18next: function(domain, source, target, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        var dirname = path.dirname(source)
          , ext = path.extname(source)
          , filename = path.basename(source, ext);

        if(!fs.existsSync(target)){
            mkdirp.sync(path.dirname(target));
        }

        if (!target) {
            var dir;
            if (dirname.lastIndexOf(domain) === dirname.length - domain.length) {
                dir = path.join(dirname);
                target = path.join(dirname, filename + '.json');
            } else {
                dir = path.join(dirname, domain);
                target = path.join(dirname, domain, filename + '.json');
            }

            if (!fs.statSync(dir)) fs.mkdirSync(dir);
        }

        self.gettextToI18nextData(domain, source, options, function(err, data) {
            self.writeFile(target, data, options, callback);
        });
    },

    gettextToI18nextData: function(domain, source, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = {};
        }

        var self = this;

        self.addTextDomain(domain, source, options, function(err, data) {
            self.parseJSON(domain, data, options, function(err, json) {
                var jsonData = JSON.stringify(json, null, 4);
                if (typeof callback === 'function') {
                   callback(err, jsonData);
                }
            });
        });
    },

    /* gettext --> barebone json
     *
     */
    addTextDomain: function(domain, source, options, callback) {
        if (!options.quiet) console.log(('\n    --> reading file from: ' + source));

        fs.readFile(source, function(err, body) {
            if(err) {
                if (typeof callback === 'function') {
                    callback(err);
                }

                return;
            }

            gt.addTextdomain(domain, body);

            if (options.filter) {
                options.filter(gt, domain, callback);
            } else {
                if (typeof callback === 'function'){
                    callback(null, gt._domains[domain]._translationTable);
                }
            }
        });
    },

    /* barebone json --> i18next json
     *
     */
    parseJSON: function(domain, data, options, callback) {
        var separator = options.keyseparator || '##';

        if (!options.quiet) console.log('\n    <-> parsing data to i18next json format'.cyan);
        var json = {};

        var toArrayIfNeeded = function(value) {
            var ret = value;
            if (ret.indexOf('\n') > -1) ret = ret.split('\n');
            return ret;
        };

        for (var m in data) {
            var context = data[m];

            for (var key in context) {
                var appendTo = json
                  , targetKey = key;

                if (key.indexOf(separator) > -1) {
                    var keys = key.split(separator);

                    var x = 0;
                    while (keys[x]) {
                        if (x < keys.length - 1) {
                            appendTo[keys[x]] = appendTo[keys[x]] || {};
                            appendTo = appendTo[keys[x]];
                        } else {
                            targetKey = keys[x];
                        }
                        x++;
                    }
                }

                var values = context[key];

                if (m !== '') targetKey = targetKey + '_' + m;

                if (values.length === 1) {
                    appendTo[targetKey] = toArrayIfNeeded(values[0]);
                } else {
                    var ext = plurals.rules[domain.split('-')[0]];

                    for (var i = 0, len = values.length; i < len; i++) {
                        var pluralSuffix = this.getI18nextPluralExtension(ext, i);
                        var pkey = targetKey + pluralSuffix;

                        appendTo[pkey] = toArrayIfNeeded(values[i]);
                    }
                }
            }

        }
        if (typeof callback === 'function'){
            callback(null, json);
        }
    },

    /* helper to get plural suffix
     *
     */
    getI18nextPluralExtension: function(ext, i) {
        if (ext) {
            var number = ext.numbers[i];
            if (ext.numbers.length === 2) {
                if (ext.numbers.length === 2) {
                    // germanic like en
                    if (ext.numbers[0] === 2) {
                        if (number === 2) {
                            number = 1; // singular
                        } else if (number === 1) {
                            number = -1; // regular plural
                        }
                    }
                    // romanic like fr
                    else if (ext.numbers[0] === 1) {
                        if (number === 2) {
                            number = -1; // regular plural
                        } else if (number === 1) {
                            number = 1; // singular
                        }
                    }
                }
                return number > 0 ? '' : '_plural';
            } else {
                return number === 1 ? '' : '_plural_' + number; // suffix all but singular
            }
        } else {
            return i === 1 ? '' : '_plural';
        }
    },

    /***************************
    *
    * SHARED
    *
    ***************************/
    writeFile: function(target, data, options, callback) {
        if (!options.quiet) console.log(('\n    <-- writing file to: ' + target));
        fs.writeFile(target, data, function(err) {
            if (typeof callback === 'function') {
                callback(err);
            }
        });
    }
};
<|endoftext|>


<commit_before>angular.module("umbraco").controller("Umbraco.Dialogs.LoginController", function ($scope, userService, legacyJsLoader, $routeParams) {

    /**
     * @ngdoc function
     * @name signin
     * @methodOf MainController
     * @function
     *
     * @description
     * signs the user in
     */
    var d = new Date();
    var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderfull Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday");

    $scope.today = weekday[d.getDay()];
    $scope.errorMsg = "";

    $scope.loginSubmit = function (login, password) {

        //if the login and password are not empty we need to automatically
        // validate them - this is because if there are validation errors on the server
        // then the user has to change both username & password to resubmit which isn't ideal,
        // so if they're not empty , we'l just make sure to set them to valid.
        if (login && password && login.length > 0 && password.length > 0) {
            $scope.loginForm.username.$setValidity('auth', true);
            $scope.loginForm.password.$setValidity('auth', true);
        }

        if ($scope.loginForm.$invalid) {
            return;
        }

        userService.authenticate(login, password)
            .then(function (data) {

                var iframe = $("#right");
                if (iframe) {
                    var url = decodeURIComponent($routeParams.url);
                    if (!url) {
                        url = "dashboard.aspx";
                    }
                    iframe.attr("src", url);
                }

                $scope.submit(true);

            }, function (reason) {
                $scope.errorMsg = reason.errorMsg;

                //set the form inputs to invalid
                $scope.loginForm.username.$setValidity("auth", false);
                $scope.loginForm.password.$setValidity("auth", false);
            });

        //setup a watch for both of the model values changing, if they change
        // while the form is invalid, then revalidate them so that the form can
        // be submitted again.
        $scope.loginForm.username.$viewChangeListeners.push(function () {
            if ($scope.loginForm.username.$invalid) {
                $scope.loginForm.username.$setValidity('auth', true);
            }
        });
        $scope.loginForm.password.$viewChangeListeners.push(function () {
            if ($scope.loginForm.password.$invalid) {
                $scope.loginForm.password.$setValidity('auth', true);
            }
        });
    };
});<commit_msg>After 2 hours of debugging finally figured out the login controller is trying to manually set the iframe url... !?<commit_after>angular.module("umbraco").controller("Umbraco.Dialogs.LoginController", function ($scope, userService, legacyJsLoader, $routeParams) {

    /**
     * @ngdoc function
     * @name signin
     * @methodOf MainController
     * @function
     *
     * @description
     * signs the user in
     */
    var d = new Date();
    var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderfull Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday");

    $scope.today = weekday[d.getDay()];
    $scope.errorMsg = "";

    $scope.loginSubmit = function (login, password) {

        //if the login and password are not empty we need to automatically
        // validate them - this is because if there are validation errors on the server
        // then the user has to change both username & password to resubmit which isn't ideal,
        // so if they're not empty , we'l just make sure to set them to valid.
        if (login && password && login.length > 0 && password.length > 0) {
            $scope.loginForm.username.$setValidity('auth', true);
            $scope.loginForm.password.$setValidity('auth', true);
        }

        if ($scope.loginForm.$invalid) {
            return;
        }

        userService.authenticate(login, password)
            .then(function (data) {
                $scope.submit(true);
            }, function (reason) {
                $scope.errorMsg = reason.errorMsg;

                //set the form inputs to invalid
                $scope.loginForm.username.$setValidity("auth", false);
                $scope.loginForm.password.$setValidity("auth", false);
            });

        //setup a watch for both of the model values changing, if they change
        // while the form is invalid, then revalidate them so that the form can
        // be submitted again.
        $scope.loginForm.username.$viewChangeListeners.push(function () {
            if ($scope.loginForm.username.$invalid) {
                $scope.loginForm.username.$setValidity('auth', true);
            }
        });
        $scope.loginForm.password.$viewChangeListeners.push(function () {
            if ($scope.loginForm.password.$invalid) {
                $scope.loginForm.password.$setValidity('auth', true);
            }
        });
    };
});<|endoftext|>


<commit_before>var Controller = require( 'clever-controller' )
  , EventEmitter = require( 'events' ).EventEmitter
  , uberUtil = require( 'utils' ).uberUtil;

module.exports = Controller.extend(
/* @Static */
{
    app: require( 'injector' ).getInstance( 'app' ),
    service: null
},
/* @Prototype */
{
    listAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .findAll( this.req.query )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    getAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .findById( this.req.params.id )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    postAction: function() {
        if ( !!this.req.body.id || !!this.req.params.id ) {
            this.action = 'putAction';
            if ( !this.req.params.id ) {
                this.req.params.id = this.req.body.id;
                delete this.req.body.id;
            }
            return this.putAction();
        } else if ( this.Class.service !== null ) {
            this.Class
                .service
                .create( this.req.body )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    putAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .update( this.req.params.id, this.req.body )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    deleteAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .destroy( this.req.params.id )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    handleServiceMessage: function( obj ) {
        if ( obj.statuscode ) {
            this.send( obj.message, obj.statuscode );
            return;
        }

        this.send( obj, 200 );
    }
});<commit_msg>hotfix(controller): Fixed issue where it would not list by id<commit_after>var Controller = require( 'clever-controller' )
  , EventEmitter = require( 'events' ).EventEmitter
  , uberUtil = require( 'utils' ).uberUtil;

module.exports = Controller.extend(
/* @Static */
{
    app: require( 'injector' ).getInstance( 'app' ),
    service: null
},
/* @Prototype */
{
    listAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .findAll( this.req.query )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    getAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .find( this.req.params.id )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    postAction: function() {
        if ( !!this.req.body.id || !!this.req.params.id ) {
            this.action = 'putAction';
            if ( !this.req.params.id ) {
                this.req.params.id = this.req.body.id;
                delete this.req.body.id;
            }
            return this.putAction();
        } else if ( this.Class.service !== null ) {
            this.Class
                .service
                .create( this.req.body )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    putAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .update( this.req.params.id, this.req.body )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    deleteAction: function() {
        if ( this.Class.service !== null ) {
            this.Class
                .service
                .destroy( this.req.params.id )
                .then( this.proxy( 'handleServiceMessage' ) )
                .catch( this.proxy( 'handleException' ) );
        } else {
            this.next();
        }
    },

    handleServiceMessage: function( obj ) {
        if ( obj.statuscode ) {
            this.send( obj.message, obj.statuscode );
            return;
        }

        this.send( obj, 200 );
    }
});<|endoftext|>


<commit_before>const {Lexer} = require('./Lexer');
const {INIT, OPEN_TAG, CLOSE_TAG, END_TAG, TAGNAME, TAG, EXPR, TEXT, ATTR, EQUAL, VALUE, EOF} = require('./StateTypes');
const {Program, If, For, Element, Attribute, Expression, Text, Types} = require('./NodeTypes');
const {Expression: expression} = require('./Expression');

const IF_ATTR = 'd:if';
const ELSE_ATTR = 'd:else';
const ELSE_IF_ATTR = 'd:elif';
const FOR_ATTR = 'd:for';
const FOR_ITEM_ATTR = 'd:for-item';
const FOR_ITEM_INDEX_ATTR = 'd:for-index';

function Parser(source) {
    const tokens = Lexer(source);
    const {code, message} = isTagClosed(tokens);
    if (code !== 0) {
        throw message;
    }

    let pos = 0;

    return Program(program(tokens));

    function ll(k = 0) {
        pos += k;

        if (pos > tokens.length - 1){
            return tokens[tokens.length-1];
        }

        return tokens[pos];
    }

    function la(...args) {
        return ll(...args).type;
    }

    function program() {
        return package(type => type !== END_TAG && type !== EOF);
    }

    function package(condition) {
        const body = [];
        while (
            condition(la())
        ) {
            const node = recurse(body);

            if (node) {
                body.push(node);
            }
        }
        return body;
    }

    function recurse(nodes) {
        const token = ll();
        const {type} = token;
        switch (type) {
        case TAGNAME:
            return element(nodes);
        case TEXT:
            return text();
        case EXPR:
            return expr();
        }
    }

    function text() {
        const {content} = ll();
        next();
        return Text(content);
    }

    function element(nodes) {
        const {content} = ll();

        next();

        let children, directives;
        let attrNodes = attrs();

        const refs = regenerateAttrs(attrNodes);
        attrNodes = refs.attrs;
        directives = refs.directives;

        if (!isVoidTag(content)) {
            children = program();
        }

        let element = Element(
            content, attrNodes, children
        );

        const ifNodeList = nodes.filter(({type}) => {
            return type === Types.If;
        });

        const lastIfNode = ifNodeList[ifNodeList.length - 1];

        element = wrapElseStatement(element, directives, lastIfNode);

        element = wrapIfStatement(element, directives);

        element = wrapForStatement(element, directives);

        eat(END_TAG);

        return element;
    }

    function wrapElseStatement (element, directives, lastIfNode) {
        let elseIfValue = directives[ELSE_IF_ATTR];

        const keys = Object.keys(directives);

        if (lastIfNode) {
            // find the empty consequent
            while (lastIfNode.consequent) {
                lastIfNode = lastIfNode.consequent;
            }

            if (~keys.indexOf(ELSE_ATTR)) {
                lastIfNode.consequent = element;
                return null;
            } else if (elseIfValue) {
                lastIfNode.consequent = If(Expression(expression(elseIfValue)), element);
                return null;
            }
        }

        return element;
    }

    function wrapIfStatement(element, directives) {
        let value = directives[IF_ATTR];
        if (value) {
            return If(Expression(expression(value)), element);
        }
        return element;
    }

    function wrapForStatement(element, directives) {
        let value = directives[FOR_ATTR];
        if (value) {
            return For(Expression(expression(value)), {
                item: directives[FOR_ITEM_ATTR],
                index: directives[FOR_ITEM_INDEX_ATTR],
            }, element);
        }
        return element;
    }

    function regenerateAttrs(attrNodes) {
        const attrs = [];
        const directives = {};

        for (let attr of attrNodes) {
            const {name, value} = attr;
            if (~name.indexOf('d:')) {
                Object.assign(directives, ({
                    [name]: value || ''
                }));
            } else {
                attrs.push(attr);
            }
        }

        return {
            attrs, directives
        };
    }

    function expr() {
        const expr = ll();
        next();
        return Expression(expression(expr.content));
    }

    function attrs() {
        const attrs = [];
        while (la() === ATTR) {
            const name = ll().content;
            next();
            const value = eat(VALUE).content;

            const attr = Attribute(name, value);
            attrs.push(attr);
        }
        return attrs;
    }

    function next() {
        pos ++;
    }

    function eat(type) {
        let matched = {};
        if (la() === type) {
            matched = ll();
        }
        next();
        return matched;
    }
}

function isTagClosed(tokens) {
    let stack = [];
    let i = 0;
    while( i < tokens.length) {
        const token = tokens[i];
        const {type, content} = token;
        if (type === TAGNAME &&
            !isVoidTag(content)) {
            stack.push(token);
        } else if (type === END_TAG) {
            const stackTop = stack[stack.length - 1];
            const {line, column} = stackTop;
            if (stackTop.content === content) {
                stack.pop();
            } else {
                return {
                    code: -1,
                    message: `Unclosed tag <${stackTop.content}>: \nline - ${line}, column - ${column}`
                };
            }
        }
        i ++;
    }

    if (stack.length !== 0) {
        const stackTop = stack[stack.length - 1];
        const {line, column} = stackTop;

        return {
            code: -1,
            message: `Unclosed tag <${stackTop.content}>: \nline - ${line}, column - ${column}`
        };
    }

    return {code: 0};
}

const voidTagTypes = splitSpace('area base br col embed hr img input keygen link menuitem meta param source track wbr r-content');
function isVoidTag(tag) {
    return voidTagTypes.indexOf(tag) !== -1;
}

function splitSpace(str) {
    return str.split(' ');
}

exports.Parser = Parser;<commit_msg>chore: eat -> consume<commit_after>const {Lexer} = require('./Lexer');
const {INIT, OPEN_TAG, CLOSE_TAG, END_TAG, TAGNAME, TAG, EXPR, TEXT, ATTR, EQUAL, VALUE, EOF} = require('./StateTypes');
const {Program, If, For, Element, Attribute, Expression, Text, Types} = require('./NodeTypes');
const {Expression: expression} = require('./Expression');

const IF_ATTR = 'd:if';
const ELSE_ATTR = 'd:else';
const ELSE_IF_ATTR = 'd:elif';
const FOR_ATTR = 'd:for';
const FOR_ITEM_ATTR = 'd:for-item';
const FOR_ITEM_INDEX_ATTR = 'd:for-index';

function Parser(source) {
    const tokens = Lexer(source);
    const {code, message} = isTagClosed(tokens);
    if (code !== 0) {
        throw message;
    }

    let pos = 0;

    return Program(program(tokens));

    function ll(k = 0) {
        pos += k;

        if (pos > tokens.length - 1){
            return tokens[tokens.length-1];
        }

        return tokens[pos];
    }

    function la(...args) {
        return ll(...args).type;
    }

    function program() {
        return package(type => type !== END_TAG && type !== EOF);
    }

    function package(condition) {
        const body = [];
        while (
            condition(la())
        ) {
            const node = recurse(body);

            if (node) {
                body.push(node);
            }
        }
        return body;
    }

    function recurse(nodes) {
        const token = ll();
        const {type} = token;
        switch (type) {
        case TAGNAME:
            return element(nodes);
        case TEXT:
            return text();
        case EXPR:
            return expr();
        }
    }

    function text() {
        const {content} = ll();
        next();
        return Text(content);
    }

    function element(nodes) {
        const {content} = ll();

        next();

        let children, directives;
        let attrNodes = attrs();

        const refs = regenerateAttrs(attrNodes);
        attrNodes = refs.attrs;
        directives = refs.directives;

        if (!isVoidTag(content)) {
            children = program();
        }

        let element = Element(
            content, attrNodes, children
        );

        const ifNodeList = nodes.filter(({type}) => {
            return type === Types.If;
        });

        const lastIfNode = ifNodeList[ifNodeList.length - 1];

        element = wrapElseStatement(element, directives, lastIfNode);

        element = wrapIfStatement(element, directives);

        element = wrapForStatement(element, directives);

        comsume(END_TAG);

        return element;
    }

    function wrapElseStatement (element, directives, lastIfNode) {
        let elseIfValue = directives[ELSE_IF_ATTR];

        const keys = Object.keys(directives);

        if (lastIfNode) {
            // find the empty consequent
            while (lastIfNode.consequent) {
                lastIfNode = lastIfNode.consequent;
            }

            if (~keys.indexOf(ELSE_ATTR)) {
                lastIfNode.consequent = element;
                return null;
            } else if (elseIfValue) {
                lastIfNode.consequent = If(Expression(expression(elseIfValue)), element);
                return null;
            }
        }

        return element;
    }

    function wrapIfStatement(element, directives) {
        let value = directives[IF_ATTR];
        if (value) {
            return If(Expression(expression(value)), element);
        }
        return element;
    }

    function wrapForStatement(element, directives) {
        let value = directives[FOR_ATTR];
        if (value) {
            return For(Expression(expression(value)), {
                item: directives[FOR_ITEM_ATTR],
                index: directives[FOR_ITEM_INDEX_ATTR],
            }, element);
        }
        return element;
    }

    function regenerateAttrs(attrNodes) {
        const attrs = [];
        const directives = {};

        for (let attr of attrNodes) {
            const {name, value} = attr;
            if (~name.indexOf('d:')) {
                Object.assign(directives, ({
                    [name]: value || ''
                }));
            } else {
                attrs.push(attr);
            }
        }

        return {
            attrs, directives
        };
    }

    function expr() {
        const expr = ll();
        next();
        return Expression(expression(expr.content));
    }

    function attrs() {
        const attrs = [];
        while (la() === ATTR) {
            const name = ll().content;
            next();
            const value = comsume(VALUE).content;

            const attr = Attribute(name, value);
            attrs.push(attr);
        }
        return attrs;
    }

    function next() {
        pos ++;
    }

    function comsume(type) {
        let matched = {};
        if (la() === type) {
            matched = ll();
        }
        next();
        return matched;
    }
}

function isTagClosed(tokens) {
    let stack = [];
    let i = 0;
    while( i < tokens.length) {
        const token = tokens[i];
        const {type, content} = token;
        if (type === TAGNAME &&
            !isVoidTag(content)) {
            stack.push(token);
        } else if (type === END_TAG) {
            const stackTop = stack[stack.length - 1];
            const {line, column} = stackTop;
            if (stackTop.content === content) {
                stack.pop();
            } else {
                return {
                    code: -1,
                    message: `Unclosed tag <${stackTop.content}>: \nline - ${line}, column - ${column}`
                };
            }
        }
        i ++;
    }

    if (stack.length !== 0) {
        const stackTop = stack[stack.length - 1];
        const {line, column} = stackTop;

        return {
            code: -1,
            message: `Unclosed tag <${stackTop.content}>: \nline - ${line}, column - ${column}`
        };
    }

    return {code: 0};
}

const voidTagTypes = splitSpace('area base br col embed hr img input keygen link menuitem meta param source track wbr r-content');
function isVoidTag(tag) {
    return voidTagTypes.indexOf(tag) !== -1;
}

function splitSpace(str) {
    return str.split(' ');
}

exports.Parser = Parser;<|endoftext|>


<commit_before>var analytics = require('./client/analytics')
var config = require('./client/config')
var modal = require('./client/modal')
var RideshareSignUp = require('./client/rideshare-sign-up')
var RouteComparisonTable = require('route-comparison-table')
var RouteResourcesView = require('route-resources-view')
var routeSummarySegments = require('route-summary-segments')
var session = require('session')
var SignUpForm = require('sign-up-form')
var hogan = require('hogan.js')

/**
 * Create `Modal`
 */

var RouteModal = module.exports = modal({
  closable: true,
  template: require('./template.html'),
  title: 'Selected Option Modal'
}, function (view, route) {
  var context = view.options.context
  if (context !== 'welcome-flow') {
    analytics.track('Selected Route', {
      context: context,
      plan: session.plan().generateQuery(),
      route: {
        modes: route.modes(),
        summary: route.summary()
      },
      from: context
    })
  }
})

RouteModal.prototype.commuterConnectionsLogo = function () {
  return config.static_url() + '/images/application/commuter-connections.png'
}

RouteModal.prototype.next = function (e) {
  e.preventDefault()
  this.emit('next')
}

RouteModal.prototype.signUpForRideshare = function (e) {
  e.preventDefault()
  RideshareSignUp().show()
}

RouteModal.prototype.routeComparisonTable = function () {
  return new RouteComparisonTable(this.model)
}

RouteModal.prototype.routeSummarySegments = function () {
  return routeSummarySegments(this.model, {
    inline: true
  })
}

RouteModal.prototype.signUpForm = function () {
  return new SignUpForm()
}

RouteModal.prototype.routeResourcesView = function () {
  return new RouteResourcesView(this.model, null, {
    resources: this.options.resources
  })
}

RouteModal.prototype.routeIntroText = function () {
  switch (this.options.context) {
    case 'welcome-flow':
      return 'Your best option is to'
    case 'help-me-choose':
    case 'route-card':
      return 'You selected'
  }
}

RouteModal.prototype.nextButtonText = function () {
  switch (this.options.context) {
    case 'welcome-flow':
      return 'Show all of my options'
    case 'help-me-choose':
    case 'route-card':
      return 'Return to my options'
  }
}

var intMatchesTemplate = hogan.compile(require('./internal-matches.html'))

RouteModal.prototype.internalMatches = function () {
  if (this.model.get('internalCarpoolMatches')) {
    var matches = this.model.get('internalCarpoolMatches').matches
  }

  // group matches by organization
  var matchesByOrg = {}
  matches.forEach(function (match) {
    if (!(match.organization.id in matchesByOrg)) {
      matchesByOrg[match.organization.id] = {
        name: match.organization.name,
        url: match.organization.url,
        matches: []
      }
    }
    matchesByOrg[match.organization.id].matches.push(match)
  })

  // pass array of organizations (w/ matches) to template
  var orgArray = []
  for (var id in matchesByOrg) orgArray.push(matchesByOrg[id])
  return intMatchesTemplate.render({ organizations: orgArray })
}

<commit_msg>Handle missing internal matches field in route-modal<commit_after>var analytics = require('./client/analytics')
var config = require('./client/config')
var modal = require('./client/modal')
var RideshareSignUp = require('./client/rideshare-sign-up')
var RouteComparisonTable = require('route-comparison-table')
var RouteResourcesView = require('route-resources-view')
var routeSummarySegments = require('route-summary-segments')
var session = require('session')
var SignUpForm = require('sign-up-form')
var hogan = require('hogan.js')
var each = require('each')
/**
 * Create `Modal`
 */

var RouteModal = module.exports = modal({
  closable: true,
  template: require('./template.html'),
  title: 'Selected Option Modal'
}, function (view, route) {
  var context = view.options.context
  if (context !== 'welcome-flow') {
    analytics.track('Selected Route', {
      context: context,
      plan: session.plan().generateQuery(),
      route: {
        modes: route.modes(),
        summary: route.summary()
      },
      from: context
    })
  }
})

RouteModal.prototype.commuterConnectionsLogo = function () {
  return config.static_url() + '/images/application/commuter-connections.png'
}

RouteModal.prototype.next = function (e) {
  e.preventDefault()
  this.emit('next')
}

RouteModal.prototype.signUpForRideshare = function (e) {
  e.preventDefault()
  RideshareSignUp().show()
}

RouteModal.prototype.routeComparisonTable = function () {
  return new RouteComparisonTable(this.model)
}

RouteModal.prototype.routeSummarySegments = function () {
  return routeSummarySegments(this.model, {
    inline: true
  })
}

RouteModal.prototype.signUpForm = function () {
  return new SignUpForm()
}

RouteModal.prototype.routeResourcesView = function () {
  return new RouteResourcesView(this.model, null, {
    resources: this.options.resources
  })
}

RouteModal.prototype.routeIntroText = function () {
  switch (this.options.context) {
    case 'welcome-flow':
      return 'Your best option is to'
    case 'help-me-choose':
    case 'route-card':
      return 'You selected'
  }
}

RouteModal.prototype.nextButtonText = function () {
  switch (this.options.context) {
    case 'welcome-flow':
      return 'Show all of my options'
    case 'help-me-choose':
    case 'route-card':
      return 'Return to my options'
  }
}

var intMatchesTemplate = hogan.compile(require('./internal-matches.html'))

RouteModal.prototype.internalMatches = function () {
  if (this.model.get('internalCarpoolMatches')) {
    var matches = this.model.get('internalCarpoolMatches').matches
  }

  // group matches by organization
  var matchesByOrg = {}
  each(matches, function (match) {
    if (!(match.organization.id in matchesByOrg)) {
      matchesByOrg[match.organization.id] = {
        name: match.organization.name,
        url: match.organization.url,
        matches: []
      }
    }
    matchesByOrg[match.organization.id].matches.push(match)
  })

  // pass array of organizations (w/ matches) to template
  var orgArray = []
  for (var id in matchesByOrg) orgArray.push(matchesByOrg[id])
  return intMatchesTemplate.render({ organizations: orgArray })
}

<|endoftext|>


<commit_before>define(["underscore", "jquery"], function(_, $) {
    $.fn.transition = function(klFrom, klActive, klFinal) {
        var self = this;
        this.addClass(klFrom);
        this.one("animationend", function(e) {
            self.removeClass(klFrom).removeClass(klActive);
            if (klFinal)
                self.addClass(klFinal);
        });
        this.addClass(klActive);
    };

    $.fn.animateAddClass = function(klBase) {
        this.classTransition(klBase + "-enter",
                             klBase + "-active");
    };

    /**
     * Takes a numeric string s and adds thousands separators.
     * For example: commas("12345678.3") -> "12,345,678.3"
     *
     * @param {String|Number} s A number or numeric string to format.
     *
     * @returns {String} A string with commas inserted
     */
    function commas(s) {
        if (!s) return "";

        s = s.toString();
        var split = s.split("."),
            after = split[1];

        s = split[0];

        var l = s.length;
        if (l <= 3)
            return s;

        var istart = 0,
            iend = (l % 3) || 3,
            pieces = [],
            p;

        while ((p = s.slice(istart, iend))) {
            pieces.push(p);
            istart = iend;
            iend += 3;
        }

        return pieces.join(",") + (after ? ("." + after) : "");
    }

    function prettyAmount(amount, currency) {
        currency = currency || "$";

        var mag = "";

        if (amount >= 10000) {
            if (amount < 1000000) {
                mag = "k";
                amount /= 1000;
            } else if (amount < 1000000000) {
                mag = "m";
                amount /= 1000000;
            } else {
                mag = "b";
                amount /= 1000000000;
            }

            var amountStr = amount.toFixed(1).replace(/\.0$/, "");

            return currency + amountStr + mag;
        }

        return currency + commas(amount);
    }

    function prettyDistance(ft) {
        var miles = ft/5280;

        if (miles >= 1) {
            var m = miles.toFixed(1).replace(/\.0$/, "");
            return m + " mile" + (miles - 1 < 0.1 ? "" : "s");
        }

        return commas(ft) + " feet";
    }

    /**
     * @param {String} s
     *
     * @returns {String} A copy of s with its first character converted
     * to upper case.
     */
    function capitalize(s) {
        return s[0].toUpperCase() + s.slice(1);
    }

    /**
     * @param {String} s
     *
     * @returns {Boolean} true if the string only contains digits.
     */
    function isDigit(s) {
        return /^[0-9]+$/.test(s);
    }

    function isSimpleObject(o) {
        return o.constructor && o.constructor === Object;
    }

    function setIn(obj, ks, v) {
        if (ks.length == 0)
            return v;

        var k = ks[0];

        if (isDigit(k))
            k = parseInt(k);

        if (ks.length === 1 && k === undefined) {
            delete obj[k];
        } else {
            obj[k] = setIn(obj[k] || {},
                           ks.slice(1),
                           v);
        }
        return obj;
    }

    function getIn(obj, ks) {
        if (ks.length === 0)
            return obj;

        if (!obj)
            return undefined;

        return getIn(obj[ks[0]], ks.slice(1));
    }

    function deepMerge(obj1, obj2) {
        _.each(obj2, function(v, k) {
            var orig = obj2[k];
            if (orig && isSimpleObject(v) && isSimpleObject(orig)) {
                deepMerge(v, orig);
            } else {
                obj1[k] = v;
            }
        });
    }

    function flattenMap(obj, pref) {
        pref = pref || "";
        return _.reduce(obj, function(m, val, key) {
            if (!(!key || val === undefined)) {
                if (isSimpleObject(val)) {
                    return _.extend(m, flattenMap(val, key + "."));
                }

                m[pref + key] = val;
            }

            return m;
        }, {});
    }

    var defaultHelpers = {
        formatDate: function(d) {
            return (d.toLocaleDateString) ?
                d.toLocaleDateString() :
                d.toString().slice(0, 15);
        },

        capitalize: capitalize,

        commas: commas,

        pluralize: function(n, sing, plur) {
            return n == 1 ? sing : (plur || sing + "s");
        },

        prettyAmount: prettyAmount,

        prettyDistance: prettyDistance
    };

    var $u = {
        keepArgs: function(fn, n) {
            return function() {
                return fn.apply(this, _.take(arguments, n));
            };
        },

        parseInt10: function(n) {
            return parseInt(n, 10);
        },

        capitalize: capitalize,

        escapeRegex: function(s) {
            return s.replace(/[.*+?\^$[\]\\(){}|\-]/g, "\\$&");
        },

        /**
         * Generate an equivalent regular expression for the given glob
         * string.
         *
         * @param {String} patt A glob pattern
         *
         * @returns {RegExp}
         */
        glob: function(patt) {
            var re = patt
                    .replace(/[.+\^$[\]\\(){}|\-]/g, "\\$&")
                    .replace("*", ".*")
                    .replace("?", ".");

            return new RegExp(re, "i");
        },

        everyPred: function(fs, arg) {
            return _.every(fs, function(f) {
                return f(arg);
            });
        },

        findIndex: function(coll, f) {
            for (var i = 0, l = coll.length; i < l; i++) {
                if (f(coll[i]))
                    return i;
            }

            return -1;
        },

        /**
         * Call function fn on an array of the 1st argument of each
         * array in colls, then on an array of the 2nd arguments,
         * etc. Stops when any of the arrays is exhausted.
         *
         * @param {Function} fn
         * @param {Array} colls
         *
         * @returns {Array} Results of calling fn on the elements of
         * colls.
         */
        zipmap: function(fn, colls) {
            var out = [],
                idx = 0;

            outer:
            while (true) {
                var args = [], i = 0, coll;

                while ((coll = colls[i++]) !== undefined) {
                    if (coll[idx] === undefined)
                        break outer;

                    args.push(coll[idx]);
                }

                out.push(fn(args));

                idx++;
            }

            return out;
        },

        /**
         * @returns {jquery.Deferred} A promise that, when resolved,
         * returns the coordinates from the user's browser.
         */
        promiseLocation: function() {
            var promise = $.Deferred();

            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    function(pos) {
                        var coords = pos.coords;
                        promise.resolve([coords.latitude,
                                         coords.longitude,
                                         coords.altitude]);
                    },
                    function() {
                        promise.reject({reason: "Permission denied"});
                    });
            } else {
                promise.reject({reason: "Geolocation unavailable in this browser."});
            }

            return promise;
        },

        closeTo: function(n1, n2, tolerance) {
            return Math.abs(n1 - n2) <= (tolerance || 0.1);
        },

        // Unit conversions:
        mToFeet: function(m) {
            return m*3.281;
        },

        feetToM: function(ft) {
            return ft/3.281;
        },

        mToMiles: function(m) {
            return m*3.281/5280;
        },

        // Formatting
        commas: commas,

        /**
         * @param {number} amount
         * @param {string} currency
         *
         * @returns {string}
         */
        prettyAmount: prettyAmount,

        /**
         * Convert a number to a human-friendly distance string.
         *
         * @param {number} feet Distance in feet
         */
        prettyDistance: prettyDistance,

        currentYear: function() {
            return (new Date()).getFullYear();
        },

        /**
         * Register a default template helper, which will be available
         * to templates created with $u.template().
         *
         * @param {string} name
         * @param {Function}
         */
        registerHelper: function(name, fn) {
            defaultHelpers[name] = fn;
            return this;
        },

        setCookie: function(name, value, options) {
            document.cookie = [
                encodeURIComponent(name), "=",
                encodeURIComponent(value), ";"
            ].join("");
        },

        getCookie: function(name) {
            var cookie = document.cookie,
                patt = new RegExp("(^|;\\s*)" +
                                  $u.escapeRegex(encodeURIComponent(name)) +
                                 "=([^;]+)"),
                m = cookie.match(patt);

            return m && decodeURIComponents(m[2]);
        },

        getIn: getIn,
        setIn: setIn,

        deepMerge: deepMerge,
        flattenMap: flattenMap,

        /**
         * @param {Object} o A map of strings to
         *
         * @returns A string encoding the contents of the map.  Nested
         * maps are flattened with flattenMap.
         */
        encodeQuery: function(o) {
            return _.map(flattenMap(o), function(val, k) {
                return encodeURIComponent(k) + "=" + encodeURIComponent(val);
            }).sort().join("&");
        },

        decodeQuery: function(s) {
            var idxRe = /\[(\d+)\]$/;
            return _.reduce(s.split("&"), function(m, piece) {
                var ss = piece.split("="),
                    k = decodeURIComponent(ss[0]),
                    val = decodeURIComponent(ss[1]);

                if (k.indexOf(".") > -1) {
                    var ks = k.split(".");
                    setIn(m, ks, val);
                } else {
                    m[k] = val;
                }

                return m;
            }, {});
        },

        /**
         * Like _.template, except that it adds helper functions to the
         * data passed to the resulting template function.
         *
         * @param {string} templateString
         * @param {object} helpers Mapping names to functions
         * @param {object} settings Passed as second argument to _.template
         */
        template: function(templateString, settings, helpers) {
            helpers = helpers || defaultHelpers;

            if (settings) {
                var varName = settings.variable;
                delete settings.variable;
            }

            var temp = _.template(templateString, settings);

            return function(data) {
                if (varName) {
                    var d = {};
                    d[varName] = data;
                    data = d;
                }

                return temp(_.extend(data, helpers));
            };
        },

        /**
         * @param {string} id Element ID of the template element in the
         * DOM.
         * @param {object} options
         */
        templateWithId: function(id, options) {
            var templateString = $("#" + id).text();

            if (!templateString) {
                throw new Error("Unknown template: " + id);
            }
            options = options || {};
            return $u.template(templateString, options, options.helpers);
        },

        templateWithUrl: (function() {
            // Close over idCounter
            var idCounter = 0;

            return function(url, options) {
                var template = null;
                options = options || {};

                return function(arg, cb) {
                    if (template) {
                        cb(template(arg));
                        return;
                    }

                    var placeholderId = "_template_placeholder_" + (idCounter++);

                    $.get(
                        url,
                        function(templateString) {
                            template = $u.template(templateString,
                                                   options,
                                                   options.helpers);
                            cb(template(arg));
                        }
                    );
                };
            };
        })()
    };

    return $u;
});
<commit_msg>Make distances a little prettier<commit_after>define(["underscore", "jquery"], function(_, $) {
    $.fn.transition = function(klFrom, klActive, klFinal) {
        var self = this;
        this.addClass(klFrom);
        this.one("animationend", function(e) {
            self.removeClass(klFrom).removeClass(klActive);
            if (klFinal)
                self.addClass(klFinal);
        });
        this.addClass(klActive);
    };

    $.fn.animateAddClass = function(klBase) {
        this.classTransition(klBase + "-enter",
                             klBase + "-active");
    };

    /**
     * Takes a numeric string s and adds thousands separators.
     * For example: commas("12345678.3") -> "12,345,678.3"
     *
     * @param {String|Number} s A number or numeric string to format.
     *
     * @returns {String} A string with commas inserted
     */
    function commas(s) {
        if (!s) return "";

        s = s.toString();
        var split = s.split("."),
            after = split[1];

        s = split[0];

        var l = s.length;
        if (l <= 3)
            return s;

        var istart = 0,
            iend = (l % 3) || 3,
            pieces = [],
            p;

        while ((p = s.slice(istart, iend))) {
            pieces.push(p);
            istart = iend;
            iend += 3;
        }

        return pieces.join(",") + (after ? ("." + after) : "");
    }

    function prettyAmount(amount, currency) {
        currency = currency || "$";

        var mag = "";

        if (amount >= 10000) {
            if (amount < 1000000) {
                mag = "K";
                amount /= 1000;
            } else if (amount < 1000000000) {
                mag = "M";
                amount /= 1000000;
            } else {
                mag = "B";
                amount /= 1000000000;
            }

            var amountStr = amount.toFixed(1).replace(/\.0$/, "");

            return currency + amountStr + mag;
        }

        return currency + commas(amount);
    }

    function prettyDistance(ft) {
        var miles = ft/5280;

        if (miles >= 1) {
            var m = miles.toFixed(1).replace(/\.0$/, "");
            return m + " mile" + (miles - 1 < 0.1 ? "" : "s");
        } else if (miles >= 0.25) {
            var denom, num;
            if (miles > 0.5) {
                denom = Math.round(1/(1-miles));
                num = Math.round(miles*denom);

            } else {
                denom = Math.round(1/miles);
                num = 1;
            }

            return "~" + num + "/" + denom + " mile";
        }

        return commas(ft) + " feet";
    }

    /**
     * @param {String} s
     *
     * @returns {String} A copy of s with its first character converted
     * to upper case.
     */
    function capitalize(s) {
        return s[0].toUpperCase() + s.slice(1);
    }

    /**
     * @param {String} s
     *
     * @returns {Boolean} true if the string only contains digits.
     */
    function isDigit(s) {
        return /^[0-9]+$/.test(s);
    }

    function isSimpleObject(o) {
        return o.constructor && o.constructor === Object;
    }

    function setIn(obj, ks, v) {
        if (ks.length == 0)
            return v;

        var k = ks[0];

        if (isDigit(k))
            k = parseInt(k);

        if (ks.length === 1 && k === undefined) {
            delete obj[k];
        } else {
            obj[k] = setIn(obj[k] || {},
                           ks.slice(1),
                           v);
        }
        return obj;
    }

    function getIn(obj, ks) {
        if (ks.length === 0)
            return obj;

        if (!obj)
            return undefined;

        return getIn(obj[ks[0]], ks.slice(1));
    }

    function deepMerge(obj1, obj2) {
        _.each(obj2, function(v, k) {
            var orig = obj2[k];
            if (orig && isSimpleObject(v) && isSimpleObject(orig)) {
                deepMerge(v, orig);
            } else {
                obj1[k] = v;
            }
        });
    }

    function flattenMap(obj, pref) {
        pref = pref || "";
        return _.reduce(obj, function(m, val, key) {
            if (!(!key || val === undefined)) {
                if (isSimpleObject(val)) {
                    return _.extend(m, flattenMap(val, key + "."));
                }

                m[pref + key] = val;
            }

            return m;
        }, {});
    }

    var defaultHelpers = {
        formatDate: function(d) {
            return (d.toLocaleDateString) ?
                d.toLocaleDateString() :
                d.toString().slice(0, 15);
        },

        capitalize: capitalize,

        commas: commas,

        pluralize: function(n, sing, plur) {
            return n == 1 ? sing : (plur || sing + "s");
        },

        prettyAmount: prettyAmount,

        prettyDistance: prettyDistance
    };

    var $u = {
        keepArgs: function(fn, n) {
            return function() {
                return fn.apply(this, _.take(arguments, n));
            };
        },

        parseInt10: function(n) {
            return parseInt(n, 10);
        },

        capitalize: capitalize,

        escapeRegex: function(s) {
            return s.replace(/[.*+?\^$[\]\\(){}|\-]/g, "\\$&");
        },

        /**
         * Generate an equivalent regular expression for the given glob
         * string.
         *
         * @param {String} patt A glob pattern
         *
         * @returns {RegExp}
         */
        glob: function(patt) {
            var re = patt
                    .replace(/[.+\^$[\]\\(){}|\-]/g, "\\$&")
                    .replace("*", ".*")
                    .replace("?", ".");

            return new RegExp(re, "i");
        },

        everyPred: function(fs, arg) {
            return _.every(fs, function(f) {
                return f(arg);
            });
        },

        findIndex: function(coll, f) {
            for (var i = 0, l = coll.length; i < l; i++) {
                if (f(coll[i]))
                    return i;
            }

            return -1;
        },

        /**
         * Call function fn on an array of the 1st argument of each
         * array in colls, then on an array of the 2nd arguments,
         * etc. Stops when any of the arrays is exhausted.
         *
         * @param {Function} fn
         * @param {Array} colls
         *
         * @returns {Array} Results of calling fn on the elements of
         * colls.
         */
        zipmap: function(fn, colls) {
            var out = [],
                idx = 0;

            outer:
            while (true) {
                var args = [], i = 0, coll;

                while ((coll = colls[i++]) !== undefined) {
                    if (coll[idx] === undefined)
                        break outer;

                    args.push(coll[idx]);
                }

                out.push(fn(args));

                idx++;
            }

            return out;
        },

        /**
         * @returns {jquery.Deferred} A promise that, when resolved,
         * returns the coordinates from the user's browser.
         */
        promiseLocation: function() {
            var promise = $.Deferred();

            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    function(pos) {
                        var coords = pos.coords;
                        promise.resolve([coords.latitude,
                                         coords.longitude,
                                         coords.altitude]);
                    },
                    function() {
                        promise.reject({reason: "Permission denied"});
                    });
            } else {
                promise.reject({reason: "Geolocation unavailable in this browser."});
            }

            return promise;
        },

        closeTo: function(n1, n2, tolerance) {
            return Math.abs(n1 - n2) <= (tolerance || 0.1);
        },

        // Unit conversions:
        mToFeet: function(m) {
            return m*3.281;
        },

        feetToM: function(ft) {
            return ft/3.281;
        },

        mToMiles: function(m) {
            return m*3.281/5280;
        },

        // Formatting
        commas: commas,

        /**
         * @param {number} amount
         * @param {string} currency
         *
         * @returns {string}
         */
        prettyAmount: prettyAmount,

        /**
         * Convert a number to a human-friendly distance string.
         *
         * @param {number} feet Distance in feet
         */
        prettyDistance: prettyDistance,

        currentYear: function() {
            return (new Date()).getFullYear();
        },

        /**
         * Register a default template helper, which will be available
         * to templates created with $u.template().
         *
         * @param {string} name
         * @param {Function}
         */
        registerHelper: function(name, fn) {
            defaultHelpers[name] = fn;
            return this;
        },

        setCookie: function(name, value, options) {
            document.cookie = [
                encodeURIComponent(name), "=",
                encodeURIComponent(value), ";"
            ].join("");
        },

        getCookie: function(name) {
            var cookie = document.cookie,
                patt = new RegExp("(^|;\\s*)" +
                                  $u.escapeRegex(encodeURIComponent(name)) +
                                 "=([^;]+)"),
                m = cookie.match(patt);

            return m && decodeURIComponents(m[2]);
        },

        getIn: getIn,
        setIn: setIn,

        deepMerge: deepMerge,
        flattenMap: flattenMap,

        /**
         * @param {Object} o A map of strings to
         *
         * @returns A string encoding the contents of the map.  Nested
         * maps are flattened with flattenMap.
         */
        encodeQuery: function(o) {
            return _.map(flattenMap(o), function(val, k) {
                return encodeURIComponent(k) + "=" + encodeURIComponent(val);
            }).sort().join("&");
        },

        decodeQuery: function(s) {
            var idxRe = /\[(\d+)\]$/;
            return _.reduce(s.split("&"), function(m, piece) {
                var ss = piece.split("="),
                    k = decodeURIComponent(ss[0]),
                    val = decodeURIComponent(ss[1]);

                if (k.indexOf(".") > -1) {
                    var ks = k.split(".");
                    setIn(m, ks, val);
                } else {
                    m[k] = val;
                }

                return m;
            }, {});
        },

        /**
         * Like _.template, except that it adds helper functions to the
         * data passed to the resulting template function.
         *
         * @param {string} templateString
         * @param {object} helpers Mapping names to functions
         * @param {object} settings Passed as second argument to _.template
         */
        template: function(templateString, settings, helpers) {
            helpers = helpers || defaultHelpers;

            if (settings) {
                var varName = settings.variable;
                delete settings.variable;
            }

            var temp = _.template(templateString, settings);

            return function(data) {
                if (varName) {
                    var d = {};
                    d[varName] = data;
                    data = d;
                }

                return temp(_.extend(data, helpers));
            };
        },

        /**
         * @param {string} id Element ID of the template element in the
         * DOM.
         * @param {object} options
         */
        templateWithId: function(id, options) {
            var templateString = $("#" + id).text();

            if (!templateString) {
                throw new Error("Unknown template: " + id);
            }
            options = options || {};
            return $u.template(templateString, options, options.helpers);
        },

        templateWithUrl: (function() {
            // Close over idCounter
            var idCounter = 0;

            return function(url, options) {
                var template = null;
                options = options || {};

                return function(arg, cb) {
                    if (template) {
                        cb(template(arg));
                        return;
                    }

                    var placeholderId = "_template_placeholder_" + (idCounter++);

                    $.get(
                        url,
                        function(templateString) {
                            template = $u.template(templateString,
                                                   options,
                                                   options.helpers);
                            cb(template(arg));
                        }
                    );
                };
            };
        })()
    };

    return $u;
});
<|endoftext|>


<commit_before>/**
 * 下拉
 * @class BI.Trigger
 * @extends BI.Single
 * @abstract
 */
BI.Trigger = BI.inherit(BI.Single, {
    _defaultConfig: function () {
        var conf = BI.Trigger.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            _baseCls: (conf._baseCls || "") + " bi-trigger cursor-pointer",
            height: 24
        });
    },

    _init: function () {
        BI.Trigger.superclass._init.apply(this, arguments);
    },

    setKey: function () {

    },

    getKey: function () {

    }
});<commit_msg>无JIRA任务 默认trigger的populate行为为空<commit_after>/**
 * 下拉
 * @class BI.Trigger
 * @extends BI.Single
 * @abstract
 */
BI.Trigger = BI.inherit(BI.Single, {
    _defaultConfig: function () {
        var conf = BI.Trigger.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            _baseCls: (conf._baseCls || "") + " bi-trigger cursor-pointer",
            height: 24
        });
    },

    _init: function () {
        BI.Trigger.superclass._init.apply(this, arguments);
    },

    setKey: function () {

    },

    getKey: function () {

    },
    populate: function () {

    }
});<|endoftext|>