<commit_before>/*
 * tksweb - Web UI for timesheet entry
 *
 * Copyright (c) 2011 Grant McLean (grant@mclean.net.nz)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

(function($) {

$.fn.tksweb = function(options) {
    return this.each(function() {
        $.fn.tksweb.build(this, options);
    });
};

$.fn.tksweb.build = function(app_el, options) {
    var app        = $.extend({}, $.fn.tksweb.defaults, options);
    var x_inc      = app.activity_width;
    var y_inc      = app.hour_height / 4;
    var x_max      = 6 * x_inc;
    var y_max      = (app.last_hour - app.first_hour + 0.75) * 4 * y_inc;
    var keyCode    = $.ui.keyCode;

    app.current_activity = null;
    app.clipboard        = null;

    register_templates();

    var week_view  = $('
');
    var week_hdr   = $('
');
    var hours      = $('
');
    var week_hours = $('
');
    var activities = $('
');
    var cursor     = add_cursor(activities);

    $(app.day_names).each(function(i, day) {
        week_hdr.append( $('
').text(day) )
    });

    for(var i = app.first_hour; i <= app.last_hour; i++) {
        var prefix = i > 9 ? '' : '0'
        hours.append( $('
').text(prefix + i + ':00') );
    }

    activities.height((app.last_hour - app.first_hour + 1) * app.hour_height);

    week_hours.append(hours, activities)
    week_view.append(week_hdr, week_hours);

    $(app_el).addClass('tksweb-app').append(week_view);

    if(app.scroll_to_hour >= 1) {
        week_hours.scrollTop((app.scroll_to_hour - 0.5) * app.hour_height);
    }

    var dlg_activity = add_activity_dialog($(app_el));

    week_hours.delegate('.activity', 'mouseenter', function() {
        init_draggable( $(this) );
    });

    $(document).keydown(function(e) { key_handler(e); });
    activities.dblclick(function(e) { dblclick_canvas(e); })
    week_hours.mousedown(function(e) { mousedown_handler(e) });

set_cursor_pos(100, 10 * app.hour_height);
create_activity({
    description : "Do some stuff with the thing",
    hours       : 1.5,
    wr_number   : "12345"
});

set_cursor_pos(200, 9 * app.hour_height);
create_activity({
    description : "Do stuff to the other thing",
    hours       : 1.75,
    wr_number   : "54763"
});

set_cursor_pos(200, 10.75 * app.hour_height);
create_activity({
    description : "Undo that last thing",
    hours       : 0.75,
    wr_number   : "12345"
});

set_cursor_pos(300, 9 * app.hour_height);
create_activity({
    description : "Decommision obselete thing",
    hours       : 1,
    wr_number   : "44632"
});

    set_cursor_pos(0, app.scroll_to_hour * app.hour_height);

    function register_templates() {
        $.template(
            "tmpl_activity",
            '
'
            + '
${wr_number}: ${description}

'
        );
    }

    function init_draggable(activity) {
        // Initialise draggable+resizable behaviours on first mouse enter
        if(activity.is(':data(draggable)')) {
            return;
        }

        activity.draggable({
            grid: [x_inc, y_inc],
            containment: 'parent',
            cursor: 'move',
            zIndex:  100,
            stop: function () {
                var act_data = activity.tmplItem().data;
                p = activity.position()
                act_data.x = p.left;
                act_data.y = p.top;
                set_cursor_pos(p.left, p.top);
            }
        });

        activity.resizable({
            handles: 'n, s',
            grid: [0, y_inc],
            stop: function (event, ui) {
                var act_data = activity.tmplItem().data;
                act_data.height = activity.height();
                act_data.hours  = (act_data.height + app.border_allowance) / (4 * y_inc);
                unselect_activity();
                select_activity(activity);
            }
        });

    }

    function add_cursor(parent) {
        var cursor = $('
');

        cursor.css({
            width  : (x_inc - app.border_allowance) + 'px',
            height : (y_inc - app.border_allowance) + 'px'
        });

        parent.append(cursor);
        return cursor;
    }

    function set_cursor_pos(x, y) {
        cursor.css({ left: x + 'px', top: y + 'px' });
    }

    function mousedown_handler(e) {
        var target = e.target;
        if(target.nodeName == "P") { target = target.parentNode; }
        var activity = $(target).hasClass('activity') ? target : null;
        if(activity) {
            select_activity(activity);
        }
        else if(!$(target).hasClass('cursor')) {
            mouse_position_cursor(e);
        }
    }

    function mouse_position_cursor(e) {
        unselect_activity();
        var x = Math.floor((e.layerX || e.offsetX) / x_inc) * x_inc;
        var y = Math.floor((e.layerY || e.offsetY) / y_inc) * y_inc;
        set_cursor_pos(x, y);
    }

    function dblclick_canvas(e) {
        activate_cursor();
    }

    function dblclick_activity(e) {
        dlg_activity.dialog('open');
        e.stopPropagation();
    }

    function current_activity_data() {
        if(app.current_activity) {
            return $(app.current_activity).tmplItem().data;
        }
        return null;
    }

    function default_activity_data() {
        return {
            wr_number   : '',
            hours       : app.default_duration,
            description : ''
        };
    }

    function key_handler(e) {
        var curr = null;
        if(app.current_activity) {
            curr = $(app.current_activity).tmplItem().data;
        }
        switch(e.keyCode) {
            case keyCode.LEFT:   move_cursor(-x_inc,  0); break;
            case keyCode.RIGHT:  move_cursor( x_inc,  0); break;
            case keyCode.ENTER:  activate_cursor();       break;
            case keyCode.UP:
                move_cursor(0, -y_inc);
                break;
            case keyCode.DOWN:
                move_cursor(0, curr ? curr.hours * 4 * y_inc : y_inc);
                break;
            case keyCode.DELETE: delete_activity();       break;
            default:
                if(e.ctrlKey && e.keyCode == 67) {  // Ctrl-C
                    copy_activity();
                }
                else if(e.ctrlKey && e.keyCode == 88) {  // Ctrl-X
                    copy_activity();
                    delete_activity();
                }
                else if(e.ctrlKey && e.keyCode == 86) {  // Ctrl-V
                    paste_activity();
                }
                else {
                    return;
                }
                break;
        }
        e.preventDefault();
    }

    function move_cursor(x_delta, y_delta) {
        var p = cursor.position();

        if(x_delta < 0 && p.left > 0    ) { p.left += x_delta; }
        if(x_delta > 0 && p.left < x_max) { p.left += x_delta; }
        if(y_delta < 0 && p.top  > 0    ) { p.top  += y_delta; }
        if(y_delta > 0 && p.top  < y_max) { p.top  += y_delta; }
        var activity = find_activity_at_cursor(p);
        if(activity) {
            select_activity(activity);
        }
        else {
            unselect_activity();
            set_cursor_pos(p.left, p.top);
        }
    }

    function find_activity_at_cursor(p) {
        return activities.find('.activity').filter(function() {
            var data = $(this).tmplItem().data;
            if(p.left != data.x) { return false; }
            if(p.top < data.y)  { return false; }
            if(p.top > (data.y + data.height))  {
                return false;
            }
            set_cursor_pos(data.x, data.y);
            return true;
        })[0];
    }

    function select_activity(activity) {
        if(app.current_activity == activity) {
            return;
        }
        unselect_activity();
        if(activity) {
            app.current_activity = activity;
            var $activity = $(activity);
            var p = $activity.position();
            set_cursor_pos(p.left, p.top);
            $activity.addClass('selected');
        }
    }

    function unselect_activity() {
        if(app.current_activity) {
            $(app.current_activity).removeClass('selected');
        }
        app.current_activity = null;
    }

    function delete_activity() {
        var activity = app.current_activity;
        if(!activity) {
            app_alert('You must select an activity first');
            return;
        }
        unselect_activity();
        $(activity).remove();
    }

    function copy_activity() {
        var data = current_activity_data();
        if(!data) {
            app_alert('You must select an activity first');
            return;
        }
        app.clipboard = {};
        for(var key in data) {
            app.clipboard[key] = data[key];
        }
    }

    function paste_activity() {
        var data = {};
        for(var key in app.clipboard) {
            data[key] = app.clipboard[key];
        }
        create_activity(data);
        var p = cursor.position();
        select_activity( find_activity_at_cursor(p) );
    }

    function activate_cursor() {
        dlg_activity.dialog('open');
    }

    function save_activity(data) {
        if(app.current_activity) {
            update_activity(data);
        }
        else {
            create_activity(data);
        }
    }

    function update_activity(data) {
        var tmpl_item = $(app.current_activity).tmplItem();
        var tmpl_data = tmpl_item.data;
        tmpl_data.wr_number   = data.wr_number;
        tmpl_data.hours       = data.hours;
        tmpl_data.description = data.description;
        tmpl_data.height      = data.hours * 4 * y_inc - app.border_allowance;
        tmpl_item.update();
    }

    function create_activity(data) {
        var p = cursor.position();
        data.height = data.hours * 4 * y_inc - app.border_allowance;
        data.x      = p.left;
        data.y      = p.top;
        var act = $.tmpl("tmpl_activity", data);
        act.dblclick(function(e) { dblclick_activity(e) });
        activities.append(act);
    }

    function app_alert(message) {
        alert(message);
        week_hours.focus();           // Work-around keyboard focus being lost
        week_hours.css({'outline': 'none'});
    }

    function add_activity_dialog($app_el) {
        var div      = $('
');
        var wr_inp   = $('<input type="text" />');
        var hr_inp   = $('<input type="text" />').val(1);
        var desc_inp = $('<input type="text" />');
        div.append(
            $('
WR Number
').append(wr_inp),
            $('
Hours
').append(hr_inp),
            $('
Activity Description
').append(desc_inp)
        );

        div.dialog({
            autoOpen:      false,
            title:         "Activity Detail",
            resizable:     false,
            closeOnEscape: true,
            width:         360,
            height:        230,
            modal:         true,
            open: function() {
                var data = current_activity_data() || default_activity_data();
                wr_inp.val(data.wr_number);
                hr_inp.val(data.hours);
                desc_inp.val(data.description);
            },
            buttons:       {
                "Ok":  function() {
                    var data = {
                        wr_number   : wr_inp.val(),
                        hours       : hr_inp.val(),
                        description : desc_inp.val()
                    };
                    save_activity(data);
                    div.dialog("close");
                },
                "Cancel": function() { $(this).dialog("close"); }
            }
        });

        div.find('input').keydown(function(e) {
            if(e.keyCode == keyCode.ENTER) {
                div.parent().find('.ui-dialog-buttonpane button:first').click();
                e.stopPropagation();  // Don't allow Enter to re-launch dialog
            }
        });

        return div;
    }

};

$.fn.tksweb.defaults = {
    day_names        : [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ],
    first_hour       : 0,
    last_hour        : 23,
    scroll_to_hour   : 9,
    hour_height      : 48,  // must be a multiple of 4 and match bg-image bands
    activity_width   : 100,
    border_allowance : 2,   // top border thickness + bottom border
    default_duration : 1    // default number of hours for a new activity
};

})(jQuery);
<commit_msg>refactor copying object data<commit_after>/*
 * tksweb - Web UI for timesheet entry
 *
 * Copyright (c) 2011 Grant McLean (grant@mclean.net.nz)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

(function($) {

$.fn.tksweb = function(options) {
    return this.each(function() {
        $.fn.tksweb.build(this, options);
    });
};

$.fn.tksweb.build = function(app_el, options) {
    var app        = $.extend({}, $.fn.tksweb.defaults, options);
    var x_inc      = app.activity_width;
    var y_inc      = app.hour_height / 4;
    var x_max      = 6 * x_inc;
    var y_max      = (app.last_hour - app.first_hour + 0.75) * 4 * y_inc;
    var keyCode    = $.ui.keyCode;

    app.current_activity = null;
    app.clipboard        = null;

    register_templates();

    var week_view  = $('
');
    var week_hdr   = $('
');
    var hours      = $('
');
    var week_hours = $('
');
    var activities = $('
');
    var cursor     = add_cursor(activities);

    $(app.day_names).each(function(i, day) {
        week_hdr.append( $('
').text(day) )
    });

    for(var i = app.first_hour; i <= app.last_hour; i++) {
        var prefix = i > 9 ? '' : '0'
        hours.append( $('
').text(prefix + i + ':00') );
    }

    activities.height((app.last_hour - app.first_hour + 1) * app.hour_height);

    week_hours.append(hours, activities)
    week_view.append(week_hdr, week_hours);

    $(app_el).addClass('tksweb-app').append(week_view);

    if(app.scroll_to_hour >= 1) {
        week_hours.scrollTop((app.scroll_to_hour - 0.5) * app.hour_height);
    }

    var dlg_activity = add_activity_dialog($(app_el));

    week_hours.delegate('.activity', 'mouseenter', function() {
        init_draggable( $(this) );
    });

    $(document).keydown(function(e) { key_handler(e); });
    activities.dblclick(function(e) { dblclick_canvas(e); })
    week_hours.mousedown(function(e) { mousedown_handler(e) });

set_cursor_pos(100, 10 * app.hour_height);
create_activity({
    description : "Do some stuff with the thing",
    hours       : 1.5,
    wr_number   : "12345"
});

set_cursor_pos(200, 9 * app.hour_height);
create_activity({
    description : "Do stuff to the other thing",
    hours       : 1.75,
    wr_number   : "54763"
});

set_cursor_pos(200, 10.75 * app.hour_height);
create_activity({
    description : "Undo that last thing",
    hours       : 0.75,
    wr_number   : "12345"
});

set_cursor_pos(300, 9 * app.hour_height);
create_activity({
    description : "Decommision obselete thing",
    hours       : 1,
    wr_number   : "44632"
});

    set_cursor_pos(0, app.scroll_to_hour * app.hour_height);

    function register_templates() {
        $.template(
            "tmpl_activity",
            '
'
            + '
${wr_number}: ${description}

'
        );
    }

    function init_draggable(activity) {
        // Initialise draggable+resizable behaviours on first mouse enter
        if(activity.is(':data(draggable)')) {
            return;
        }

        activity.draggable({
            grid: [x_inc, y_inc],
            containment: 'parent',
            cursor: 'move',
            zIndex:  100,
            stop: function () {
                var act_data = activity.tmplItem().data;
                p = activity.position()
                act_data.x = p.left;
                act_data.y = p.top;
                set_cursor_pos(p.left, p.top);
            }
        });

        activity.resizable({
            handles: 'n, s',
            grid: [0, y_inc],
            stop: function (event, ui) {
                var act_data = activity.tmplItem().data;
                act_data.height = activity.height();
                act_data.hours  = (act_data.height + app.border_allowance) / (4 * y_inc);
                unselect_activity();
                select_activity(activity);
            }
        });

    }

    function add_cursor(parent) {
        var cursor = $('
');

        cursor.css({
            width  : (x_inc - app.border_allowance) + 'px',
            height : (y_inc - app.border_allowance) + 'px'
        });

        parent.append(cursor);
        return cursor;
    }

    function set_cursor_pos(x, y) {
        cursor.css({ left: x + 'px', top: y + 'px' });
    }

    function mousedown_handler(e) {
        var target = e.target;
        if(target.nodeName == "P") { target = target.parentNode; }
        var activity = $(target).hasClass('activity') ? target : null;
        if(activity) {
            select_activity(activity);
        }
        else if(!$(target).hasClass('cursor')) {
            mouse_position_cursor(e);
        }
    }

    function mouse_position_cursor(e) {
        unselect_activity();
        var x = Math.floor((e.layerX || e.offsetX) / x_inc) * x_inc;
        var y = Math.floor((e.layerY || e.offsetY) / y_inc) * y_inc;
        set_cursor_pos(x, y);
    }

    function dblclick_canvas(e) {
        activate_cursor();
    }

    function dblclick_activity(e) {
        dlg_activity.dialog('open');
        e.stopPropagation();
    }

    function current_activity_data() {
        if(app.current_activity) {
            return $(app.current_activity).tmplItem().data;
        }
        return null;
    }

    function default_activity_data() {
        return {
            wr_number   : '',
            hours       : app.default_duration,
            description : ''
        };
    }

    function key_handler(e) {
        var curr = null;
        if(app.current_activity) {
            curr = $(app.current_activity).tmplItem().data;
        }
        switch(e.keyCode) {
            case keyCode.LEFT:   move_cursor(-x_inc,  0); break;
            case keyCode.RIGHT:  move_cursor( x_inc,  0); break;
            case keyCode.ENTER:  activate_cursor();       break;
            case keyCode.UP:
                move_cursor(0, -y_inc);
                break;
            case keyCode.DOWN:
                move_cursor(0, curr ? curr.hours * 4 * y_inc : y_inc);
                break;
            case keyCode.DELETE: delete_activity();       break;
            default:
                if(e.ctrlKey && e.keyCode == 67) {  // Ctrl-C
                    copy_activity();
                }
                else if(e.ctrlKey && e.keyCode == 88) {  // Ctrl-X
                    copy_activity();
                    delete_activity();
                }
                else if(e.ctrlKey && e.keyCode == 86) {  // Ctrl-V
                    paste_activity();
                }
                else {
                    return;
                }
                break;
        }
        e.preventDefault();
    }

    function move_cursor(x_delta, y_delta) {
        var p = cursor.position();

        if(x_delta < 0 && p.left > 0    ) { p.left += x_delta; }
        if(x_delta > 0 && p.left < x_max) { p.left += x_delta; }
        if(y_delta < 0 && p.top  > 0    ) { p.top  += y_delta; }
        if(y_delta > 0 && p.top  < y_max) { p.top  += y_delta; }
        var activity = find_activity_at_cursor(p);
        if(activity) {
            select_activity(activity);
        }
        else {
            unselect_activity();
            set_cursor_pos(p.left, p.top);
        }
    }

    function find_activity_at_cursor(p) {
        return activities.find('.activity').filter(function() {
            var data = $(this).tmplItem().data;
            if(p.left != data.x) { return false; }
            if(p.top < data.y)  { return false; }
            if(p.top > (data.y + data.height))  {
                return false;
            }
            set_cursor_pos(data.x, data.y);
            return true;
        })[0];
    }

    function select_activity(activity) {
        if(app.current_activity == activity) {
            return;
        }
        unselect_activity();
        if(activity) {
            app.current_activity = activity;
            var $activity = $(activity);
            var p = $activity.position();
            set_cursor_pos(p.left, p.top);
            $activity.addClass('selected');
        }
    }

    function unselect_activity() {
        if(app.current_activity) {
            $(app.current_activity).removeClass('selected');
        }
        app.current_activity = null;
    }

    function delete_activity() {
        var activity = app.current_activity;
        if(!activity) {
            app_alert('You must select an activity first');
            return;
        }
        unselect_activity();
        $(activity).remove();
    }

    function copy_activity() {
        var data = current_activity_data();
        if(!data) {
            app_alert('You must select an activity first');
            return;
        }
        app.clipboard = $.extend({}, data);
    }

    function paste_activity() {
        var data = $.extend({}, app.clipboard);
        var activity = create_activity(data);
        select_activity( activity );
    }

    function activate_cursor() {
        dlg_activity.dialog('open');
    }

    function save_activity(data) {
        if(app.current_activity) {
            update_activity(data);
        }
        else {
            create_activity(data);
        }
    }

    function update_activity(data) {
        var tmpl_item = $(app.current_activity).tmplItem();
        var tmpl_data = tmpl_item.data;
        tmpl_data.wr_number   = data.wr_number;
        tmpl_data.hours       = data.hours;
        tmpl_data.description = data.description;
        tmpl_data.height      = data.hours * 4 * y_inc - app.border_allowance;
        tmpl_item.update();
    }

    function create_activity(data) {
        var p = cursor.position();
        data.height = data.hours * 4 * y_inc - app.border_allowance;
        data.x      = p.left;
        data.y      = p.top;
        var activity = $.tmpl("tmpl_activity", data);
        activity.dblclick(function(e) { dblclick_activity(e) });
        activities.append(activity);
        return activity;
    }

    function app_alert(message) {
        alert(message);
        week_hours.focus();           // Work-around keyboard focus being lost
        week_hours.css({'outline': 'none'});
    }

    function add_activity_dialog($app_el) {
        var div      = $('
');
        var wr_inp   = $('<input type="text" />');
        var hr_inp   = $('<input type="text" />').val(1);
        var desc_inp = $('<input type="text" />');
        div.append(
            $('
WR Number
').append(wr_inp),
            $('
Hours
').append(hr_inp),
            $('
Activity Description
').append(desc_inp)
        );

        div.dialog({
            autoOpen:      false,
            title:         "Activity Detail",
            resizable:     false,
            closeOnEscape: true,
            width:         360,
            height:        230,
            modal:         true,
            open: function() {
                var data = current_activity_data() || default_activity_data();
                wr_inp.val(data.wr_number);
                hr_inp.val(data.hours);
                desc_inp.val(data.description);
            },
            buttons:       {
                "Ok":  function() {
                    var data = {
                        wr_number   : wr_inp.val(),
                        hours       : hr_inp.val(),
                        description : desc_inp.val()
                    };
                    save_activity(data);
                    div.dialog("close");
                },
                "Cancel": function() { $(this).dialog("close"); }
            }
        });

        div.find('input').keydown(function(e) {
            if(e.keyCode == keyCode.ENTER) {
                div.parent().find('.ui-dialog-buttonpane button:first').click();
                e.stopPropagation();  // Don't allow Enter to re-launch dialog
            }
        });

        return div;
    }

};

$.fn.tksweb.defaults = {
    day_names        : [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ],
    first_hour       : 0,
    last_hour        : 23,
    scroll_to_hour   : 9,
    hour_height      : 48,  // must be a multiple of 4 and match bg-image bands
    activity_width   : 100,
    border_allowance : 2,   // top border thickness + bottom border
    default_duration : 1    // default number of hours for a new activity
};

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

/**
 * compare images
 */

var resemble = require('node-resemble-js');

module.exports = function() {

    /**
     * need to find done function because gm doesn't have node like callbacks (err,res)
     */
    var done = arguments[arguments.length - 1];

    /**
     * if there is no need for image comparison or no images gets saved on fs, just continue
     */
    if(!this.isComparable || !this.self.saveImages) {
        return done();
    }

    // This feature makes the output nearly worthless and impossible to read.
    // Set it high enought that we never hit it.
    resemble.outputOptions({largeImageThreshold:1000000000})

    /**
     * compare images
     */
    var diff = resemble(this.baselinePath).compareTo(this.regressionPath);

    /**
     * map 'ignore' configuration to resemble options
     */
    var ignore = this.currentArgs.ignore || "";
    if (ignore.indexOf("color") === 0) {
        diff.ignoreColors();
    } else if (ignore.indexOf("antialias") === 0) {
        diff.ignoreAntialiasing();
    }

    /**
     * execute the comparison
     */
    diff.onComplete(done.bind(null,null));
};
<commit_msg>largeImageThreshold: disable explicitly<commit_after>'use strict';

/**
 * compare images
 */

var resemble = require('node-resemble-js');

module.exports = function() {

    /**
     * need to find done function because gm doesn't have node like callbacks (err,res)
     */
    var done = arguments[arguments.length - 1];

    /**
     * if there is no need for image comparison or no images gets saved on fs, just continue
     */
    if(!this.isComparable || !this.self.saveImages) {
        return done();
    }

    // This feature makes the output nearly worthless and impossible to read.
    // Turn it off.
    resemble.outputOptions({largeImageThreshold:0})

    /**
     * compare images
     */
    var diff = resemble(this.baselinePath).compareTo(this.regressionPath);

    /**
     * map 'ignore' configuration to resemble options
     */
    var ignore = this.currentArgs.ignore || "";
    if (ignore.indexOf("color") === 0) {
        diff.ignoreColors();
    } else if (ignore.indexOf("antialias") === 0) {
        diff.ignoreAntialiasing();
    }

    /**
     * execute the comparison
     */
    diff.onComplete(done.bind(null,null));
};
<|endoftext|>


<commit_before>
// make a request to lastFM
function lastFM(data, callback){
  return reqwest({
    url:"http://ws.audioscrobbler.com/2.0/",
    data: data,
    type: 'xml',
    success: function(data){
      if(callback){callback(false, data)}
    },
    error: function(err){
      if(callback){callback(err)}
    }
  })
}

// generate data for a request
function requestData(api_key, user, page){
  return {
    method:'user.getrecenttracks',
    user:user,
    api_key:api_key,
    limit:200,
    page: page || 0
  }
}

// generate a list of request data objects
function requestList(api_key, user, page_count){
  var requests = [];
  for(var page = 0; page <= page_count; page++){
    requests.push(requestData(api_key, user, page))
  }
  return requests
}

// extract the data from the xml response
function extractTracks(doc){

  // probably nicer ways to do this
  var arr = [];
  var track, obj, child;
  var tracks = doc.evaluate('lfm/recenttracks/track', doc, null, XPathResult.ANY_TYPE, null)
  while (track = tracks.iterateNext()){
    obj = {};
    for (var i = track.childNodes.length - 1; i >= 0; i--) {
      child = track.childNodes[i];
      obj[child.tagName] = child.textContent;
    };
    arr.push(obj)
  }

  return arr;
}

function extractPageCount(doc){
  var recenttracks = doc.evaluate('lfm/recenttracks', doc, null, XPathResult.ANY_TYPE, null).iterateNext()
  return parseInt(recenttracks.getAttribute('totalPages'), 10)
}

// pull out a row of keys
function row(keys, obj){
  return keys.map(function(k){
    return obj[k]
  })
}

// create a csv row from an array
function csv(array){

  // this is not a world class csv generator
  return array.map(function(item){
    return  typeof(item) === 'string' ?
      item.replace(/[\",]/g,'') :
      item;
  }).join(',')
}

// delay a function by millis
function delay(fn, millis){
  return function(){
    var args = [].slice.call(arguments);
    setTimeout.apply(this, [fn,millis].concat(args));
  }
}

/*
var output = [];

// find the page count
lastFM(requestData(key, username))
.then(extractPageCount)
.then(function(page_count){

  // request all pages
  requestList(key, username, page_count)
  // .slice(0,30) // actually only 5
  .forEach(function(r,i){
    setTimeout(function(){
      lastFM(r)
      .then(extractTracks)
      .then(function(tracks){
        console.log('.')
        // output[0].map(function(d){return row(['artist', 'name', 'date'], d)}).map(csv).join('\n')
        output[i] = new Blob([tracks.map(function(d){return row(['artist', 'name', 'date'], d)}).map(csv).join('\n'),'\n'])
      })
    },  i * 1000)
  })
})

// b = new Blob(output, {type: 'text/csv'})
// saveAs(b)

*/
<commit_msg>Start at page `1`<commit_after>
// make a request to lastFM
function lastFM(data, callback){
  return reqwest({
    url:"http://ws.audioscrobbler.com/2.0/",
    data: data,
    type: 'xml',
    success: function(data){
      if(callback){callback(false, data)}
    },
    error: function(err){
      if(callback){callback(err)}
    }
  })
}

// generate data for a request
function requestData(api_key, user, page){
  return {
    method:'user.getrecenttracks',
    user:user,
    api_key:api_key,
    limit:200,
    page: page || 1
  }
}

// generate a list of request data objects
function requestList(api_key, user, page_count){
  var requests = [];
  for(var page = 1; page <= page_count; page++){
    requests.push(requestData(api_key, user, page))
  }
  return requests
}

// extract the data from the xml response
function extractTracks(doc){

  // probably nicer ways to do this
  var arr = [];
  var track, obj, child;
  var tracks = doc.evaluate('lfm/recenttracks/track', doc, null, XPathResult.ANY_TYPE, null)
  while (track = tracks.iterateNext()){
    obj = {};
    for (var i = track.childNodes.length - 1; i >= 0; i--) {
      child = track.childNodes[i];
      obj[child.tagName] = child.textContent;
    };
    arr.push(obj)
  }

  return arr;
}

function extractPageCount(doc){
  var recenttracks = doc.evaluate('lfm/recenttracks', doc, null, XPathResult.ANY_TYPE, null).iterateNext()
  return parseInt(recenttracks.getAttribute('totalPages'), 10)
}

// pull out a row of keys
function row(keys, obj){
  return keys.map(function(k){
    return obj[k]
  })
}

// create a csv row from an array
function csv(array){

  // this is not a world class csv generator
  return array.map(function(item){
    return  typeof(item) === 'string' ?
      item.replace(/[\",]/g,'') :
      item;
  }).join(',')
}

// delay a function by millis
function delay(fn, millis){
  return function(){
    var args = [].slice.call(arguments);
    setTimeout.apply(this, [fn,millis].concat(args));
  }
}

/*
var output = [];

// find the page count
lastFM(requestData(key, username))
.then(extractPageCount)
.then(function(page_count){

  // request all pages
  requestList(key, username, page_count)
  // .slice(0,30) // actually only 5
  .forEach(function(r,i){
    setTimeout(function(){
      lastFM(r)
      .then(extractTracks)
      .then(function(tracks){
        console.log('.')
        // output[0].map(function(d){return row(['artist', 'name', 'date'], d)}).map(csv).join('\n')
        output[i] = new Blob([tracks.map(function(d){return row(['artist', 'name', 'date'], d)}).map(csv).join('\n'),'\n'])
      })
    },  i * 1000)
  })
})

// b = new Blob(output, {type: 'text/csv'})
// saveAs(b)

*/
<|endoftext|>


<commit_before>var LongRangeView = Marionette.ItemView.extend({
    template: '#longRangeViewTpl',
    initialize: function(options) {
        this.throttledRender = _.throttle(this.render, 100);
        this.listenTo(this.model.attributes.weeks, 'add change:goal change:total remove reset', this.throttledRender);
    },
    templateHelpers: function() {
        // Do this computation only once per render.
        var maxMinutes = Math.max(420,
                _.max(this.model.attributes.weeks.pluck('total')),
                _.max(this.model.attributes.weeks.pluck('goal')));
        var PX_PER_MIN = (198 /*total usable width*/ / maxMinutes);
        var maxTicks = 5;
        // Choose an integer number of hours at which we can draw a tick.
        var hoursPerTick = Math.floor(maxMinutes / 60 / (maxTicks+1)) + 1;
        return {
            WEEK_HEIGHT_PX: 13,
            PX_PER_MIN: PX_PER_MIN,
            maxMinutes: maxMinutes,
            hoursPerTick: hoursPerTick,
            // Round so our 1px borders are aligned with the screen pixels.
            rm2p: function(min) {
                return Math.round(this.PX_PER_MIN * min);
            },
            totalBarClass: function(week) {
                return (week.attributes.total >= week.attributes.goal ?
                        "longRangeBarComplete" : "longRangeBarIncomplete");
            }
        };
    },
    events: {
        "click g.longRangeWeek":        "jumpToWeek",
        "mouseover g.longRangeWeek":    "mouseoverHistoryBar"
    },
    jumpToWeek: function(event) {
        var cid = $(event.currentTarget).data('cid');
        window.scrollToWeek(this.model.attributes.weeks.get(cid));
    },
    mouseoverHistoryBar: function(event) {
        var weeks = this.model.attributes.weeks;
        var cid = $(event.currentTarget).data('cid');
        showToolTipForWeek(weeks.get(cid), event.target);
    },
    mouseoutHistoryBar: function(event) {
        hideTooltipForWeek();
    }
});

function showToolTipForWeek(week, element) {
    var attrs = week.attributes;

    var beginStr = attrs.beginning.format("M/D");
    var endStr = attrs.end.format("M/D");
    var totalStr = formatDuration(attrs.total);
    var goalStr = formatDuration(attrs.goal);
    var success = attrs.total > attrs.goal;
    var content = '
' + beginStr + '–' + endStr + ':
';
    if (success) {
        content += '
Success!
';
        content += '
Did ';
    } else {
        content += '
Failure
';
        content += '
Only did ';
    }
    content += totalStr + ' out of ' + goalStr + '
';

    var tip = $('#historyToolTip');
    $(tip).css('opacity', 1);
    $(tip).html(content);

    moveToElementPlusOffset(tip, element, 215, -26);
}

function hideTooltipForWeek() {
    $(tip).css('opacity', 0);
}
<commit_msg>FIX history tooltips not hiding<commit_after>var LongRangeView = Marionette.ItemView.extend({
    template: '#longRangeViewTpl',
    initialize: function(options) {
        this.throttledRender = _.throttle(this.render, 100);
        this.listenTo(this.model.attributes.weeks, 'add change:goal change:total remove reset', this.throttledRender);
    },
    templateHelpers: function() {
        // Do this computation only once per render.
        var maxMinutes = Math.max(420,
                _.max(this.model.attributes.weeks.pluck('total')),
                _.max(this.model.attributes.weeks.pluck('goal')));
        var PX_PER_MIN = (198 /*total usable width*/ / maxMinutes);
        var maxTicks = 5;
        // Choose an integer number of hours at which we can draw a tick.
        var hoursPerTick = Math.floor(maxMinutes / 60 / (maxTicks+1)) + 1;
        return {
            WEEK_HEIGHT_PX: 13,
            PX_PER_MIN: PX_PER_MIN,
            maxMinutes: maxMinutes,
            hoursPerTick: hoursPerTick,
            // Round so our 1px borders are aligned with the screen pixels.
            rm2p: function(min) {
                return Math.round(this.PX_PER_MIN * min);
            },
            totalBarClass: function(week) {
                return (week.attributes.total >= week.attributes.goal ?
                        "longRangeBarComplete" : "longRangeBarIncomplete");
            }
        };
    },
    events: {
        "click g.longRangeWeek":        "jumpToWeek",
        "mouseover g.longRangeWeek":    "mouseoverHistoryBar"
    },
    jumpToWeek: function(event) {
        var cid = $(event.currentTarget).data('cid');
        window.scrollToWeek(this.model.attributes.weeks.get(cid));
    },
    mouseoverHistoryBar: function(event) {
        var weeks = this.model.attributes.weeks;
        var cid = $(event.currentTarget).data('cid');
        showToolTipForWeek(weeks.get(cid), event.target);
    },
    mouseoutHistoryBar: function(event) {
        hideTooltipForWeek();
    }
});

function showToolTipForWeek(week, element) {
    var attrs = week.attributes;

    var beginStr = attrs.beginning.format("M/D");
    var endStr = attrs.end.format("M/D");
    var totalStr = formatDuration(attrs.total);
    var goalStr = formatDuration(attrs.goal);
    var success = attrs.total > attrs.goal;
    var content = '
' + beginStr + '–' + endStr + ':
';
    if (success) {
        content += '
Success!
';
        content += '
Did ';
    } else {
        content += '
Failure
';
        content += '
Only did ';
    }
    content += totalStr + ' out of ' + goalStr + '
';

    var tip = $('#historyToolTip');
    $(tip).css('opacity', 1);
    $(tip).html(content);

    moveToElementPlusOffset(tip, element, 215, -26);
}

function hideTooltipForWeek() {
    $('#historyToolTip').css('opacity', 0);
}
<|endoftext|>


<commit_before>/*
 * MBP - Mobile boilerplate helper functions
 */
(function(document){

window.MBP = window.MBP || {};

// Fix for iPhone viewport scale bug
// http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/

MBP.scaleFix = function () {
  var i;
  var metas = document.getElementsByTagName('meta');
    if (navigator.userAgent.match(/iPhone/i) && !navigator.userAgent.match(/Opera/i)) {
      for (i=0; i<metas.length; i++) {
        if (metas[i].name == "viewport") {
          metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
        }
      }
      document.addEventListener("gesturestart", MBP.gestureStart, false);
    }
};

MBP.gestureStart = function () {
    var i;
    var metas = document.getElementsByTagName('meta');
    for (i=0; i<metas.length; i++) {
        if (metas[i].name == "viewport") {
          metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
        }
    }
}

// Hide URL Bar for iOS
// http://remysharp.com/2010/08/05/doing-it-right-skipping-the-iphone-url-bar/

MBP.hideUrlBar = function () {
    /iPhone/i.test(navigator.userAgent) && !pageYOffset && !location.hash && setTimeout(function () {
    window.scrollTo(0, 1);
    }, 1000);
};

// Fast Buttons
// http://code.google.com/mobile/articles/fast_buttons.html

MBP.fastButton = function (element, handler) {
    this.element = element;
    this.handler = handler;
    if (element.addEventListener) {
      element.addEventListener('touchstart', this, false);
      element.addEventListener('click', this, false);
    }
};

MBP.fastButton.prototype.handleEvent = function(event) {
    switch (event.type) {
        case 'touchstart': this.onTouchStart(event); break;
        case 'touchmove': this.onTouchMove(event); break;
        case 'touchend': this.onClick(event); break;
        case 'click': this.onClick(event); break;
    }
};

MBP.fastButton.prototype.onTouchStart = function(event) {
    event.stopPropagation();
    this.element.addEventListener('touchend', this, false);
    document.body.addEventListener('touchmove', this, false);
    this.startX = event.touches[0].clientX;
    this.startY = event.touches[0].clientY;
    this.element.style.backgroundColor = "rgba(0,0,0,.7)";
};

MBP.fastButton.prototype.onTouchMove = function(event) {
    if(Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) {
        this.reset();
    }
};

MBP.fastButton.prototype.onClick = function(event) {
    event.stopPropagation();
    this.reset();
    this.handler(event);
    if(event.type == 'touchend') {
        MBP.preventGhostClick(this.startX, this.startY);
    }
    this.element.style.backgroundColor = "";
};

MBP.fastButton.prototype.reset = function() {
    this.element.removeEventListener('touchend', this, false);
    document.body.removeEventListener('touchmove', this, false);
    this.element.style.backgroundColor = "";
};

MBP.preventGhostClick = function (x, y) {
    MBP.coords.push(x, y);
    window.setTimeout(function (){
        MBP.coords.splice(0, 2);
    }, 2500);
};

MBP.ghostClickHandler = function (event) {
    for(var i = 0, len = MBP.coords.length; i < len; i += 2) {
        var x = MBP.coords[i];
        var y = MBP.coords[i + 1];
        if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
            event.stopPropagation();
            event.preventDefault();
        }
    }
};

if (document.addEventListener) {
    document.addEventListener('click', MBP.ghostClickHandler, true);
}

MBP.coords = [];

// iOS Startup Image
// https://github.com/shichuan/mobile-html5-boilerplate/issues#issue/2

MBP.splash = function () {
    var filename = navigator.platform === 'iPad' ? 'h/' : 'l/';
    document.write('<link rel="apple-touch-startup-image" href="/img/' + filename + 'splash.png" />' );
};

// Autogrow
// http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series.html

MBP.autogrow = function (element, lh) {

    function handler(e){
        var newHeight = this.scrollHeight,
            currentHeight = this.clientHeight;
        if (newHeight > currentHeight) {
            this.style.height = newHeight + 3 * textLineHeight + "px";
        }
    }

    var setLineHeight = (lh) ? lh : 12,
        textLineHeight = element.currentStyle ? element.currentStyle.lineHeight :
                         getComputedStyle(element, null).lineHeight;

    textLineHeight = (textLineHeight.indexOf("px") == -1) ? setLineHeight :
                     parseInt(textLineHeight, 10);

    element.style.overflow = "hidden";
    element.addEventListener ? element.addEventListener('keyup', handler, false) :
                               element.attachEvent('onkeyup', handler);
};

})(document);

<commit_msg>cleanup of scaleFix() to be a little smarter and DRYer.<commit_after>/*
 * MBP - Mobile boilerplate helper functions
 */
(function(document){

window.MBP = window.MBP || {};

// Fix for iPhone viewport scale bug
// http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/

MBP.viewportmeta = document.querySelector && document.querySelector('meta[name="viewport"]');
MBP.ua = navigator.userAgent;

MBP.scaleFix = function () {
  if (MBP.viewportmeta && /iPhone|iPad/.test(MBP.ua) && !/Opera Mini/.test(MBP.ua)) {
    MBP.viewportmeta.content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
    document.addEventListener("gesturestart", MBP.gestureStart, false);
  }
};
MBP.gestureStart = function () {
    MBP.viewportmeta.content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
};

// Hide URL Bar for iOS
// http://remysharp.com/2010/08/05/doing-it-right-skipping-the-iphone-url-bar/

MBP.hideUrlBar = function () {
    /iPhone/.test(MBP.ua) && !pageYOffset && !location.hash && setTimeout(function () {
      window.scrollTo(0, 1);
    }, 1000);
};

// Fast Buttons
// http://code.google.com/mobile/articles/fast_buttons.html

MBP.fastButton = function (element, handler) {
    this.element = element;
    this.handler = handler;
    if (element.addEventListener) {
      element.addEventListener('touchstart', this, false);
      element.addEventListener('click', this, false);
    }
};

MBP.fastButton.prototype.handleEvent = function(event) {
    switch (event.type) {
        case 'touchstart': this.onTouchStart(event); break;
        case 'touchmove': this.onTouchMove(event); break;
        case 'touchend': this.onClick(event); break;
        case 'click': this.onClick(event); break;
    }
};

MBP.fastButton.prototype.onTouchStart = function(event) {
    event.stopPropagation();
    this.element.addEventListener('touchend', this, false);
    document.body.addEventListener('touchmove', this, false);
    this.startX = event.touches[0].clientX;
    this.startY = event.touches[0].clientY;
    this.element.style.backgroundColor = "rgba(0,0,0,.7)";
};

MBP.fastButton.prototype.onTouchMove = function(event) {
    if(Math.abs(event.touches[0].clientX - this.startX) > 10 || Math.abs(event.touches[0].clientY - this.startY) > 10) {
        this.reset();
    }
};

MBP.fastButton.prototype.onClick = function(event) {
    event.stopPropagation();
    this.reset();
    this.handler(event);
    if(event.type == 'touchend') {
        MBP.preventGhostClick(this.startX, this.startY);
    }
    this.element.style.backgroundColor = "";
};

MBP.fastButton.prototype.reset = function() {
    this.element.removeEventListener('touchend', this, false);
    document.body.removeEventListener('touchmove', this, false);
    this.element.style.backgroundColor = "";
};

MBP.preventGhostClick = function (x, y) {
    MBP.coords.push(x, y);
    window.setTimeout(function (){
        MBP.coords.splice(0, 2);
    }, 2500);
};

MBP.ghostClickHandler = function (event) {
    for(var i = 0, len = MBP.coords.length; i < len; i += 2) {
        var x = MBP.coords[i];
        var y = MBP.coords[i + 1];
        if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
            event.stopPropagation();
            event.preventDefault();
        }
    }
};

if (document.addEventListener) {
    document.addEventListener('click', MBP.ghostClickHandler, true);
}

MBP.coords = [];

// iOS Startup Image
// https://github.com/shichuan/mobile-html5-boilerplate/issues#issue/2

MBP.splash = function () {
    var filename = navigator.platform === 'iPad' ? 'h/' : 'l/';
    document.write('<link rel="apple-touch-startup-image" href="/img/' + filename + 'splash.png" />' );
};

// Autogrow
// http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series.html

MBP.autogrow = function (element, lh) {

    function handler(e){
        var newHeight = this.scrollHeight,
            currentHeight = this.clientHeight;
        if (newHeight > currentHeight) {
            this.style.height = newHeight + 3 * textLineHeight + "px";
        }
    }

    var setLineHeight = (lh) ? lh : 12,
        textLineHeight = element.currentStyle ? element.currentStyle.lineHeight :
                         getComputedStyle(element, null).lineHeight;

    textLineHeight = (textLineHeight.indexOf("px") == -1) ? setLineHeight :
                     parseInt(textLineHeight, 10);

    element.style.overflow = "hidden";
    element.addEventListener ? element.addEventListener('keyup', handler, false) :
                               element.attachEvent('onkeyup', handler);
};

})(document);

<|endoftext|>


<commit_before>/*global define */
/*
 | Copyright 2014 Esri
 |
 | Licensed 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.
 */
define({
    root: ({
        map: {  // Map, feature layer, and comments table loading and checking
            error: "Unable to create map",
            layerLoad: "Unable to fully load map",
            missingItemsFeatureLayer: "Please configure the application to use a feature layer"
        },
        sidebar_header: {  // Top panel of right-side display; contains social media sign-in, help button, title
            menuButtonTooltip: "Show menu",
            signInButton: "Sign In",
            signInButtonTooltip: "Sign in",
            signOutButton: "Sign Out",
            signOutButtonTooltip: "Sign out",
            helpButtonLabel: "Help",
            helpButtonTooltip: "Learn more",
            gotoListViewLabel: "List View",
            gotoListViewTooltip: "Go to list view", // Go to List view tooltip text
            gotoMapViewLabel: "Map View",
            gotoMapViewTooltip: "Go to map view" // Tooltip for map-it icon in list header
        },
        popup_Close: {  // Close button for help and social-media-sign-in popup box
            closeButtonTooltip: "Close"
        },
        social_media: {  // Social media sign-in/out
            signIntoFacebookTooltip: "Sign in with Facebook",
            signIntoGooglePlusTooltip: "Sign in with Google+",
            signIntoTwitterTooltip: "Sign in with Twitter",
            signOutOfFacebookTooltip: "Sign out of Facebook",
            signOutOfGooglePlusTooltip: "Sign out of Google+",
            signOutOfTwitterTooltip: "Sign out of Twitter"
        },
        dynamic_form: {  // General-purpose form; used to receive comment entry
            optionalFormItemFlag: " (optional)",
            requiredFormItemFlag: " (required)",
            unsettableRequiredField: "A required field is neither initialized nor in the form",
            countOfRemainingCharactersTooltip: "Characters remaining",
            cancelButtonLabel: "Cancel",
            submitButtonLabel: "Submit"
        },
        item_details: {  // Detailed information about an item and a list of its comments
            likeButtonTooltip: "Vote for this item",
            commentButtonTooltip: "Add a comment",
            gotoMapViewTooltip: "Go to map view",
            galleryButtonTooltip: "See attached files",
            commentsListHeading: "Comments",
            noCommentsPlaceholder: "No comments"
        },
        item_list: {  // List of feature layer items
            linkToMapViewOptionLabel: "Filter list by map",
            linkToMapViewOptionTooltip: "List features that are visible in the current map",
            likesForThisItemTooltip: "Votes for this item"
        }
    }),
    "ar": 0,
    "cs": 0,
    "da": 0,
    "de": 0,
    "el": 0,
    "es": 0,
    "et": 0,
    "fi": 0,
    "fr": 1,
    "he": 0,
    "it": 0,
    "ja": 0,
    "ko": 0,
    "lt": 0,
    "lv": 0,
    "nb": 0,
    "nl": 0,
    "pl": 0,
    "pt-br": 0,
    "pt-pt": 0,
    "ro": 0,
    "ru": 0,
    "sv": 0,
    "th": 0,
    "tr": 0,
    "vi": 0,
    "zh-cn": 0,
    "zh-hk": 0,
    "zh-tw": 0
});
<commit_msg>Enabled languages<commit_after>/*global define */
/*
 | Copyright 2014 Esri
 |
 | Licensed 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.
 */
define({
    root: ({
        map: {  // Map, feature layer, and comments table loading and checking
            error: "Unable to create map",
            layerLoad: "Unable to fully load map",
            missingItemsFeatureLayer: "Please configure the application to use a feature layer"
        },
        sidebar_header: {  // Top panel of right-side display; contains social media sign-in, help button, title
            menuButtonTooltip: "Show menu",
            signInButton: "Sign In",
            signInButtonTooltip: "Sign in",
            signOutButton: "Sign Out",
            signOutButtonTooltip: "Sign out",
            helpButtonLabel: "Help",
            helpButtonTooltip: "Learn more",
            gotoListViewLabel: "List View",
            gotoListViewTooltip: "Go to list view", // Go to List view tooltip text
            gotoMapViewLabel: "Map View",
            gotoMapViewTooltip: "Go to map view" // Tooltip for map-it icon in list header
        },
        popup_Close: {  // Close button for help and social-media-sign-in popup box
            closeButtonTooltip: "Close"
        },
        social_media: {  // Social media sign-in/out
            signIntoFacebookTooltip: "Sign in with Facebook",
            signIntoGooglePlusTooltip: "Sign in with Google+",
            signIntoTwitterTooltip: "Sign in with Twitter",
            signOutOfFacebookTooltip: "Sign out of Facebook",
            signOutOfGooglePlusTooltip: "Sign out of Google+",
            signOutOfTwitterTooltip: "Sign out of Twitter"
        },
        dynamic_form: {  // General-purpose form; used to receive comment entry
            optionalFormItemFlag: " (optional)",
            requiredFormItemFlag: " (required)",
            unsettableRequiredField: "A required field is neither initialized nor in the form",
            countOfRemainingCharactersTooltip: "Characters remaining",
            cancelButtonLabel: "Cancel",
            submitButtonLabel: "Submit"
        },
        item_details: {  // Detailed information about an item and a list of its comments
            likeButtonTooltip: "Vote for this item",
            commentButtonTooltip: "Add a comment",
            gotoMapViewTooltip: "Go to map view",
            galleryButtonTooltip: "See attached files",
            commentsListHeading: "Comments",
            noCommentsPlaceholder: "No comments"
        },
        item_list: {  // List of feature layer items
            linkToMapViewOptionLabel: "Filter list by map",
            linkToMapViewOptionTooltip: "List features that are visible in the current map",
            likesForThisItemTooltip: "Votes for this item"
        }
    }),
    "ar": 1,
    "cs": 1,
    "da": 1,
    "de": 1,
    "el": 1,
    "es": 1,
    "et": 1,
    "fi": 1,
    "fr": 1,
    "he": 1,
    "it": 1,
    "ja": 1,
    "ko": 1,
    "lt": 1,
    "lv": 1,
    "nb": 1,
    "nl": 1,
    "pl": 1,
    "pt-br": 1,
    "pt-pt": 1,
    "ro": 1,
    "ru": 1,
    "sv": 1,
    "th": 1,
    "tr": 1,
    "vi": 1,
    "zh-cn": 1,
    "zh-hk": 1,
    "zh-tw": 1
});
<|endoftext|>


<commit_before>/*
 | Copyright 2014 Esri
 |
 | Licensed 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.
 */
define({
    root: ({
        map: {  // Map, feature layer, and comments table loading and checking
            error: "Unable to create map",
            layerLoad: "Unable to fully load map",
            missingItemsFeatureLayer: "Please configure the application to use a feature layer"
        },
        sidebar_header: {  // Top panel of right-side display; contains social media sign-in, help button, title
            menuButtonTooltip: "Show menu",
            signInButton: "Sign In",
            signInButtonTooltip: "Sign in",
            signOutButton: "Sign Out",
            signOutButtonTooltip: "Sign out",
            helpButtonLabel: "Help",
            helpButtonTooltip: "Learn more",
            gotoListViewLabel: "List View",
            gotoListViewTooltip: "Go to list view", // Go to List view tooltip text
            gotoMapViewLabel: "Map View",
            gotoMapViewTooltip: "Go to map view" // Tooltip for map-it icon in list header
        },
        popup_Close: {  // Close button for help and social-media-sign-in popup box
            closeButtonTooltip: "Close"
        },
        social_media: {  // Social media sign-in/out
            signIntoFacebookTooltip: "Sign in with Facebook",
            signIntoGooglePlusTooltip: "Sign in with Google+",
            signIntoTwitterTooltip: "Sign in with Twitter",
            signOutOfFacebookTooltip: "Sign out of Facebook",
            signOutOfGooglePlusTooltip: "Sign out of Google+",
            signOutOfTwitterTooltip: "Sign out of Twitter"
        },
        dynamic_form: {  // General-purpose form; used to receive comment entry
            optionalFormItemFlag: " (optional)",
            requiredFormItemFlag: " (required)",
            unsettableRequiredField: "A required field is neither initialized nor in the form",
            countOfRemainingCharactersTooltip: "Characters remaining",
            attachmentsHeading: "Attachments",
            addAttachmentTooltip: "Add attachment",
            removeAttachmentTooltip: "Remove attachment",
            cancelButtonLabel: "Cancel",
            submitButtonLabel: "Submit"
        },
        item_details: {  // Detailed information about an item and a list of its comments
            likeButtonTooltip: "Vote for this item",
            likeButtonInverseTooltip: "Vote counted",
            commentButtonTooltip: "Add a comment",
            gotoMapViewTooltip: "Go to map view",
            galleryButtonTooltip: "See attached files",
            commentsListHeading: "Comments",
            noCommentsPlaceholder: "No comments"
        },
        item_list: {  // List of feature layer items
            linkToMapViewOptionLabel: "Filter list by map",
            linkToMapViewOptionTooltip: "List features that are visible in the current map",
            likesForThisItemTooltip: "Votes for this item"
        }
    }),
    "ar": 1,
    "bs": 1,
    "cs": 1,
    "da": 1,
    "de": 1,
    "el": 1,
    "es": 1,
    "et": 1,
    "fi": 1,
    "fr": 1,
    "he": 1,
    "hr": 1,
    "id": 1,
    "it": 1,
    "ja": 1,
    "ko": 1,
    "lt": 1,
    "lv": 1,
    "nb": 1,
    "nl": 1,
    "pl": 1,
    "pt-br": 1,
    "pt-pt": 1,
    "ro": 1,
    "ru": 1,
    "sr": 1,
    "sv": 1,
    "th": 1,
    "tr": 1,
    "vi": 1,
    "zh-cn": 1,
    "zh-hk": 1,
    "zh-tw": 1
});
<commit_msg>Added Hindi<commit_after>/*
 | Copyright 2014 Esri
 |
 | Licensed 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.
 */
define({
    root: ({
        map: {  // Map, feature layer, and comments table loading and checking
            error: "Unable to create map",
            layerLoad: "Unable to fully load map",
            missingItemsFeatureLayer: "Please configure the application to use a feature layer"
        },
        sidebar_header: {  // Top panel of right-side display; contains social media sign-in, help button, title
            menuButtonTooltip: "Show menu",
            signInButton: "Sign In",
            signInButtonTooltip: "Sign in",
            signOutButton: "Sign Out",
            signOutButtonTooltip: "Sign out",
            helpButtonLabel: "Help",
            helpButtonTooltip: "Learn more",
            gotoListViewLabel: "List View",
            gotoListViewTooltip: "Go to list view", // Go to List view tooltip text
            gotoMapViewLabel: "Map View",
            gotoMapViewTooltip: "Go to map view" // Tooltip for map-it icon in list header
        },
        popup_Close: {  // Close button for help and social-media-sign-in popup box
            closeButtonTooltip: "Close"
        },
        social_media: {  // Social media sign-in/out
            signIntoFacebookTooltip: "Sign in with Facebook",
            signIntoGooglePlusTooltip: "Sign in with Google+",
            signIntoTwitterTooltip: "Sign in with Twitter",
            signOutOfFacebookTooltip: "Sign out of Facebook",
            signOutOfGooglePlusTooltip: "Sign out of Google+",
            signOutOfTwitterTooltip: "Sign out of Twitter"
        },
        dynamic_form: {  // General-purpose form; used to receive comment entry
            optionalFormItemFlag: " (optional)",
            requiredFormItemFlag: " (required)",
            unsettableRequiredField: "A required field is neither initialized nor in the form",
            countOfRemainingCharactersTooltip: "Characters remaining",
            attachmentsHeading: "Attachments",
            addAttachmentTooltip: "Add attachment",
            removeAttachmentTooltip: "Remove attachment",
            cancelButtonLabel: "Cancel",
            submitButtonLabel: "Submit"
        },
        item_details: {  // Detailed information about an item and a list of its comments
            likeButtonTooltip: "Vote for this item",
            likeButtonInverseTooltip: "Vote counted",
            commentButtonTooltip: "Add a comment",
            gotoMapViewTooltip: "Go to map view",
            galleryButtonTooltip: "See attached files",
            commentsListHeading: "Comments",
            noCommentsPlaceholder: "No comments"
        },
        item_list: {  // List of feature layer items
            linkToMapViewOptionLabel: "Filter list by map",
            linkToMapViewOptionTooltip: "List features that are visible in the current map",
            likesForThisItemTooltip: "Votes for this item"
        }
    }),
    "ar": 1,
    "bs": 1,
    "cs": 1,
    "da": 1,
    "de": 1,
    "el": 1,
    "es": 1,
    "et": 1,
    "fi": 1,
    "fr": 1,
    "he": 1,
    "hi": 1,
    "hr": 1,
    "id": 1,
    "it": 1,
    "ja": 1,
    "ko": 1,
    "lt": 1,
    "lv": 1,
    "nb": 1,
    "nl": 1,
    "pl": 1,
    "pt-br": 1,
    "pt-pt": 1,
    "ro": 1,
    "ru": 1,
    "sr": 1,
    "sv": 1,
    "th": 1,
    "tr": 1,
    "vi": 1,
    "zh-cn": 1,
    "zh-hk": 1,
    "zh-tw": 1
});
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

var DEFAULT_PRIORITY = 1000;

function Event() { }

Event.prototype = {
  stopPropagation: function() {
    this.propagationStopped = true;
  },
  preventDefault: function() {
    this.defaultPrevented = true;
  },
  isPropagationStopped: function() {
    return !!this.propagationStopped;
  },
  isDefaultPrevented: function() {
    return !!this.defaultPrevented;
  }
};

/**
 * @class
 *
 * A general purpose event bus
 */
function EventBus() {
  this._listeners = {};
}

module.exports = EventBus;

module.exports.Event = Event;

/**
 * Register an event listener for events with the given name.
 *
 * The callback will be invoked with `event, ...additionalArguments`
 * that have been passed to the evented elements
 *
 * @param {String|Array<String>} events
 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
 * @param {Function} callback
 */
EventBus.prototype.on = function(events, priority, callback) {

  events = _.isArray(events) ? events : [ events ];

  if (_.isFunction(priority)) {
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!_.isNumber(priority)) {
    throw new Error('priority needs to be a number');
  }

  var self = this,
      listener = { priority: priority, callback: callback };

  _.forEach(events, function(e) {
    self._addListener(e, listener);
  });
};

/**
 * Register an event listener that is executed only once.
 *
 * @param {String} event the event name to register for
 * @param {Function} callback the callback to execute
 */
EventBus.prototype.once = function(event, callback) {

  var self = this;
  var wrappedCallback = function() {
    var eventType = arguments[0].type;
    callback.apply(self, arguments);
    self.off(eventType, wrappedCallback);
  };

  this.on(event, wrappedCallback);
};

/**
 * Removes event listeners by event and callback.
 *
 * If no callback is given, all listeners for a given event name are being removed.
 *
 * @param {String} event
 * @param {Function} [callback]
 */
EventBus.prototype.off = function(event, callback) {
  var listeners = this._getListeners(event),
      l, i;

  if (callback) {

    // move through listeners from back to front
    // and remove matching listeners
    for (i = listeners.length - 1; !!(l = listeners[i]); i--) {
      if (l.callback === callback) {
        listeners.splice(i, 1);
      }
    }
  } else {
    // clear listeners
    listeners.length = 0;
  }
};

/**
 * Fires a named event.
 *
 * @example
 *
 * // fire event by name
 * events.fire('foo');
 *
 * // fire event object with nested type
 * var event = { type: 'foo' };
 * events.fire(event);
 *
 * // fire event with explicit type
 * var event = { x: 10, y: 20 };
 * events.fire('element.moved', event);
 *
 * // pass additional arguments to the event
 * events.on('foo', function(event, bar) {
 *   alert(bar);
 * });
 *
 * events.fire({ type: 'foo' }, 'I am bar!');
 *
 * @param {String} [name] the optional event name
 * @param {Object} [event] the event object
 * @param {...Object} additional arguments to be passed to the callback functions
 *
 * @return {Boolean} false if default was prevented
 */
EventBus.prototype.fire = function() {

  var event, eventType,
      listeners, i, l,
      args;

  args = Array.prototype.slice.call(arguments);

  eventType = args[0];

  if (_.isObject(eventType)) {
    event = eventType;

    // parse type from event
    eventType = event.type;
  } else {
    // remove name parameter
    args.shift();

    event = args[0] || {};
    event.type = eventType;

    if (!args.length) {
      args.push(event);
    }
  }

  listeners = this._getListeners(eventType);
  event = this._extendEvent(event, eventType);

  for (i = 0, l; !!(l = listeners[i]); i++) {
    if (event.isPropagationStopped()) {
      break;
    }

    try {
      l.callback.apply(this, args);
    } catch (e) {
      if (!this.handleError(e)) {
        console.error('unhandled error in event listener', e);
        throw e;
      }
    }
  }

  return !event.isDefaultPrevented();
};

EventBus.prototype.handleError = function(error) {
  return !this.fire('error', { error: error });
};

EventBus.prototype._addListener = function(event, listener) {

  var listeners = this._getListeners(event),
      i, l;

  // ensure we order listeners by priority from
  // 0 (high) to n > 0 (low)
  for (i = 0; !!(l = listeners[i]); i++) {
    if (l.priority < listener.priority) {
      listeners.splice(i, 0, listener);
      return;
    }
  }

  listeners.push(listener);
};

EventBus.prototype._getListeners = function(name) {
  var listeners = this._listeners[name];

  if (!listeners) {
    this._listeners[name] = listeners = [];
  }

  return listeners;
};

EventBus.prototype._extendEvent = function(event, type) {
  return _.extend(event, Event.prototype, { type: type });
};<commit_msg>fix(core): properly destroy eventBus<commit_after>'use strict';

var _ = require('lodash');

var DEFAULT_PRIORITY = 1000;

function Event() { }

Event.prototype = {
  stopPropagation: function() {
    this.propagationStopped = true;
  },
  preventDefault: function() {
    this.defaultPrevented = true;
  },
  isPropagationStopped: function() {
    return !!this.propagationStopped;
  },
  isDefaultPrevented: function() {
    return !!this.defaultPrevented;
  }
};

/**
 * @class
 *
 * A general purpose event bus
 */
function EventBus() {
  this._listeners = {};

  // cleanup on destroy

  var self = this;

  this.on('diagram.destroy', function() {
    self._listeners = null;
  });
}

module.exports = EventBus;

module.exports.Event = Event;

/**
 * Register an event listener for events with the given name.
 *
 * The callback will be invoked with `event, ...additionalArguments`
 * that have been passed to the evented elements
 *
 * @param {String|Array<String>} events
 * @param {Number} [priority=1000] the priority in which this listener is called, larger is higher
 * @param {Function} callback
 */
EventBus.prototype.on = function(events, priority, callback) {

  events = _.isArray(events) ? events : [ events ];

  if (_.isFunction(priority)) {
    callback = priority;
    priority = DEFAULT_PRIORITY;
  }

  if (!_.isNumber(priority)) {
    throw new Error('priority needs to be a number');
  }

  var self = this,
      listener = { priority: priority, callback: callback };

  _.forEach(events, function(e) {
    self._addListener(e, listener);
  });
};

/**
 * Register an event listener that is executed only once.
 *
 * @param {String} event the event name to register for
 * @param {Function} callback the callback to execute
 */
EventBus.prototype.once = function(event, callback) {

  var self = this;
  var wrappedCallback = function() {
    var eventType = arguments[0].type;
    callback.apply(self, arguments);
    self.off(eventType, wrappedCallback);
  };

  this.on(event, wrappedCallback);
};

/**
 * Removes event listeners by event and callback.
 *
 * If no callback is given, all listeners for a given event name are being removed.
 *
 * @param {String} event
 * @param {Function} [callback]
 */
EventBus.prototype.off = function(event, callback) {
  var listeners = this._getListeners(event),
      l, i;

  if (callback) {

    // move through listeners from back to front
    // and remove matching listeners
    for (i = listeners.length - 1; !!(l = listeners[i]); i--) {
      if (l.callback === callback) {
        listeners.splice(i, 1);
      }
    }
  } else {
    // clear listeners
    listeners.length = 0;
  }
};

/**
 * Fires a named event.
 *
 * @example
 *
 * // fire event by name
 * events.fire('foo');
 *
 * // fire event object with nested type
 * var event = { type: 'foo' };
 * events.fire(event);
 *
 * // fire event with explicit type
 * var event = { x: 10, y: 20 };
 * events.fire('element.moved', event);
 *
 * // pass additional arguments to the event
 * events.on('foo', function(event, bar) {
 *   alert(bar);
 * });
 *
 * events.fire({ type: 'foo' }, 'I am bar!');
 *
 * @param {String} [name] the optional event name
 * @param {Object} [event] the event object
 * @param {...Object} additional arguments to be passed to the callback functions
 *
 * @return {Boolean} false if default was prevented
 */
EventBus.prototype.fire = function() {

  var event, eventType,
      listeners, i, l,
      args;

  args = Array.prototype.slice.call(arguments);

  eventType = args[0];

  if (_.isObject(eventType)) {
    event = eventType;

    // parse type from event
    eventType = event.type;
  } else {
    // remove name parameter
    args.shift();

    event = args[0] || {};
    event.type = eventType;

    if (!args.length) {
      args.push(event);
    }
  }

  listeners = this._getListeners(eventType);
  event = this._extendEvent(event, eventType);

  for (i = 0, l; !!(l = listeners[i]); i++) {
    if (event.isPropagationStopped()) {
      break;
    }

    try {
      l.callback.apply(this, args);
    } catch (e) {
      if (!this.handleError(e)) {
        console.error('unhandled error in event listener', e);
        throw e;
      }
    }
  }

  return !event.isDefaultPrevented();
};

EventBus.prototype.handleError = function(error) {
  return !this.fire('error', { error: error });
};

EventBus.prototype._addListener = function(event, listener) {

  var listeners = this._getListeners(event),
      i, l;

  // ensure we order listeners by priority from
  // 0 (high) to n > 0 (low)
  for (i = 0; !!(l = listeners[i]); i++) {
    if (l.priority < listener.priority) {
      listeners.splice(i, 0, listener);
      return;
    }
  }

  listeners.push(listener);
};

EventBus.prototype._getListeners = function(name) {
  var listeners = this._listeners[name];

  if (!listeners) {
    this._listeners[name] = listeners = [];
  }

  return listeners;
};

EventBus.prototype._extendEvent = function(event, type) {
  return _.extend(event, Event.prototype, { type: type });
};<|endoftext|>


<commit_before>// OpenWrap v2
// Author: Nuno Aguiar
// Metrics

OpenWrap.metrics = function() {
	return ow.metrics;
};

OpenWrap.metrics.prototype.__m = {
    mem: () => {
        var res = {
            max: Number(java.lang.Runtime.getRuntime().maxMemory()),
            total: Number(java.lang.Runtime.getRuntime().totalMemory()),
            free: Number(java.lang.Runtime.getRuntime().freeMemory())
        };
        res.used = res.total - res.free;
        return res;
    },
    cpu: () => ({
        load1 : getCPULoad(),
        load2 : getCPULoad(true),
        cores : getNumberOfCores(),
        _cores: __cpucores
    }),
    oaf: () => {
        var res = {
            libs : __loadedLibs,
            nlibs: Object.keys(__loadedLibs).length,
            nscopes: af.getScopeIds().length,
            preCompileLevel: __preCompileLevel,
            version: getVersion(),
            path   : getOpenAFPath(),
            java   : String(java.lang.System.getProperty("java.version")),
            javapath: String(java.lang.System.getProperty("java.home")),
            os     : String(java.lang.System.getProperty("os.name")),
            init   : __oafInit,
            now    : now(),
            logErr : __clogErr.get(),
            logWarn: __clogWarn.get(),
            cpuCores: __cpucores,
            threadPoolFactor: __threadPoolFactor,
            bottlenecks: (isDef(global.__bottleneck) ? Object.keys(global.__bottleneck).map(r => ({
                name    : r,
                running : global.__bottleneck[r].atomic.get(),
                maxWait : global.__bottleneck[r].attw,
                maxExecs: global.__bottleneck[r].ance
            })) : "n/a"),
            cache: (isDef(global.__cache) ? Object.keys(global.__cache).map(r => ({
                name: r,
                chName: global.__cache[r].name,
                ttl : global.__cache[r].ttl,
                maxSize: global.__cache[r].msize,
                size: global.__cache[r].size(),
                hits: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].hits,
                miss: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].miss,
                avgExecTime: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].avg,
            })) : "n/a"),
            rest: (isDef(global.__openaf_rest) ? Object.keys(global.__openaf_rest.urls).map(r => ({
                url: r,
                hits: _$(global.__openaf_rest.urls[r].c).default(0),
                miss: _$(global.__openaf_rest.urls[r].f).default(0)
            })) : "n/a"),
            fns    : ow.metrics.__fnMetrics
        };
        if (isDef(res.fns)) {
            Object.keys(res.fns).map(r => {
                res.fns[r].avg = res.fns[r].sum / (res.fns[r].err + res.fns[r].end);
            });
        }
        return res;
    },
    ojob: () => {
        var res = {};
        if (isDef(ow.oJob)) {
            res = ow.oJob.getLogCh().getAll().map(j => ({
                name : j.name,
                start: j.count,
                //err  : $path(j.log, "[?not_null(error)] | length(@)"),
                //end  : $path(j.log, "[?!not_null(error)] | length(@)"),
                error: j.error,
                sum  : j.totalTime,
                avg  : j.avgTime
            }) );
        }
        return res;
    },
    os: () => ({
        pid: getPid()
    }),
    threads: () => {
        var res = {
            list  : af.fromJavaArray(java.lang.Thread.getAllStackTraces().keySet().toArray()).map(t => ({
                id      : t.getId(),
                name    : String(t.getName()),
                isAlive : t.isAlive(),
                priority: Number(t.getPriority()),
                state   : String(t.getState())
            })),
            active: Number(java.lang.Thread.activeCount()),
            total : Number(java.lang.Thread.getAllStackTraces().size())
        };
        res.states = {};
        res.list.map(r => {
            if (isUnDef(res.states[r.state]))
                res.states[r.state] = 1;
            else
                res.states[r.state] += 1;
        });
        return res;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.add(aName, aFunction)</key>
 * Adds aName metric whose values are a map returned by aFunction.
 * </odoc>
 */
OpenWrap.metrics.prototype.add = function(aName, aFn) {
    if (isUnDef(ow.metrics.__m[aName])) {
        ow.metrics.__m[aName] = aFn;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.getSome(anArrayOfNames) : Map</key>
 * Returns just the metrics in the provided anArrayOfNames.
 * </odoc>
 */
OpenWrap.metrics.prototype.getSome = function(aArray) {
    var r = {};
    aArray.map(f => {
        r[f] = ow.metrics.__m[f]();
    });
    return r;
};

/**
 * <odoc>
 * <key>ow.metrics.getAll() : Map</key>
 * Returns a map with all registered metrics.
 * </odoc>
 */
OpenWrap.metrics.prototype.getAll = function() {
    return ow.metrics.getSome(Object.keys(ow.metrics.__m));
};

/**
 * <odoc>
 * <key>ow.metrics.startCollecting(aChName, aPeriod, some)</key>
 * Starts collecting metrics on aChName (defaults to '__metrics') every aPeriod ms (defaults to 1000ms) optionally just some (array) metrics.
 * </odoc>
 */
OpenWrap.metrics.prototype.startCollecting = function(aChName, aPeriod, aSome) {
    var createCh = isUnDef(aChName) || $ch().list().indexOf(aChName) < 0;

    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};

    aChName = _$(aChName).isString().default("__metrics");
    aPeriod = _$(aPeriod).isNumber().default(1000);

    if (createCh) $ch(aChName).create(1, "mvs", { file: "metrics.db" });

    if (isUnDef(ow.metrics.__ch)) ow.metrics.__ch = [];
    ow.metrics.__ch.push(aChName);

    if (isUnDef(ow.metrics.__t)) {
        plugin("Threads");
        ow.metrics.__t = new Threads();
        ow.metrics.__t.addScheduleThreadWithFixedDelay(function() {
            var k = { t: now() };
            var v;
            if(isArray(aSome))
               v = merge(k, ow.metrics.getSome(aSome));
            else
	       v = merge(k, ow.metrics.getAll());

            ow.metrics.__ch.map(ch => {
                $ch(ch).set(k, v);
            });
        }, aPeriod);
        ow.metrics.__t.startNoWait();
    }
};

/**
 * <odoc>
 * <key>ow.metrics.stopCollecting(aChName)</key>
 * Stops collecting metrics on aChName (defaults to '__metrics')
 * </odoc>
 */
OpenWrap.metrics.prototype.stopCollecting = function(aChName) {
    aChName = _$(aChName).isString().default("__metrics");
    if (ow.metrics.__ch.indexOf(aChName) < 0) throw "Not collecting into " + aChName;

    ow.metrics.__ch = deleteFromArray(ow.metrics.__ch, ow.metrics.__ch.indexOf(aChName));
    if (isDef(ow.metrics.__t) && ow.metrics.__ch.length <= 0) {
        ow.metrics.__t.stop(true);
        ow.metrics.__t = void 0;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.collectMetrics4Fn(aName, aFn)</key>
 * Adds extra code to an existing aFn to collect functions metrics under the name aName. If the same aName and aFn
 * has been already executed before it will throw an exception "Already collecting for the provided function."
 * </odoc>
 */
OpenWrap.metrics.prototype.collectMetrics4Fn = function(aName, aFn) {
    _$(aName, "name").isString().$_();
    _$(aFn, "fn").isString().$_();

    var aBody = eval(aFn).toString();
    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};
    if (isDef(ow.metrics.__fnMetrics[aName])) throw "Already collecting for the provided function.";

    aBody = aBody.split(/\n/);
    var newBody = [];
    ow.metrics.__fnMetrics[aName] = {
        start: 0,
        err  : 0,
        end  : 0,
        sum  : 0,
        avg  : 0
    };

    for(var ii in aBody) {
        if (ii == 2 || ii == aBody.length -2) {
            if (ii == 2) {
                newBody.push("ow.metrics.__fnMetrics[\"" + aName + "\"].start += 1; var __resMetricsProxyE, __resMetricsProxyR, __resMetricsProxyI = now(); try { __resMetricsProxyR = (function(){");
            } else {
                newBody.push("})(); ow.metrics.__fnMetrics[\"" + aName + "\"].end += 1; ow.metrics.__fnMetrics[\"" + aName + "\"].sum += (now() - __resMetricsProxyI); return __resMetricsProxyR; } catch(__fnMetricsProxyE) { ow.metrics.__fnMetrics[\"" + aName + "\"].err += 1; throw __fnMetricsProxyE; }");
            }
        }
        newBody.push(aBody[ii]);
    }
    eval(aFn + " = " + newBody.join("\n"));
};

/**
 * <odoc>
 * <key>ow.metrics.collectMetrics(aName, aFunction) : Object</key>
 * Executes aFunction while collecting functions metrics under the name aName. Returns whatever the function returns
 * or throws any exception.
 * </odoc>
 */
OpenWrap.metrics.prototype.collectMetrics = function(aName, aFunction) {
    _$(aName, "name").isString().$_();
    _$(aFunction).isFunction().$_();

    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};
    if (isUnDef(ow.metrics.__fnMetrics[aName])) {
        ow.metrics.__fnMetrics[aName] = {
            start: 0,
            err  : 0,
            end  : 0,
            sum  : 0
        };
    }

    var __resMetricsProxyE, __resMetricsProxyR, __resMetricsProxyI = now(), res;
    try {
        ow.metrics.__fnMetrics[aName].start += 1;
        __resMetricsProxyR = aFunction();
        ow.metrics.__fnMetrics[aName].end += 1;
        return __resMetricsProxyR;
    } catch(__resMetricsProxyE) {
        ow.metrics.__fnMetrics[aName].err += 1;
        throw __resMetricsProxyE;
    }
}
<commit_msg>metrics error control<commit_after>// OpenWrap v2
// Author: Nuno Aguiar
// Metrics

OpenWrap.metrics = function() {
	return ow.metrics;
};

OpenWrap.metrics.prototype.__m = {
    mem: () => {
        var res = {
            max: Number(java.lang.Runtime.getRuntime().maxMemory()),
            total: Number(java.lang.Runtime.getRuntime().totalMemory()),
            free: Number(java.lang.Runtime.getRuntime().freeMemory())
        };
        res.used = res.total - res.free;
        return res;
    },
    cpu: () => ({
        load1 : getCPULoad(),
        load2 : getCPULoad(true),
        cores : getNumberOfCores(),
        _cores: __cpucores
    }),
    oaf: () => {
        var res = {
            libs : __loadedLibs,
            nlibs: Object.keys(__loadedLibs).length,
            nscopes: af.getScopeIds().length,
            preCompileLevel: __preCompileLevel,
            version: getVersion(),
            path   : getOpenAFPath(),
            java   : String(java.lang.System.getProperty("java.version")),
            javapath: String(java.lang.System.getProperty("java.home")),
            os     : String(java.lang.System.getProperty("os.name")),
            init   : __oafInit,
            now    : now(),
            logErr : __clogErr.get(),
            logWarn: __clogWarn.get(),
            cpuCores: __cpucores,
            threadPoolFactor: __threadPoolFactor,
            bottlenecks: (isDef(global.__bottleneck) ? Object.keys(global.__bottleneck).map(r => ({
                name    : r,
                running : global.__bottleneck[r].atomic.get(),
                maxWait : global.__bottleneck[r].attw,
                maxExecs: global.__bottleneck[r].ance
            })) : "n/a"),
            cache: (isDef(global.__cache) ? Object.keys(global.__cache).map(r => ({
                name: r,
                chName: global.__cache[r].name,
                ttl : global.__cache[r].ttl,
                maxSize: global.__cache[r].msize,
                size: global.__cache[r].size(),
                hits: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].hits,
                miss: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].miss,
                avgExecTime: ow.ch.__types.cache.__cacheStats[global.__cache[r].name].avg,
            })) : "n/a"),
            rest: (isDef(global.__openaf_rest) ? Object.keys(global.__openaf_rest.urls).map(r => ({
                url: r,
                hits: _$(global.__openaf_rest.urls[r].c).default(0),
                miss: _$(global.__openaf_rest.urls[r].f).default(0)
            })) : "n/a"),
            fns    : ow.metrics.__fnMetrics
        };
        if (isDef(res.fns)) {
            Object.keys(res.fns).map(r => {
                res.fns[r].avg = res.fns[r].sum / (res.fns[r].err + res.fns[r].end);
            });
        }
        return res;
    },
    ojob: () => {
        var res = {};
        if (isDef(ow.oJob)) {
            res = ow.oJob.getLogCh().getAll().map(j => ({
                name : j.name,
                start: j.count,
                //err  : $path(j.log, "[?not_null(error)] | length(@)"),
                //end  : $path(j.log, "[?!not_null(error)] | length(@)"),
                error: j.error,
                sum  : j.totalTime,
                avg  : j.avgTime
            }) );
        }
        return res;
    },
    os: () => ({
        pid: getPid()
    }),
    threads: () => {
        var res = {
            list  : af.fromJavaArray(java.lang.Thread.getAllStackTraces().keySet().toArray()).map(t => ({
                id      : t.getId(),
                name    : String(t.getName()),
                isAlive : t.isAlive(),
                priority: Number(t.getPriority()),
                state   : String(t.getState())
            })),
            active: Number(java.lang.Thread.activeCount()),
            total : Number(java.lang.Thread.getAllStackTraces().size())
        };
        res.states = {};
        res.list.map(r => {
            if (isUnDef(res.states[r.state]))
                res.states[r.state] = 1;
            else
                res.states[r.state] += 1;
        });
        return res;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.add(aName, aFunction)</key>
 * Adds aName metric whose values are a map returned by aFunction.
 * </odoc>
 */
OpenWrap.metrics.prototype.add = function(aName, aFn) {
    if (isUnDef(ow.metrics.__m[aName])) {
        ow.metrics.__m[aName] = aFn;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.getSome(anArrayOfNames) : Map</key>
 * Returns just the metrics in the provided anArrayOfNames.
 * </odoc>
 */
OpenWrap.metrics.prototype.getSome = function(aArray) {
    var r = {}, errors = [];
    aArray.map(f => {
        try {
            r[f] = ow.metrics.__m[f]();
        } catch(e) {
            r[f] = "error";
            logErr(e);
        }
    });
    return r;
};

/**
 * <odoc>
 * <key>ow.metrics.getAll() : Map</key>
 * Returns a map with all registered metrics.
 * </odoc>
 */
OpenWrap.metrics.prototype.getAll = function() {
    return ow.metrics.getSome(Object.keys(ow.metrics.__m));
};

/**
 * <odoc>
 * <key>ow.metrics.startCollecting(aChName, aPeriod, some)</key>
 * Starts collecting metrics on aChName (defaults to '__metrics') every aPeriod ms (defaults to 1000ms) optionally just some (array) metrics.
 * </odoc>
 */
OpenWrap.metrics.prototype.startCollecting = function(aChName, aPeriod, aSome) {
    var createCh = isUnDef(aChName) || $ch().list().indexOf(aChName) < 0;

    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};

    aChName = _$(aChName).isString().default("__metrics");
    aPeriod = _$(aPeriod).isNumber().default(1000);

    if (createCh) $ch(aChName).create(1, "mvs", { file: "metrics.db" });

    if (isUnDef(ow.metrics.__ch)) ow.metrics.__ch = [];
    ow.metrics.__ch.push(aChName);

    if (isUnDef(ow.metrics.__t)) {
        plugin("Threads");
        ow.metrics.__t = new Threads();
        ow.metrics.__t.addScheduleThreadWithFixedDelay(function() {
            var k = { t: now() };
            var v;
            if(isArray(aSome))
               v = merge(k, ow.metrics.getSome(aSome));
            else
	       v = merge(k, ow.metrics.getAll());

            ow.metrics.__ch.map(ch => {
                $ch(ch).set(k, v);
            });
        }, aPeriod);
        ow.metrics.__t.startNoWait();
    }
};

/**
 * <odoc>
 * <key>ow.metrics.stopCollecting(aChName)</key>
 * Stops collecting metrics on aChName (defaults to '__metrics')
 * </odoc>
 */
OpenWrap.metrics.prototype.stopCollecting = function(aChName) {
    aChName = _$(aChName).isString().default("__metrics");
    if (ow.metrics.__ch.indexOf(aChName) < 0) throw "Not collecting into " + aChName;

    ow.metrics.__ch = deleteFromArray(ow.metrics.__ch, ow.metrics.__ch.indexOf(aChName));
    if (isDef(ow.metrics.__t) && ow.metrics.__ch.length <= 0) {
        ow.metrics.__t.stop(true);
        ow.metrics.__t = void 0;
    }
};

/**
 * <odoc>
 * <key>ow.metrics.collectMetrics4Fn(aName, aFn)</key>
 * Adds extra code to an existing aFn to collect functions metrics under the name aName. If the same aName and aFn
 * has been already executed before it will throw an exception "Already collecting for the provided function."
 * </odoc>
 */
OpenWrap.metrics.prototype.collectMetrics4Fn = function(aName, aFn) {
    _$(aName, "name").isString().$_();
    _$(aFn, "fn").isString().$_();

    var aBody = eval(aFn).toString();
    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};
    if (isDef(ow.metrics.__fnMetrics[aName])) throw "Already collecting for the provided function.";

    aBody = aBody.split(/\n/);
    var newBody = [];
    ow.metrics.__fnMetrics[aName] = {
        start: 0,
        err  : 0,
        end  : 0,
        sum  : 0,
        avg  : 0
    };

    for(var ii in aBody) {
        if (ii == 2 || ii == aBody.length -2) {
            if (ii == 2) {
                newBody.push("ow.metrics.__fnMetrics[\"" + aName + "\"].start += 1; var __resMetricsProxyE, __resMetricsProxyR, __resMetricsProxyI = now(); try { __resMetricsProxyR = (function(){");
            } else {
                newBody.push("})(); ow.metrics.__fnMetrics[\"" + aName + "\"].end += 1; ow.metrics.__fnMetrics[\"" + aName + "\"].sum += (now() - __resMetricsProxyI); return __resMetricsProxyR; } catch(__fnMetricsProxyE) { ow.metrics.__fnMetrics[\"" + aName + "\"].err += 1; throw __fnMetricsProxyE; }");
            }
        }
        newBody.push(aBody[ii]);
    }
    eval(aFn + " = " + newBody.join("\n"));
};

/**
 * <odoc>
 * <key>ow.metrics.collectMetrics(aName, aFunction) : Object</key>
 * Executes aFunction while collecting functions metrics under the name aName. Returns whatever the function returns
 * or throws any exception.
 * </odoc>
 */
OpenWrap.metrics.prototype.collectMetrics = function(aName, aFunction) {
    _$(aName, "name").isString().$_();
    _$(aFunction).isFunction().$_();

    if (isUnDef(ow.metrics.__fnMetrics)) ow.metrics.__fnMetrics = {};
    if (isUnDef(ow.metrics.__fnMetrics[aName])) {
        ow.metrics.__fnMetrics[aName] = {
            start: 0,
            err  : 0,
            end  : 0,
            sum  : 0
        };
    }

    var __resMetricsProxyE, __resMetricsProxyR, __resMetricsProxyI = now(), res;
    try {
        ow.metrics.__fnMetrics[aName].start += 1;
        __resMetricsProxyR = aFunction();
        ow.metrics.__fnMetrics[aName].end += 1;
        return __resMetricsProxyR;
    } catch(__resMetricsProxyE) {
        ow.metrics.__fnMetrics[aName].err += 1;
        throw __resMetricsProxyE;
    }
}
<|endoftext|>