<commit_before>
(function(){

    var MAX_LABEL_WIDTH = 160;

    dw.visualization.register('bar-chart', 'raphael-chart', {

        render: function(el) {
            el = $(el);

            this.setRoot(el);

            var me = this, row = 0,
                dataset = me.dataset,
                sortBars = me.get('sort-values', false),
                reverse = me.get('reverse-order'),
                useNegativeColor = me.get('negative-color', false);

            me.axesDef = me.axes();
            if (!me.axesDef) return;

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row', 0);
                row = row > me.axesDef.bars.length ? 0 : row;
            }
            me.__lastRow = row;

            var sliceColumns = _.map(me.axesDef.bars, function(i) { return dataset.column(i); }),
                filter = dw.utils.filter(dw.utils.columnNameColumn(sliceColumns), row),
                filterUI = filter.ui(me);

            if (filterUI) {
                $('#header').append(filterUI);
                filter.change(function(val, i) {
                    me.__lastRow = i;
                    me.update(i);
                });
            }

            var c = me.initCanvas({
                h: Math.max(
                    dw.utils.getMaxChartHeight(el)+5,
                    18 * 1.35 * me.getBarColumn().length + 5
                )
            });

            var
                chart_width = c.w - c.lpad - c.rpad,
                series_gap = 0.05, // pull from theme
                row_gap = 0.01,
                formatValue = me.chart().columnFormatter(me.getBarColumn());

            me.init();
            me.initDimensions();

            $('.tooltip').hide();

            c.lastBarY = 0;

            _.each(me.getBarValues(sortBars, reverse), function(barv, s) {
                var d = me.barDimensions(barv, s, row),
                    lpos = me.labelPosition(barv, s, row),
                    fill = me.getKeyColor(barv.name, barv.value, useNegativeColor),
                    stroke = chroma.color(fill).darken(14).hex();

                // draw bar
                var bar = me.registerElement(c.paper.rect(d.x, d.y, d.width, d.height).attr({
                    'stroke': stroke,
                    'fill': fill
                }).data('strokeCol', stroke), barv.name);
                if (me.theme().barChart.barAttrs) {
                    bar.attr(me.theme().barChart.barAttrs);
                }

                if (lpos.show_val) {
                    me.registerLabel(me.label(lpos.val_x, lpos.top, formatValue(barv.value, true),{
                        // w: 40,
                        align: lpos.val_align,
                        cl: 'value' + lpos.lblClass
                    }), barv.name);
                }

                if (lpos.show_lbl) {
                    me.registerLabel(me.label(lpos.lbl_x , lpos.top, barv.name, {
                        w: Math.min(me.labelWidth(barv.name, 'series')+20, MAX_LABEL_WIDTH),
                        align: lpos.lbl_align,
                        valign: 'middle',
                        cl: 'series' + lpos.lblClass
                    }), barv.name);
                }

                c.lastBarY = Math.max(c.lastBarY, d.y + d.height);
            });

            if (me.__domain[0] < 0) {
                var x = c.lpad + c.zero ;
                // add y-axis
                me.__yaxis = me.path('M' + [x, c.tpad] + 'V' + c.lastBarY, 'axis')
                    .attr(me.theme().yAxis);
            }

            // enable mouse events
            el.mousemove(_.bind(me.onMouseMove, me));
            me.renderingComplete();
        },

        getBarValues: function(sortBars, reverse) {
            var me = this,
                values = [],
                filter = me.__lastRow,
                labels = me.axes(true).labels,
                column = me.getBarColumn(filter),
                fmt = me.chart().columnFormatter(labels);

            column.each(function(val, i) {
                values.push({
                    name: fmt(labels.val(i)),
                    value: val
                });
            });
            if (sortBars) values.sort(function(a,b) { return b.value - a.value; });
            if (reverse) values.reverse();
            return values;
        },

        getBarColumn: function() {
            var me = this,
                filter = me.__lastRow;
            if (_.isUndefined(filter)) throw 'filter must not be undefined';
            return me.axes(true).bars[filter];
        },

        update: function(row) {
            var me = this,
                formatValue = me.chart().columnFormatter(me.getBarColumn());

            // update scales
            me.initDimensions();

            // update bar heights and labels
            _.each(me.getBarValues(me.get('sort-values', false)), function(bar, s) {
                _.each(me.__elements[bar.name], function(rect) {
                    var dim = me.barDimensions(bar, s, row);
                    dim.fill = me.getKeyColor(bar.name, bar.value, me.get('negative-color', false));
                    dim.stroke = chroma.color(dim.fill).darken(14).hex();
                    rect.animate(dim, me.theme().duration, me.theme().easing);
                });

                _.each(me.__labels[bar.name], function(lbl) {
                    var pos = me.labelPosition(bar, s, row), lpos;
                    if (lbl.hasClass('value')) {
                        // update value
                        lbl.text(formatValue(bar.value));
                        lpos = { halign: pos.val_align, left: pos.val_x, top: pos.top };
                    } else if (lbl.hasClass('series')) {
                        // update series label position
                        lpos = { halign: pos.lbl_align, left: pos.lbl_x, top: pos.top };
                    }
                    if (lpos) {
                        lbl.animate({
                            align: lpos.halign,
                            x: lpos.left,
                            y: lpos.top
                        }, me.theme().duration, me.theme().easing);
                    }
                });
            });
            if (me.__domain[0] < 0) {
                var c = me.__canvas,
                    x = c.lpad + c.zero,
                    p = 'M' + [x, c.tpad] + 'V' + c.lastBarY;
                // add y-axis
                if (me.__yaxis) {
                    me.__yaxis.animate({ path: p, opacity: 1 }, me.theme().duration, me.theme().easing);
                } else {
                    me.__yaxis = me.path(p, 'axis').attr(me.theme().yAxis);
                }
            } else if (me.__yaxis) {
                me.__yaxis.animate({ opacity: 0 }, me.theme().duration * 0.5, me.theme().easing);
            }
        },

        initDimensions: function() {
            //
            var me = this, c = me.__canvas,
                w = c.w - c.lpad - c.rpad - 30,
                column = me.getBarColumn(),
                bars = me.getBarValues(),
                formatValue = me.chart().columnFormatter(column),
                domain = me.get('absolute-scale', false) ? dw.utils.minMax(_.map(me.axesDef.bars, function(c) { return me.dataset.column(c); })) : column.range();

            if (domain[0] > 0) domain[0] = 0;
            if (domain[1] < 0) domain[1] = 0;

            me.__domain = domain;
            me.__scales = {
                y: d3.scale.linear().domain(domain)
            };
            /* how maxw works:
             *
             * maxw[0] .. max series name label width      \
             * maxw[1] .. max formatted value label width   } positive
             * largestVal[0] .. max absolute value               /
             * maxw[2] .. max series name label width      \
             * maxw[3] .. max formatted value label width   } negative
             * largestVal[1] .. max absolute value               /
             */
            var maxw = [0, 0, 0, 0], ratio, largestVal = [0, 0], lw;
            _.each(bars, function(bar) {
                if (isNaN(bar.value)) return;
                var neg = bar.value < 0;
                largestVal[neg ? 1 : 0] = Math.max(largestVal[neg ? 1 : 0], Math.abs(bar.value));
            });
            me.__longLabels = false;
            _.each(bars, function(bar) {
                if (isNaN(bar.value)) return;
                var neg = bar.value < 0,
                    t = neg ? 2 : 0,
                    bw;
                bw = Math.abs(bar.value) / (largestVal[0] + largestVal[1]) * w;
                lw = me.labelWidth(bar.name, 'series');
                if (lw > MAX_LABEL_WIDTH) me.__longLabels = true;
                maxw[t] = Math.max(maxw[t], Math.min(lw, MAX_LABEL_WIDTH) + 20);
                maxw[t+1] = Math.max(maxw[t+1], me.labelWidth(me.chart().formatValue(bar.value, true), 'value') + 20 + bw);

            });

            c.left = 0;
            c.right = 0;
            c.zero = largestVal[1] / (largestVal[0] + largestVal[1]) * w;
            if (w > 300) {
                var maxNegBar = c.zero;

                c.left = Math.max(maxw[0], maxw[3]) - c.zero;
                c.right = Math.max(maxw[1], maxw[2]) - (w - c.zero); // Math.max((maxw[2] + maxw[1]) - (w - c.zero), 0);

                w -= c.left + c.right;

                c.zero = c.left + largestVal[1] / (largestVal[0] + largestVal[1]) * w;
            } else {
                c.zero += 15;
            }

            c.maxSeriesLabelWidth = [maxw[0], maxw[2]];
            c.maxValueLabelWidth = [maxw[1], maxw[3]];

            me.__scales.y.rangeRound([c.lpad, w]);
        },

        barDimensions: function(bar, s, r) {
            var me = this, w, h, x, y, i, cw, n = me.getBarValues().length,
                sc = me.__scales, c = me.__canvas, bw, pad = 0.35, vspace = 0.1,
                val = bar.value;

            if (isNaN(val)) val = 0;
            //
            cw = c.h - c.bpad - c.tpad;
            //
            bw = Math.max(18, Math.min(50, cw / (n + (n-1) * pad)));
            w = sc.y(val) - sc.y(0);
            h = bw;
            if (w > 0) {
                x = c.lpad + c.zero;
            } else {
                x = c.lpad + c.zero + w;
                w *= -1;
            }
            if (val !== 0) w = Math.max(1, w);
            y = Math.round(c.tpad + s * (bw + bw * pad));
            return { width: w, height: h, x: x, y: y };
        },

        labelPosition: function(bar, s, r) {
            var me = this,
                d = me.barDimensions(bar, s, r),
                formatValue = me.chart().columnFormatter(me.getBarColumn()),
                c = me.__canvas,
                val = bar.value,
                lbl_left = val >= 0 || isNaN(val),
                lbl_x = lbl_left ? c.zero - 10 : c.zero + 10,
                lbl_align = lbl_left ? 'right' : 'left',
                val_x = lbl_left ?
                    d.x + d.width + 10
                    : d.x - 10,
                val_align = lbl_left ? 'left' : 'right',
                show_lbl = true,
                show_val = true,
                lblClass = me.chart().hasHighlight() && me.chart().isHighlighted(bar) ? ' highlighted' : '';

            if (me.__longLabels && me.__domain[0] >= 0) {
                lbl_align = lbl_left ? 'left' : 'right';
                lbl_x = 0;
            }

            return { lblClass: lblClass, val_align: val_align, show_lbl: show_lbl,
                show_val: show_val, lbl_align: lbl_align, lbl_x: lbl_x, val_x: val_x,
                top: d.y + d.height * 0.5 };
        },

        getDataRowByPoint: function(x, y) {
            return 0;
        },

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        hover: function(hover_key) {
            var me = this;
            _.each(me.getBarValues(), function(bar) {
                _.each(me.__labels[bar.name], function(lbl) {
                    if (hover_key !== undefined && bar.name == hover_key) {
                        lbl.addClass('hover');
                    } else {
                        lbl.removeClass('hover');
                    }
                });
                 _.each(me.__elements[bar.name], function(el) {
                    var fill = me.getKeyColor(bar.name, bar.value, me.get('negative-color', false)), stroke;
                    if (hover_key !== undefined && bar.name == hover_key) fill = chroma.color(fill).darken(14).hex();
                    stroke = chroma.color(fill).darken(14).hex();
                    if (el.attrs.fill != fill || el.attrs.stroke != stroke)
                        el.animate({ fill: fill, stroke: stroke }, 50);
                });
            });
        },

        unhoverSeries: function() {
            this.hoverSeries();
        }

    });

}).call(this);<commit_msg>using left padding for long labels<commit_after>
(function(){

    var MAX_LABEL_WIDTH = 160;

    dw.visualization.register('bar-chart', 'raphael-chart', {

        render: function(el) {
            el = $(el);

            this.setRoot(el);

            var me = this, row = 0,
                dataset = me.dataset,
                sortBars = me.get('sort-values', false),
                reverse = me.get('reverse-order'),
                useNegativeColor = me.get('negative-color', false);

            me.axesDef = me.axes();
            if (!me.axesDef) return;

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row', 0);
                row = row > me.axesDef.bars.length ? 0 : row;
            }
            me.__lastRow = row;

            var sliceColumns = _.map(me.axesDef.bars, function(i) { return dataset.column(i); }),
                filter = dw.utils.filter(dw.utils.columnNameColumn(sliceColumns), row),
                filterUI = filter.ui(me);

            if (filterUI) {
                $('#header').append(filterUI);
                filter.change(function(val, i) {
                    me.__lastRow = i;
                    me.update(i);
                });
            }

            var c = me.initCanvas({
                h: Math.max(
                    dw.utils.getMaxChartHeight(el)+5,
                    18 * 1.35 * me.getBarColumn().length + 5
                )
            });

            var
                chart_width = c.w - c.lpad - c.rpad,
                series_gap = 0.05, // pull from theme
                row_gap = 0.01,
                formatValue = me.chart().columnFormatter(me.getBarColumn());

            me.init();
            me.initDimensions();

            $('.tooltip').hide();

            c.lastBarY = 0;

            _.each(me.getBarValues(sortBars, reverse), function(barv, s) {
                var d = me.barDimensions(barv, s, row),
                    lpos = me.labelPosition(barv, s, row),
                    fill = me.getKeyColor(barv.name, barv.value, useNegativeColor),
                    stroke = chroma.color(fill).darken(14).hex();

                // draw bar
                var bar = me.registerElement(c.paper.rect(d.x, d.y, d.width, d.height).attr({
                    'stroke': stroke,
                    'fill': fill
                }).data('strokeCol', stroke), barv.name);
                if (me.theme().barChart.barAttrs) {
                    bar.attr(me.theme().barChart.barAttrs);
                }

                if (lpos.show_val) {
                    me.registerLabel(me.label(lpos.val_x, lpos.top, formatValue(barv.value, true),{
                        // w: 40,
                        align: lpos.val_align,
                        cl: 'value' + lpos.lblClass
                    }), barv.name);
                }

                if (lpos.show_lbl) {
                    me.registerLabel(me.label(lpos.lbl_x , lpos.top, barv.name, {
                        w: Math.min(me.labelWidth(barv.name, 'series')+20, MAX_LABEL_WIDTH),
                        align: lpos.lbl_align,
                        valign: 'middle',
                        cl: 'series' + lpos.lblClass
                    }), barv.name);
                }

                c.lastBarY = Math.max(c.lastBarY, d.y + d.height);
            });

            if (me.__domain[0] < 0) {
                var x = c.lpad + c.zero ;
                // add y-axis
                me.__yaxis = me.path('M' + [x, c.tpad] + 'V' + c.lastBarY, 'axis')
                    .attr(me.theme().yAxis);
            }

            // enable mouse events
            el.mousemove(_.bind(me.onMouseMove, me));
            me.renderingComplete();
        },

        getBarValues: function(sortBars, reverse) {
            var me = this,
                values = [],
                filter = me.__lastRow,
                labels = me.axes(true).labels,
                column = me.getBarColumn(filter),
                fmt = me.chart().columnFormatter(labels);

            column.each(function(val, i) {
                values.push({
                    name: fmt(labels.val(i)),
                    value: val
                });
            });
            if (sortBars) values.sort(function(a,b) { return b.value - a.value; });
            if (reverse) values.reverse();
            return values;
        },

        getBarColumn: function() {
            var me = this,
                filter = me.__lastRow;
            if (_.isUndefined(filter)) throw 'filter must not be undefined';
            return me.axes(true).bars[filter];
        },

        update: function(row) {
            var me = this,
                formatValue = me.chart().columnFormatter(me.getBarColumn());

            // update scales
            me.initDimensions();

            // update bar heights and labels
            _.each(me.getBarValues(me.get('sort-values', false)), function(bar, s) {
                _.each(me.__elements[bar.name], function(rect) {
                    var dim = me.barDimensions(bar, s, row);
                    dim.fill = me.getKeyColor(bar.name, bar.value, me.get('negative-color', false));
                    dim.stroke = chroma.color(dim.fill).darken(14).hex();
                    rect.animate(dim, me.theme().duration, me.theme().easing);
                });

                _.each(me.__labels[bar.name], function(lbl) {
                    var pos = me.labelPosition(bar, s, row), lpos;
                    if (lbl.hasClass('value')) {
                        // update value
                        lbl.text(formatValue(bar.value));
                        lpos = { halign: pos.val_align, left: pos.val_x, top: pos.top };
                    } else if (lbl.hasClass('series')) {
                        // update series label position
                        lpos = { halign: pos.lbl_align, left: pos.lbl_x, top: pos.top };
                    }
                    if (lpos) {
                        lbl.animate({
                            align: lpos.halign,
                            x: lpos.left,
                            y: lpos.top
                        }, me.theme().duration, me.theme().easing);
                    }
                });
            });
            if (me.__domain[0] < 0) {
                var c = me.__canvas,
                    x = c.lpad + c.zero,
                    p = 'M' + [x, c.tpad] + 'V' + c.lastBarY;
                // add y-axis
                if (me.__yaxis) {
                    me.__yaxis.animate({ path: p, opacity: 1 }, me.theme().duration, me.theme().easing);
                } else {
                    me.__yaxis = me.path(p, 'axis').attr(me.theme().yAxis);
                }
            } else if (me.__yaxis) {
                me.__yaxis.animate({ opacity: 0 }, me.theme().duration * 0.5, me.theme().easing);
            }
        },

        initDimensions: function() {
            //
            var me = this, c = me.__canvas,
                w = c.w - c.lpad - c.rpad - 30,
                column = me.getBarColumn(),
                bars = me.getBarValues(),
                formatValue = me.chart().columnFormatter(column),
                domain = me.get('absolute-scale', false) ? dw.utils.minMax(_.map(me.axesDef.bars, function(c) { return me.dataset.column(c); })) : column.range();

            if (domain[0] > 0) domain[0] = 0;
            if (domain[1] < 0) domain[1] = 0;

            me.__domain = domain;
            me.__scales = {
                y: d3.scale.linear().domain(domain)
            };
            /* how maxw works:
             *
             * maxw[0] .. max series name label width      \
             * maxw[1] .. max formatted value label width   } positive
             * largestVal[0] .. max absolute value               /
             * maxw[2] .. max series name label width      \
             * maxw[3] .. max formatted value label width   } negative
             * largestVal[1] .. max absolute value               /
             */
            var maxw = [0, 0, 0, 0], ratio, largestVal = [0, 0], lw;
            _.each(bars, function(bar) {
                if (isNaN(bar.value)) return;
                var neg = bar.value < 0;
                largestVal[neg ? 1 : 0] = Math.max(largestVal[neg ? 1 : 0], Math.abs(bar.value));
            });
            me.__longLabels = false;
            _.each(bars, function(bar) {
                if (isNaN(bar.value)) return;
                var neg = bar.value < 0,
                    t = neg ? 2 : 0,
                    bw;
                bw = Math.abs(bar.value) / (largestVal[0] + largestVal[1]) * w;
                lw = me.labelWidth(bar.name, 'series');
                if (lw > MAX_LABEL_WIDTH) me.__longLabels = true;
                maxw[t] = Math.max(maxw[t], Math.min(lw, MAX_LABEL_WIDTH) + 20);
                maxw[t+1] = Math.max(maxw[t+1], me.labelWidth(me.chart().formatValue(bar.value, true), 'value') + 20 + bw);

            });

            c.left = 0;
            c.right = 0;
            c.zero = largestVal[1] / (largestVal[0] + largestVal[1]) * w;
            if (w > 300) {
                var maxNegBar = c.zero;

                c.left = Math.max(maxw[0], maxw[3]) - c.zero;
                c.right = Math.max(maxw[1], maxw[2]) - (w - c.zero); // Math.max((maxw[2] + maxw[1]) - (w - c.zero), 0);

                w -= c.left + c.right;

                c.zero = c.left + largestVal[1] / (largestVal[0] + largestVal[1]) * w;
            } else {
                c.zero += 15;
            }

            c.maxSeriesLabelWidth = [maxw[0], maxw[2]];
            c.maxValueLabelWidth = [maxw[1], maxw[3]];

            me.__scales.y.rangeRound([c.lpad, w]);
        },

        barDimensions: function(bar, s, r) {
            var me = this, w, h, x, y, i, cw, n = me.getBarValues().length,
                sc = me.__scales, c = me.__canvas, bw, pad = 0.35, vspace = 0.1,
                val = bar.value;

            if (isNaN(val)) val = 0;
            //
            cw = c.h - c.bpad - c.tpad;
            //
            bw = Math.max(18, Math.min(50, cw / (n + (n-1) * pad)));
            w = sc.y(val) - sc.y(0);
            h = bw;
            if (w > 0) {
                x = c.lpad + c.zero;
            } else {
                x = c.lpad + c.zero + w;
                w *= -1;
            }
            if (val !== 0) w = Math.max(1, w);
            y = Math.round(c.tpad + s * (bw + bw * pad));
            return { width: w, height: h, x: x, y: y };
        },

        labelPosition: function(bar, s, r) {
            var me = this,
                d = me.barDimensions(bar, s, r),
                formatValue = me.chart().columnFormatter(me.getBarColumn()),
                c = me.__canvas,
                val = bar.value,
                lbl_left = val >= 0 || isNaN(val),
                lbl_x = lbl_left ? c.zero - 10 : c.zero + 10,
                lbl_align = lbl_left ? 'right' : 'left',
                val_x = lbl_left ?
                    d.x + d.width + 10
                    : d.x - 10,
                val_align = lbl_left ? 'left' : 'right',
                show_lbl = true,
                show_val = true,
                lblClass = me.chart().hasHighlight() && me.chart().isHighlighted(bar) ? ' highlighted' : '';

            if (me.__longLabels && me.__domain[0] >= 0) {
                lbl_align = lbl_left ? 'left' : 'right';
                lbl_x = c.lpad;
            }

            return { lblClass: lblClass, val_align: val_align, show_lbl: show_lbl,
                show_val: show_val, lbl_align: lbl_align, lbl_x: lbl_x, val_x: val_x,
                top: d.y + d.height * 0.5 };
        },

        getDataRowByPoint: function(x, y) {
            return 0;
        },

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        hover: function(hover_key) {
            var me = this;
            _.each(me.getBarValues(), function(bar) {
                _.each(me.__labels[bar.name], function(lbl) {
                    if (hover_key !== undefined && bar.name == hover_key) {
                        lbl.addClass('hover');
                    } else {
                        lbl.removeClass('hover');
                    }
                });
                 _.each(me.__elements[bar.name], function(el) {
                    var fill = me.getKeyColor(bar.name, bar.value, me.get('negative-color', false)), stroke;
                    if (hover_key !== undefined && bar.name == hover_key) fill = chroma.color(fill).darken(14).hex();
                    stroke = chroma.color(fill).darken(14).hex();
                    if (el.attrs.fill != fill || el.attrs.stroke != stroke)
                        el.animate({ fill: fill, stroke: stroke }, 50);
                });
            });
        },

        unhoverSeries: function() {
            this.hoverSeries();
        }

    });

}).call(this);<|endoftext|>


<commit_before>'use strict';

/**
 * Validation Context which holds all information about a validation context
 * @param {string} uuid context identifier (optional)
 * @constructor
 */
function ValidationContext(uuid) {
    var that = this;
    this.uuid = uuid;
    this.global = undefined;
    this.fieldErrors = {};
    this.knownFields = [];

    /**
     * Registers a field name to be a known field which is visible in the ui
     * @param {string} name name of the field
     */
    this.registerField = function (name) {
        if (!_.contains(that.knownFields, name)) {
            that.knownFields.push(name);
        }
    };
}

function CatValidationService($globalMessages, catValidations, catValidationContexts, catMessagesConfig) {
    var that = this;

    /**
     * Returns the validations context for a specific context identifier.
     * @param {string} contextId context identifier
     * @returns {ValidationContext} validation context
     */
    this.getContext = function (contextId) {
        if (contextId !== undefined) {
            var validations = catValidationContexts[contextId];
            if (validations === undefined) {
                throw new Error('Unknown contextId: ' + contextId);
            }
            return validations;
        } else {
            return catValidations;
        }
    };

    /**
     * Creates a new validation context.
     * @returns {string} context identifier
     */
    this.createContext = function () {
        var uuid = window.cat.util.generateUUID();
        catValidationContexts[uuid] = new ValidationContext(uuid);
        return uuid;
    };

    /**
     * Removes/unregisters the context from the validation service.
     * @param contextId context context identifier
     */
    this.destroyContext = function (contextId) {
        delete catValidationContexts[contextId];
    };

    this.updateFromRejection = function (rejection) {
        var contextId;
        if (!!rejection.config) {
            contextId = rejection.config.catValidationContextId;
        }

        var context = that.getContext(contextId);

        var fieldErrors = context.fieldErrors = {};

        if (!!rejection.data.fieldErrors) {
            // group by field
            _.forEach(rejection.data.fieldErrors, function (fieldError) {
                // Allow config to switch between displaying errors at the field and displaying errors at known fields or globally
                if (catMessagesConfig.knownFieldsActive === true) {
                    // If the error is for a known field, show the error at the field.
                    // If not, display it as a global error.
                    if (_.contains(context.knownFields, fieldError.field)) {
                        fieldErrors[fieldError.field] = fieldErrors[fieldError.field] || [];
                        fieldErrors[fieldError.field].push(fieldError.message);
                    } else {
                        rejection.data.globalErrors = rejection.data.globalErrors || [];
                        rejection.data.globalErrors.push(fieldError.message);
                    }
                } else {
                    fieldErrors[fieldError.field] = fieldErrors[fieldError.field] || [];
                    fieldErrors[fieldError.field].push(fieldError.message);
                }
            });
        }

        if (!!rejection.data.globalErrors) {
            context.global = rejection.data.globalErrors;

            // TODO is this also context dependend? or even necessary?
            $globalMessages.addMessages('error', rejection.data.globalErrors, context);
        }
    };

    this.clearValidationErrors = function (contextId) {
        var context = that.getContext(contextId);
        delete context.global;
        context.fieldErrors = {};
    };

    this.hasGlobalErrors = function (contextId) {
        var globalErrors = that.getContext(contextId).global;
        return !!globalErrors && globalErrors.length > 0;
    };

    this.getGlobalErrors = function (contextId) {
        return that.getContext(contextId).global;
    };

    this.hasFieldErrors = function (fieldName, contextId) {
        var fieldErrors = that.getContext(contextId).fieldErrors[fieldName];
        return !!fieldErrors && fieldErrors.length > 0;
    };

    this.hasAnyFieldErrors = function (contextId) {
        var fieldErrors = that.getContext(contextId).fieldErrors;
        return !_.$isEmpty(fieldErrors);
    };

    this.getFieldErrors = function (fieldName, contextId) {
        return that.getContext(contextId).fieldErrors[fieldName];
    };

    this.prepareConfig = function (contextId, config) {
        return _.assign(config || {}, {
            catValidationContextId: contextId
        });
    };
}

/**
 * @ngdoc overview
 * @name cat.service.validation
 *
 * @descripton
 * module wrapping the validation logic
 */
angular.module('cat.service.validation', [
        'cat.service.message'
    ])
    /**
     * @ngdoc object
     * @name cat.service.validation:catValidations
     *
     * @description
     * value holding 'global' and 'field' errors
     */
    .value('catValidations', new ValidationContext())

    /**
     * @ngdoc object
     * @name cat.service.validation:catValidationContexts
     *
     * @description
     * value holding 'global' and 'field' errors
     */
    .value('catValidationContexts', {})

    /**
     * @ngdoc service
     * @name cat.service.validation:catValidationService
     *
     * @description
     * Service which maps the 'fieldErrors' list recieved from the backend to a usable map for the client. All methods
     * have a 'context' parameter as the last parameter. If no context is provided the global context will be used,
     * otherwise the field error messages will be assigned to the specified context.
     */
    .service('catValidationService', ['$globalMessages', 'catValidations', 'catValidationContexts', 'catMessagesConfig', CatValidationService]);<commit_msg>fix isEmpty call<commit_after>'use strict';

/**
 * Validation Context which holds all information about a validation context
 * @param {string} uuid context identifier (optional)
 * @constructor
 */
function ValidationContext(uuid) {
    var that = this;
    this.uuid = uuid;
    this.global = undefined;
    this.fieldErrors = {};
    this.knownFields = [];

    /**
     * Registers a field name to be a known field which is visible in the ui
     * @param {string} name name of the field
     */
    this.registerField = function (name) {
        if (!_.contains(that.knownFields, name)) {
            that.knownFields.push(name);
        }
    };
}

function CatValidationService($globalMessages, catValidations, catValidationContexts, catMessagesConfig) {
    var that = this;

    /**
     * Returns the validations context for a specific context identifier.
     * @param {string} contextId context identifier
     * @returns {ValidationContext} validation context
     */
    this.getContext = function (contextId) {
        if (contextId !== undefined) {
            var validations = catValidationContexts[contextId];
            if (validations === undefined) {
                throw new Error('Unknown contextId: ' + contextId);
            }
            return validations;
        } else {
            return catValidations;
        }
    };

    /**
     * Creates a new validation context.
     * @returns {string} context identifier
     */
    this.createContext = function () {
        var uuid = window.cat.util.generateUUID();
        catValidationContexts[uuid] = new ValidationContext(uuid);
        return uuid;
    };

    /**
     * Removes/unregisters the context from the validation service.
     * @param contextId context context identifier
     */
    this.destroyContext = function (contextId) {
        delete catValidationContexts[contextId];
    };

    this.updateFromRejection = function (rejection) {
        var contextId;
        if (!!rejection.config) {
            contextId = rejection.config.catValidationContextId;
        }

        var context = that.getContext(contextId);

        var fieldErrors = context.fieldErrors = {};

        if (!!rejection.data.fieldErrors) {
            // group by field
            _.forEach(rejection.data.fieldErrors, function (fieldError) {
                // Allow config to switch between displaying errors at the field and displaying errors at known fields or globally
                if (catMessagesConfig.knownFieldsActive === true) {
                    // If the error is for a known field, show the error at the field.
                    // If not, display it as a global error.
                    if (_.contains(context.knownFields, fieldError.field)) {
                        fieldErrors[fieldError.field] = fieldErrors[fieldError.field] || [];
                        fieldErrors[fieldError.field].push(fieldError.message);
                    } else {
                        rejection.data.globalErrors = rejection.data.globalErrors || [];
                        rejection.data.globalErrors.push(fieldError.message);
                    }
                } else {
                    fieldErrors[fieldError.field] = fieldErrors[fieldError.field] || [];
                    fieldErrors[fieldError.field].push(fieldError.message);
                }
            });
        }

        if (!!rejection.data.globalErrors) {
            context.global = rejection.data.globalErrors;

            // TODO is this also context dependend? or even necessary?
            $globalMessages.addMessages('error', rejection.data.globalErrors, context);
        }
    };

    this.clearValidationErrors = function (contextId) {
        var context = that.getContext(contextId);
        delete context.global;
        context.fieldErrors = {};
    };

    this.hasGlobalErrors = function (contextId) {
        var globalErrors = that.getContext(contextId).global;
        return !!globalErrors && globalErrors.length > 0;
    };

    this.getGlobalErrors = function (contextId) {
        return that.getContext(contextId).global;
    };

    this.hasFieldErrors = function (fieldName, contextId) {
        var fieldErrors = that.getContext(contextId).fieldErrors[fieldName];
        return !!fieldErrors && fieldErrors.length > 0;
    };

    this.hasAnyFieldErrors = function (contextId) {
        var fieldErrors = that.getContext(contextId).fieldErrors;
        return !_.isEmpty(fieldErrors);
    };

    this.getFieldErrors = function (fieldName, contextId) {
        return that.getContext(contextId).fieldErrors[fieldName];
    };

    this.prepareConfig = function (contextId, config) {
        return _.assign(config || {}, {
            catValidationContextId: contextId
        });
    };
}

/**
 * @ngdoc overview
 * @name cat.service.validation
 *
 * @descripton
 * module wrapping the validation logic
 */
angular.module('cat.service.validation', [
        'cat.service.message'
    ])
    /**
     * @ngdoc object
     * @name cat.service.validation:catValidations
     *
     * @description
     * value holding 'global' and 'field' errors
     */
    .value('catValidations', new ValidationContext())

    /**
     * @ngdoc object
     * @name cat.service.validation:catValidationContexts
     *
     * @description
     * value holding 'global' and 'field' errors
     */
    .value('catValidationContexts', {})

    /**
     * @ngdoc service
     * @name cat.service.validation:catValidationService
     *
     * @description
     * Service which maps the 'fieldErrors' list recieved from the backend to a usable map for the client. All methods
     * have a 'context' parameter as the last parameter. If no context is provided the global context will be used,
     * otherwise the field error messages will be assigned to the specified context.
     */
    .service('catValidationService', ['$globalMessages', 'catValidations', 'catValidationContexts', 'catMessagesConfig', CatValidationService]);<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var RelayHandler = require('../relay_handler');

var REGISTER_GRACE_PERIOD = 1000;
var REGISTER_TTL = 1000;

function ServiceDispatchHandler(options) {
    if (!(this instanceof ServiceDispatchHandler)) {
        return new ServiceDispatchHandler(options);
    }
    var self = this;

    self.options = options;
    assert(options, 'service dispatch handler options not actually optional');
    self.channel = self.options.channel;
    self.config = self.options.config;
    self.logger = self.options.logger;
    self.statsd = self.options.statsd;
    self.egressNodes = self.options.egressNodes;

    self.egressNodes.on('membershipChanged', onMembershipChanged);

    self.registerTTL = numberOrDefault(self.config,
        'core.exitNode.registerTTL', REGISTER_TTL);
    self.registrationGracePeriod = numberOrDefault(self.config,
        'core.exitNode.registrationGracePeriod', REGISTER_GRACE_PERIOD);

    function onMembershipChanged() {
        self.updateServiceChannels();
    }
}

ServiceDispatchHandler.prototype.type = 'tchannel.hyperbahn.service-dispatch-handler';

ServiceDispatchHandler.prototype.handleRequest =
function handleRequest(req, buildRes) {
    /* eslint max-statements:[2,20] */
    var self = this;
    if (!req.serviceName) {
        self.logger.error('Got incoming req with no service', {
            serviceName: req.serviceName,
            arg1: String(req.arg1)
        });

        buildRes().sendError('BadRequest', 'no service name given');
        return;
    }

    if (!req.streamed) {
        var name = String(req.arg1);
        self.onEndpointHandled(req.serviceName, name);
    } else {
        var statsdKey = 'server.request-stream.' + req.serviceName;
        self.statsd.increment(statsdKey);
    }

    var chan = self.channel.subChannels[req.serviceName];
    if (chan) {
        // Temporary hack. Need to set json by default because
        // we want to upgrade without breaking ncar
        chan.handler.handleRequest(req, buildRes);
    } else {
        self.handleDefault(req, buildRes);
    }
};

ServiceDispatchHandler.prototype.onEndpointHandled =
function onEndpointHandled(service, name) {
    var self = this;

    var logRequest = self.config.get('server.logRequest');

    var endpointName = name
        .replace(/\//g, '_')
        .replace(/:/g, '_');

    var statsdKey = 'server.request.' + service +
        '.' + endpointName;

    self.statsd.increment(statsdKey);

    if (logRequest && logRequest[name] === false) {
        return;
    }
};

ServiceDispatchHandler.prototype.handleDefault =
function handleDefault(req, buildRes) {
    var self = this;
    var svcchan = self.getOrCreateServiceChannel(req.serviceName);
    svcchan.handler.handleRequest(req, buildRes);
};

ServiceDispatchHandler.prototype.getOrCreateServiceChannel =
function getOrCreateServiceChannel(serviceName) {
    var self = this;
    return self.getServiceChannel(serviceName, true);
};

ServiceDispatchHandler.prototype.getServiceChannel =
function getServiceChannel(serviceName, create) {
    var self = this;
    var svcchan = self.channel.subChannels[serviceName];
    if (!svcchan && create) {
        self.logger.info('Creating new sub channel', {
            serviceName: serviceName
        });

        svcchan = self.createServiceChannel(serviceName);
    }
    return svcchan;
};

ServiceDispatchHandler.prototype.getServicePeer =
function getServicePeer(serviceName, hostPort) {
    var self = this;
    var svcchan = self.getOrCreateServiceChannel(serviceName);
    return self._getServicePeer(svcchan, hostPort);
};

ServiceDispatchHandler.prototype._getServicePeer =
function _getServicePeer(svcchan, hostPort) {
    var peer = svcchan.peers.get(hostPort);
    if (!peer) {
        peer = svcchan.peers.add(hostPort);
    }
    if (!peer.serviceProxyServices) {
        peer.serviceProxyServices = {};
    }
    peer.serviceProxyServices[svcchan.serviceName] = true;
    return peer;
};

ServiceDispatchHandler.prototype.createServiceChannel =
function createServiceChannel(serviceName) {
    var self = this;

    var exitNodes = self.egressNodes.exitsFor(serviceName);
    var isExit = self.egressNodes.isExitFor(serviceName);
    var mode = isExit ? 'exit' : 'forward';
    var svcchan = self.channel.makeSubChannel({
        serviceName: serviceName
    });
    svcchan.serviceProxyMode = mode; // duck: punched

    if (mode === 'forward') {
        var exitNames = Object.keys(exitNodes);
        for (var i = 0; i < exitNames.length; i++) {
            self._getServicePeer(svcchan, exitNames[i]);
        }
    }

    svcchan.handler = new RelayHandler(svcchan);

    return svcchan;
};

ServiceDispatchHandler.prototype.updateServiceChannels =
function updateServiceChannels() {
    var self = this;
    var serviceNames = Object.keys(self.channel.subChannels);
    for (var i = 0; i < serviceNames.length; i++) {
        var serviceName = serviceNames[i];
        var chan = self.channel.subChannels[serviceName];
        if (chan.serviceProxyMode) {
            self.updateServiceChannel(chan);
        }
    }
};

ServiceDispatchHandler.prototype.updateServiceChannel =
function updateServiceChannel(svcchan) {
    var self = this;
    var exitNodes = self.egressNodes.exitsFor(svcchan.serviceName);
    var isExit = self.egressNodes.isExitFor(svcchan.serviceName);
    if (isExit && svcchan.serviceProxyMode === 'forward') {
        self.changeToExit(exitNodes, svcchan);
    } else if (!isExit) {
        if (svcchan.serviceProxyMode === 'exit') {
            self.changeToForward(exitNodes, svcchan);
        } else {
            self.updateExitNodes(exitNodes, svcchan);
        }
    }
};

ServiceDispatchHandler.prototype.changeToExit =
function changeToExit(exitNodes, svcchan) {
    var self = this;

    var oldMode = svcchan.serviceProxyMode;
    svcchan.serviceProxyMode = 'exit';
    svcchan.peers.clear();
    self.emit('roleTransition', svcchan, {
        oldMode: oldMode,
        newMode: 'exit'
    });

    self.logger.info('Changing to exit node', {
        oldMode: oldMode,
        newMode: 'exit',
        serviceName: svcchan.serviceName
    });
};

ServiceDispatchHandler.prototype.changeToForward =
function changeToForward(exitNodes, svcchan) {
    var self = this;
    var oldMode = svcchan.serviceProxyMode;
    svcchan.serviceProxyMode = 'forward';

    // TODO make sure we close all connections.
    svcchan.peers.clear();
    // TODO: transmit prior known registration data to new owner(s) to
    // speed convergence / deal with transitions better:
    //     var oldPeers = svcchan.peers.clear();
    //     ... send rpc to new exit nodes
    var exitNames = Object.keys(exitNodes);
    for (var i = 0; i < exitNames.length; i++) {
        self._getServicePeer(svcchan, exitNames[i]);
    }
    self.emit('roleTransition', svcchan, {
        oldMode: oldMode,
        newMode: 'forward'
    });

    self.logger.info('Changing to forward node', {
        oldMode: oldMode,
        newMode: 'forward',
        serviceName: svcchan.serviceName
    });
};

ServiceDispatchHandler.prototype.updateExitNodes =
function updateExitNodes(exitNodes, svcchan) {
    var self = this;
    var i;
    var oldNames = svcchan.peers.keys();
    for (i = 0; i < oldNames.length; i++) {
        if (!exitNodes[oldNames[i]]) {
            svcchan.peers.delete(oldNames[i]);
        }
    }
    var exitNames = Object.keys(exitNodes);
    for (i = 0; i < exitNames.length; i++) {
        self._getServicePeer(svcchan, exitNames[i]);
    }
};

// TODO Consider sharding by hostPort and indexing exit exitNodes by hostPort.
// We also have to shard by serviceName and store the serviceName <-> hostPort
// information under the "service exitNodes".  This means that sharding by
// hostPort gives an even spread of socket distribution. i.e. if we shard
// dispatch to 5 exit exitNodes and some small lulzy service to 5 exit
// exitNodes we wont have massive imbalance of dispatch having 500 workers and
// the small service having 2 workers.  We would need two hops to find an exit
// node though

function numberOrDefault(config, key, defaultValue) {
    var value = config.get(key);
    if (typeof value === 'number') {
        return value;
    }
    return defaultValue;
}

module.exports = ServiceDispatchHandler;
<commit_msg>hyperbahn: add a grace period for logging<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var RelayHandler = require('../relay_handler');

var REGISTER_GRACE_PERIOD = 1000;
var REGISTER_TTL = 1000;
var DEFAULT_LOG_GRACE_PERIOD = 5 * 60 * 1000;

function ServiceDispatchHandler(options) {
    if (!(this instanceof ServiceDispatchHandler)) {
        return new ServiceDispatchHandler(options);
    }
    var self = this;

    self.options = options;
    assert(options, 'service dispatch handler options not actually optional');
    self.channel = self.options.channel;
    self.config = self.options.config;
    self.logger = self.options.logger;
    self.statsd = self.options.statsd;
    self.egressNodes = self.options.egressNodes;
    self.createdAt = self.channel.timers.now();
    self.logGracePeriod = self.options.logGracePeriod ||
        DEFAULT_LOG_GRACE_PERIOD;

    self.egressNodes.on('membershipChanged', onMembershipChanged);

    self.registerTTL = numberOrDefault(self.config,
        'core.exitNode.registerTTL', REGISTER_TTL);
    self.registrationGracePeriod = numberOrDefault(self.config,
        'core.exitNode.registrationGracePeriod', REGISTER_GRACE_PERIOD);

    function onMembershipChanged() {
        self.updateServiceChannels();
    }
}

ServiceDispatchHandler.prototype.type = 'tchannel.hyperbahn.service-dispatch-handler';

ServiceDispatchHandler.prototype.handleRequest =
function handleRequest(req, buildRes) {
    /* eslint max-statements:[2,20] */
    var self = this;
    if (!req.serviceName) {
        self.logger.error('Got incoming req with no service', {
            serviceName: req.serviceName,
            arg1: String(req.arg1)
        });

        buildRes().sendError('BadRequest', 'no service name given');
        return;
    }

    if (!req.streamed) {
        var name = String(req.arg1);
        self.onEndpointHandled(req.serviceName, name);
    } else {
        var statsdKey = 'server.request-stream.' + req.serviceName;
        self.statsd.increment(statsdKey);
    }

    var chan = self.channel.subChannels[req.serviceName];
    if (chan) {
        // Temporary hack. Need to set json by default because
        // we want to upgrade without breaking ncar
        chan.handler.handleRequest(req, buildRes);
    } else {
        self.handleDefault(req, buildRes);
    }
};

ServiceDispatchHandler.prototype.onEndpointHandled =
function onEndpointHandled(service, name) {
    var self = this;

    var logRequest = self.config.get('server.logRequest');

    var endpointName = name
        .replace(/\//g, '_')
        .replace(/:/g, '_');

    var statsdKey = 'server.request.' + service +
        '.' + endpointName;

    self.statsd.increment(statsdKey);

    if (logRequest && logRequest[name] === false) {
        return;
    }
};

ServiceDispatchHandler.prototype.handleDefault =
function handleDefault(req, buildRes) {
    var self = this;
    var svcchan = self.getOrCreateServiceChannel(req.serviceName);
    svcchan.handler.handleRequest(req, buildRes);
};

ServiceDispatchHandler.prototype.getOrCreateServiceChannel =
function getOrCreateServiceChannel(serviceName) {
    var self = this;
    return self.getServiceChannel(serviceName, true);
};

ServiceDispatchHandler.prototype.getServiceChannel =
function getServiceChannel(serviceName, create) {
    var self = this;
    var svcchan = self.channel.subChannels[serviceName];
    if (!svcchan && create) {
        var now = self.channel.timers.now();
        if (now >= self.createdAt + self.logGracePeriod) {
            self.logger.info('Creating new sub channel', {
                serviceName: serviceName
            });
        }

        svcchan = self.createServiceChannel(serviceName);
    }
    return svcchan;
};

ServiceDispatchHandler.prototype.getServicePeer =
function getServicePeer(serviceName, hostPort) {
    var self = this;
    var svcchan = self.getOrCreateServiceChannel(serviceName);
    return self._getServicePeer(svcchan, hostPort);
};

ServiceDispatchHandler.prototype._getServicePeer =
function _getServicePeer(svcchan, hostPort) {
    var peer = svcchan.peers.get(hostPort);
    if (!peer) {
        peer = svcchan.peers.add(hostPort);
    }
    if (!peer.serviceProxyServices) {
        peer.serviceProxyServices = {};
    }
    peer.serviceProxyServices[svcchan.serviceName] = true;
    return peer;
};

ServiceDispatchHandler.prototype.createServiceChannel =
function createServiceChannel(serviceName) {
    var self = this;

    var exitNodes = self.egressNodes.exitsFor(serviceName);
    var isExit = self.egressNodes.isExitFor(serviceName);
    var mode = isExit ? 'exit' : 'forward';
    var svcchan = self.channel.makeSubChannel({
        serviceName: serviceName
    });
    svcchan.serviceProxyMode = mode; // duck: punched

    if (mode === 'forward') {
        var exitNames = Object.keys(exitNodes);
        for (var i = 0; i < exitNames.length; i++) {
            self._getServicePeer(svcchan, exitNames[i]);
        }
    }

    svcchan.handler = new RelayHandler(svcchan);

    return svcchan;
};

ServiceDispatchHandler.prototype.updateServiceChannels =
function updateServiceChannels() {
    var self = this;
    var serviceNames = Object.keys(self.channel.subChannels);
    for (var i = 0; i < serviceNames.length; i++) {
        var serviceName = serviceNames[i];
        var chan = self.channel.subChannels[serviceName];
        if (chan.serviceProxyMode) {
            self.updateServiceChannel(chan);
        }
    }
};

ServiceDispatchHandler.prototype.updateServiceChannel =
function updateServiceChannel(svcchan) {
    var self = this;
    var exitNodes = self.egressNodes.exitsFor(svcchan.serviceName);
    var isExit = self.egressNodes.isExitFor(svcchan.serviceName);
    if (isExit && svcchan.serviceProxyMode === 'forward') {
        self.changeToExit(exitNodes, svcchan);
    } else if (!isExit) {
        if (svcchan.serviceProxyMode === 'exit') {
            self.changeToForward(exitNodes, svcchan);
        } else {
            self.updateExitNodes(exitNodes, svcchan);
        }
    }
};

ServiceDispatchHandler.prototype.changeToExit =
function changeToExit(exitNodes, svcchan) {
    var self = this;

    var oldMode = svcchan.serviceProxyMode;
    svcchan.serviceProxyMode = 'exit';
    svcchan.peers.clear();
    self.emit('roleTransition', svcchan, {
        oldMode: oldMode,
        newMode: 'exit'
    });

    self.logger.info('Changing to exit node', {
        oldMode: oldMode,
        newMode: 'exit',
        serviceName: svcchan.serviceName
    });
};

ServiceDispatchHandler.prototype.changeToForward =
function changeToForward(exitNodes, svcchan) {
    var self = this;
    var oldMode = svcchan.serviceProxyMode;
    svcchan.serviceProxyMode = 'forward';

    // TODO make sure we close all connections.
    svcchan.peers.clear();
    // TODO: transmit prior known registration data to new owner(s) to
    // speed convergence / deal with transitions better:
    //     var oldPeers = svcchan.peers.clear();
    //     ... send rpc to new exit nodes
    var exitNames = Object.keys(exitNodes);
    for (var i = 0; i < exitNames.length; i++) {
        self._getServicePeer(svcchan, exitNames[i]);
    }
    self.emit('roleTransition', svcchan, {
        oldMode: oldMode,
        newMode: 'forward'
    });

    self.logger.info('Changing to forward node', {
        oldMode: oldMode,
        newMode: 'forward',
        serviceName: svcchan.serviceName
    });
};

ServiceDispatchHandler.prototype.updateExitNodes =
function updateExitNodes(exitNodes, svcchan) {
    var self = this;
    var i;
    var oldNames = svcchan.peers.keys();
    for (i = 0; i < oldNames.length; i++) {
        if (!exitNodes[oldNames[i]]) {
            svcchan.peers.delete(oldNames[i]);
        }
    }
    var exitNames = Object.keys(exitNodes);
    for (i = 0; i < exitNames.length; i++) {
        self._getServicePeer(svcchan, exitNames[i]);
    }
};

// TODO Consider sharding by hostPort and indexing exit exitNodes by hostPort.
// We also have to shard by serviceName and store the serviceName <-> hostPort
// information under the "service exitNodes".  This means that sharding by
// hostPort gives an even spread of socket distribution. i.e. if we shard
// dispatch to 5 exit exitNodes and some small lulzy service to 5 exit
// exitNodes we wont have massive imbalance of dispatch having 500 workers and
// the small service having 2 workers.  We would need two hops to find an exit
// node though

function numberOrDefault(config, key, defaultValue) {
    var value = config.get(key);
    if (typeof value === 'number') {
        return value;
    }
    return defaultValue;
}

module.exports = ServiceDispatchHandler;
<|endoftext|>


<commit_before>/*
	jQuery Colorbox language configuration
	language: Hebrew (he)
	translated by: DavidCo
	site: DavidCo.me
*/
jQuery.extend(jQuery.colorbox.settings, {
	current: "תמונה {current} מתוך {total}",
	previous: "הקודם",
	next: "הבא",
	close: "סגור",
	xhrError: "שגיאה בטעינת התוכן.",
	imgError: "שגיאה בטעינת התמונה.",
	slideshowStart: "התחל מצגת",
	slideshowStop: "עצור מצגת"
});
<commit_msg>Update my homepage<commit_after>/*
	jQuery Colorbox language configuration
	language: Hebrew (he)
	translated by: David Cohen
	site: dav.co.il
*/
jQuery.extend(jQuery.colorbox.settings, {
	current: "תמונה {current} מתוך {total}",
	previous: "הקודם",
	next: "הבא",
	close: "סגור",
	xhrError: "שגיאה בטעינת התוכן.",
	imgError: "שגיאה בטעינת התמונה.",
	slideshowStart: "התחל מצגת",
	slideshowStop: "עצור מצגת"
});
<|endoftext|>


<commit_before>'use strict';

angular.module('app').directive('animateOnChange', function ($animate) {
    return {
        restrict: 'A',
        link: function (scope, elem, attr) {
            scope.$watch(attr.animateOnChange, function (newValue, oldValue) {
                if (newValue != oldValue) {
                    var c = newValue > oldValue ? 'change-up' : 'change';
                    $animate.addClass(elem, c, function () {
                        $animate.removeClass(elem, c);
                    });
                }
            });
        }
    }
});<commit_msg>Delete useless directive<commit_after><|endoftext|>


<commit_before>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2014@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

import {ConcolicValue} from './Values/WrappedValue';
import {SymbolicObject} from './Values/SymbolicObject';
import ObjectHelper from './Utilities/ObjectHelper';
import SymbolicState from './SymbolicState';
import SymbolicHelper from './SymbolicHelper';
import Log from './Utilities/Log';
import NotAnErrorException from './NotAnErrorException';
import {isNative} from './Utilities/IsNative';
import ModelBuilder from './FunctionModels';
import External from './External';

//Electron can't resolve external library's directly. The External packages makes that transparent
const Tropigate = External('Tropigate');

class SymbolicExecution {

    constructor(sandbox, initialInput, exitFn) {
        this._sandbox = sandbox;
        this.state = new SymbolicState(initialInput, this._sandbox);
        this.models = ModelBuilder(this.state);
        this._fileList = new Array();

        //Bind any uncaught exceptions to the uncaught exception handler
        process.on('uncaughtException', this._uncaughtException.bind(this));

        //Bind the exit handler to the exit callback supplied
        process.on('exit', exitFn.bind(null, this.state, this.state.coverage));
    }

    _uncaughtException(e) {

        //Ignore NotAnErrorException
        if (e instanceof NotAnErrorException) {
            return;
        }

        Log.log('Uncaught exception ' + e + (e.stack ? ('(stack ' + e.stack + ')') : ''));

        this.state.errors.push({
            error: '' + e,
            stack: e.stack
        });
    }

    invokeFunPre(iid, f, base, args, isConstructor, isMethod) {
        this.state.coverage.touch(iid);
        Log.logHigh('Execute function ' + ObjectHelper.asString(f) + ' at ' + this._location(iid));

        f = this.state.getConcrete(f);

        /**
         * Concretize the function if it is native and we do not have a custom model for it
         */
        if (isNative(f) && !this.models[f]) {
            const concretized = this.state.concretizeCall(f, base, args);
            base = concretized.base;
            args = concretized.args;
        }

        /**
         * End of conc
         */
        return {
            f: f,
            base: base,
            args: args,
            skip: isModelled
        };
    }

    /**
     * Called after a function completes execution
     */
    invokeFun(iid, f, base, args, result, isConstructor, isMethod) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Exit function (${ObjectHelper.asString(f)}) near ${this._location(iid)}`);
        return { result: this.models[f] ? this.models[f](f, base, args, result) : result };
    }

    literal(iid, val, hasGetterSetter) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    forinObject(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _location(iid) {
        return this._sandbox.iidToLocation(this._sandbox.getGlobalIID(iid));
    }

    endExpression(iid) {
        this.state.coverage.touch(iid);
    }

    declare(iid, name, val, isArgument, argumentIndex, isCatchParam) {
        this.state.coverage.touch(iid);
        Log.logHigh('Declare ' + name + ' at ' + this._location(iid));
        return {
            result: val
        };
    }

    getFieldPre(iid, base, offset, isComputed, isOpAssign, isMethodCall) {
        this.state.coverage.touch(iid);
        return {
            base: base,
            offset: offset,
            skip: this.state.isWrapped(base) || this.state.isWrapped(offset)
        };
    }

    _getFieldSymbolicOffset(base, offset) {
        const base_c = this.state.getConcrete(base);
        const offset_c = this.state.getConcrete(offset);
        for (const idx in base_c) {
            if (offset_c != base_c[idx]) {
                const condition = this.state.binary('==', idx, offset);
                this.state.pushCondition(this.state.ctx.mkNot(condition));
            }
        }
    }

    /**
     * GetField will be skipped if the base or offset is not wrapped (SymbolicObject or isSymbolic)
     */
    getField(iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
        this.state.coverage.touch(iid);
        Log.logHigh('Get field ' + ObjectHelper.asString(base) + '.' + ObjectHelper.asString(offset) + ' at ' + this._location(iid));

        //If dealing with a SymbolicObject then concretize the offset and defer to SymbolicObject.getField
        if (base instanceof SymbolicObject) {
            Log.logMid('Potential loss of precision, cocretize offset on SymbolicObject field lookups');
            return {
                result: base.getField(this.state, this.state.getConcrete(offset))
            }
        }

        //If we are evaluating a symbolic string offset on a concrete base then enumerate all fields
        //Then return the concrete lookup
        if (!this.state.isSymbolic(base) &&
             this.state.isSymbolic(offset) &&
             typeof this.state.getConcrete(offset) == 'string') {
            this._getFieldSymbolicOffset(base, offset);
            return {
                result: base[this.state.getConcrete(offset)]
            }
        }

        //Otherwise defer to symbolicField
        const result_s = this.state.isSymbolic(base) ? this.state.symbolicField(this.state.getConcrete(base), this.state.asSymbolic(base), this.state.getConcrete(offset), this.state.asSymbolic(offset)) : undefined;
        const result_c = this.state.getConcrete(base)[this.state.getConcrete(offset)];

        return {
            result: result_s ? new ConcolicValue(result_c, result_s) : result_c
        };
    }

    putFieldPre(iid, base, offset, val, isComputed, isOpAssign) {
        this.state.coverage.touch(iid);
        Log.logHigh('Put field ' + ObjectHelper.asString(base) + '.' + ObjectHelper.asString(offset) + ' at ' + this._location(iid));

        return {
            base: base,
            offset: offset,
            val: val,
            skip: this.state.isWrapped(base) || this.state.isWrapped(offset)
        };
    }

    putField(iid, base, offset, val, isComputed, isOpAssign) {
        this.state.coverage.touch(iid);
        Log.logHigh(`PutField ${base.toString()} at ${offset}`);

        if (base instanceof SymbolicObject) {
            return {
                result: base.setField(this.state, this.state.getConcrete(offset), val)
            }
        }

        //TODO: Enumerate if symbolic offset and concrete input

        if (this.state.isSymbolic(base) && this.state.getConcrete(base) instanceof Array) {
            Log.log('TODO: Check that setField is homogonous');

            //SetField produce a new array
            //Therefore the symbolic portion of base needs to be updated
            const base_s = this.state.asSymbolic(base).setField(
                this.state.asSymbolic(offset),
                this.state.asSymbolic(val));

            this.state.getConcrete(base)[this.state.getConcrete(offset)] = val;
            this.state.updateSymbolic(base, base_s);

            return {
                result: val
            }
        }

        this.state.getConcrete(base)[this.state.getConcrete(offset)] = val;

        return { result: val };
    }

    read(iid, name, val, isGlobal, isScriptLocal) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Read ${name} at ${this._location(iid)}`);
        return { result: val };
    }

    write(iid, name, val, lhs, isGlobal, isScriptLocal) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Write ${name} at ${this._location(iid)}`);
        return { result: val };
    }

    _return(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _throw(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _with(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    functionEnter(iid, f, dis, args) {
        this.state.coverage.touch(iid);
        Log.logHigh('Entering ' + ObjectHelper.asString(f) + ' ' + this._location(iid));
    }

    functionExit(iid, returnVal, wrappedExceptionVal) {
        this.state.coverage.touch(iid);

        Log.logHigh('Exiting function ' + this._location(iid));

        return {
            returnVal: returnVal,
            wrappedExceptionVal: wrappedExceptionVal,
            isBacktrack: false
        };
    }

    _scriptDepth() {
        return this._fileList.length;
    }

    _addScript(fd) {
        this._fileList.push(fd);
    }

    _removeScript() {
        return this._fileList.pop();
    }

    scriptEnter(iid, instrumentedFileName, originalFileName) {
        this.state.coverage.touch(iid);

        const enterString = "====== ENTERING SCRIPT " + originalFileName + " depth " + this._scriptDepth() + " ======";

        if (this._scriptDepth() == 0) {
            Log.log(enterString);
        } else {
            Log.logMid(enterString);
        }

        this._addScript(originalFileName);
    }

    scriptExit(iid, wrappedExceptionVal) {
        this.state.coverage.touch(iid);
        const originalFileName = this._removeScript();
        const exitString = "====== EXITING SCRIPT " + originalFileName + " depth " + this._scriptDepth() + " ======";

        if (this._scriptDepth() > 0) {
            Log.logMid(exitString);
        } else {
            Log.log(exitString);
        }

        return {
            wrappedExceptionVal: wrappedExceptionVal,
            isBacktrack: false
        };
    }

    binaryPre(iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {

        //Don't do symbolic logic if the symbolic values are diff types
        //Concretise instead
        if (this.state.isWrapped(left) || this.state.isWrapped(right)) {

            const left_c  = this.state.getConcrete(left),
                  right_c = this.state.getConcrete(right);

            //We also consider boxed primatives to be primative
            const is_primative = typeof(left_c) != 'object' || (left_c instanceof Number || left_c instanceof String || left_c instanceof Boolean);
            const is_null = left_c === undefined || right_c === undefined || left_c === null || right_c === null;
            const is_real = typeof(left_c) == "number" ? (Number.isFinite(left_c) && Number.isFinite(right_c)) : true;

            //TODO: Work out how to check that boxed values are the same type
            const is_same_type = typeof(left_c) === typeof(right_c) || (!is_null && left_c.valueOf() == right_c.valueOf());

            if (!is_same_type || !is_primative || is_null || !is_real) {
                Log.log("Concretizing binary " + op + " on operands of differing types. Type coercion not yet implemented symbolically. (" + ObjectHelper.asString(left_c) + ", " + ObjectHelper.asString(right_c) + ') (' + typeof left_c + ', ' + typeof right_c + ')');
                left = left_c;
                right = right_c;
            } else {
                Log.logHigh('Not concretizing ' + op + ' ' + left + ' ' + right + ' ' + typeof left_c + ' ' + typeof right_c);
            }

        }

        // Don't evaluate natively when args are symbolic
        return {
            op: op,
            left: left,
            right: right,
            skip: this.state.isWrapped(left) || this.state.isWrapped(right)
        };
    }

    binary(iid, op, left, right, result_c, isOpAssign, isSwitchCaseComparison, isComputed) {
        this.state.coverage.touch(iid);

        Log.logHigh('Op ' + op + ' left ' + ObjectHelper.asString(left) + ' right ' + ObjectHelper.asString(right) + ' result_c ' + ObjectHelper.asString(result_c) + ' at ' + this._location(iid));

        let result;

        if (this.state.isSymbolic(left) || this.state.isSymbolic(right)) {
            result = this.state.binary(op, left, right);
        } else {
            result = result_c;
        }

        return {
            result: result
        }
    }

    unaryPre(iid, op, left) {
        this.state.coverage.touch(iid);

        // Don't evaluate natively when args are symbolic
        return {
            op: op,
            left: left,
            skip: this.state.isWrapped(left)
        }
    }

    unary(iid, op, left, result_c) {
        this.state.coverage.touch(iid);

        Log.logHigh('Unary ' + op + ' left ' + ObjectHelper.asString(left) + ' result ' + ObjectHelper.asString(result_c));

        return {
            result: this.state.unary(op, left)
        };
    }

    conditional(iid, result) {
        this.state.coverage.touch_cnd(iid, this.state.getConcrete(result));
        Log.logHigh(`Evaluating conditional ${ObjectHelper.asString(result)}`);

        if (this.state.isSymbolic(result)) {
            Log.logMid(`Evaluating symbolic condition ${this.state.asSymbolic(result)} at ${this._location(iid)}`);
            this.state.conditional(this.state.toBool(result));
        }

        return { result: this.state.getConcrete(result) };
    }

    instrumentCodePre(iid, code) {

        try {
            code = Tropigate(code);
        } catch (e) {
            throw `Tropigate failed because ${e} on program ${code} at ${e.stack}`;
        }

        return { code: code, skip: false };
    }

    instrumentCode(iid, code, newAst) {
        return { result: code };
    }

    runInstrumentedFunctionBody(iid) {
        this.state.coverage.touch(iid);
    }

    onReady(cb) {
        cb();
    }
}

export default SymbolicExecution;
<commit_msg>Fix misc isModelledx<commit_after>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2014@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

import {ConcolicValue} from './Values/WrappedValue';
import {SymbolicObject} from './Values/SymbolicObject';
import ObjectHelper from './Utilities/ObjectHelper';
import SymbolicState from './SymbolicState';
import SymbolicHelper from './SymbolicHelper';
import Log from './Utilities/Log';
import NotAnErrorException from './NotAnErrorException';
import {isNative} from './Utilities/IsNative';
import ModelBuilder from './FunctionModels';
import External from './External';

//Electron can't resolve external library's directly. The External packages makes that transparent
const Tropigate = External('Tropigate');

class SymbolicExecution {

    constructor(sandbox, initialInput, exitFn) {
        this._sandbox = sandbox;
        this.state = new SymbolicState(initialInput, this._sandbox);
        this.models = ModelBuilder(this.state);
        this._fileList = new Array();

        //Bind any uncaught exceptions to the uncaught exception handler
        process.on('uncaughtException', this._uncaughtException.bind(this));

        //Bind the exit handler to the exit callback supplied
        process.on('exit', exitFn.bind(null, this.state, this.state.coverage));
    }

    _uncaughtException(e) {

        //Ignore NotAnErrorException
        if (e instanceof NotAnErrorException) {
            return;
        }

        Log.log('Uncaught exception ' + e + (e.stack ? ('(stack ' + e.stack + ')') : ''));

        this.state.errors.push({
            error: '' + e,
            stack: e.stack
        });
    }

    invokeFunPre(iid, f, base, args, isConstructor, isMethod) {
        this.state.coverage.touch(iid);
        Log.logHigh('Execute function ' + ObjectHelper.asString(f) + ' at ' + this._location(iid));

        f = this.state.getConcrete(f);

        let skip = false;

        /**
         * Concretize the function if it is native and we do not have a custom model for it
         */
        if (isNative(f) && !this.models[f]) {
            const concretized = this.state.concretizeCall(f, base, args);
            base = concretized.base;
            args = concretized.args;
            skip = true;
        }

        /**
         * End of conc
         */
        return {
            f: f,
            base: base,
            args: args,
            skip: skip
        };
    }

    /**
     * Called after a function completes execution
     */
    invokeFun(iid, f, base, args, result, isConstructor, isMethod) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Exit function (${ObjectHelper.asString(f)}) near ${this._location(iid)}`);
        return { result: this.models[f] ? this.models[f](f, base, args, result) : result };
    }

    literal(iid, val, hasGetterSetter) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    forinObject(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _location(iid) {
        return this._sandbox.iidToLocation(this._sandbox.getGlobalIID(iid));
    }

    endExpression(iid) {
        this.state.coverage.touch(iid);
    }

    declare(iid, name, val, isArgument, argumentIndex, isCatchParam) {
        this.state.coverage.touch(iid);
        Log.logHigh('Declare ' + name + ' at ' + this._location(iid));
        return {
            result: val
        };
    }

    getFieldPre(iid, base, offset, isComputed, isOpAssign, isMethodCall) {
        this.state.coverage.touch(iid);
        return {
            base: base,
            offset: offset,
            skip: this.state.isWrapped(base) || this.state.isWrapped(offset)
        };
    }

    _getFieldSymbolicOffset(base, offset) {
        const base_c = this.state.getConcrete(base);
        const offset_c = this.state.getConcrete(offset);
        for (const idx in base_c) {
            if (offset_c != base_c[idx]) {
                const condition = this.state.binary('==', idx, offset);
                this.state.pushCondition(this.state.ctx.mkNot(condition));
            }
        }
    }

    /**
     * GetField will be skipped if the base or offset is not wrapped (SymbolicObject or isSymbolic)
     */
    getField(iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
        this.state.coverage.touch(iid);
        Log.logHigh('Get field ' + ObjectHelper.asString(base) + '.' + ObjectHelper.asString(offset) + ' at ' + this._location(iid));

        //If dealing with a SymbolicObject then concretize the offset and defer to SymbolicObject.getField
        if (base instanceof SymbolicObject) {
            Log.logMid('Potential loss of precision, cocretize offset on SymbolicObject field lookups');
            return {
                result: base.getField(this.state, this.state.getConcrete(offset))
            }
        }

        //If we are evaluating a symbolic string offset on a concrete base then enumerate all fields
        //Then return the concrete lookup
        if (!this.state.isSymbolic(base) &&
             this.state.isSymbolic(offset) &&
             typeof this.state.getConcrete(offset) == 'string') {
            this._getFieldSymbolicOffset(base, offset);
            return {
                result: base[this.state.getConcrete(offset)]
            }
        }

        //Otherwise defer to symbolicField
        const result_s = this.state.isSymbolic(base) ? this.state.symbolicField(this.state.getConcrete(base), this.state.asSymbolic(base), this.state.getConcrete(offset), this.state.asSymbolic(offset)) : undefined;
        const result_c = this.state.getConcrete(base)[this.state.getConcrete(offset)];

        return {
            result: result_s ? new ConcolicValue(result_c, result_s) : result_c
        };
    }

    putFieldPre(iid, base, offset, val, isComputed, isOpAssign) {
        this.state.coverage.touch(iid);
        Log.logHigh('Put field ' + ObjectHelper.asString(base) + '.' + ObjectHelper.asString(offset) + ' at ' + this._location(iid));

        return {
            base: base,
            offset: offset,
            val: val,
            skip: this.state.isWrapped(base) || this.state.isWrapped(offset)
        };
    }

    putField(iid, base, offset, val, isComputed, isOpAssign) {
        this.state.coverage.touch(iid);
        Log.logHigh(`PutField ${base.toString()} at ${offset}`);

        if (base instanceof SymbolicObject) {
            return {
                result: base.setField(this.state, this.state.getConcrete(offset), val)
            }
        }

        //TODO: Enumerate if symbolic offset and concrete input

        if (this.state.isSymbolic(base) && this.state.getConcrete(base) instanceof Array) {
            Log.log('TODO: Check that setField is homogonous');

            //SetField produce a new array
            //Therefore the symbolic portion of base needs to be updated
            const base_s = this.state.asSymbolic(base).setField(
                this.state.asSymbolic(offset),
                this.state.asSymbolic(val));

            this.state.getConcrete(base)[this.state.getConcrete(offset)] = val;
            this.state.updateSymbolic(base, base_s);

            return {
                result: val
            }
        }

        this.state.getConcrete(base)[this.state.getConcrete(offset)] = val;

        return { result: val };
    }

    read(iid, name, val, isGlobal, isScriptLocal) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Read ${name} at ${this._location(iid)}`);
        return { result: val };
    }

    write(iid, name, val, lhs, isGlobal, isScriptLocal) {
        this.state.coverage.touch(iid);
        Log.logHigh(`Write ${name} at ${this._location(iid)}`);
        return { result: val };
    }

    _return(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _throw(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    _with(iid, val) {
        this.state.coverage.touch(iid);
        return { result: val };
    }

    functionEnter(iid, f, dis, args) {
        this.state.coverage.touch(iid);
        Log.logHigh('Entering ' + ObjectHelper.asString(f) + ' ' + this._location(iid));
    }

    functionExit(iid, returnVal, wrappedExceptionVal) {
        this.state.coverage.touch(iid);

        Log.logHigh('Exiting function ' + this._location(iid));

        return {
            returnVal: returnVal,
            wrappedExceptionVal: wrappedExceptionVal,
            isBacktrack: false
        };
    }

    _scriptDepth() {
        return this._fileList.length;
    }

    _addScript(fd) {
        this._fileList.push(fd);
    }

    _removeScript() {
        return this._fileList.pop();
    }

    scriptEnter(iid, instrumentedFileName, originalFileName) {
        this.state.coverage.touch(iid);

        const enterString = "====== ENTERING SCRIPT " + originalFileName + " depth " + this._scriptDepth() + " ======";

        if (this._scriptDepth() == 0) {
            Log.log(enterString);
        } else {
            Log.logMid(enterString);
        }

        this._addScript(originalFileName);
    }

    scriptExit(iid, wrappedExceptionVal) {
        this.state.coverage.touch(iid);
        const originalFileName = this._removeScript();
        const exitString = "====== EXITING SCRIPT " + originalFileName + " depth " + this._scriptDepth() + " ======";

        if (this._scriptDepth() > 0) {
            Log.logMid(exitString);
        } else {
            Log.log(exitString);
        }

        return {
            wrappedExceptionVal: wrappedExceptionVal,
            isBacktrack: false
        };
    }

    binaryPre(iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {

        //Don't do symbolic logic if the symbolic values are diff types
        //Concretise instead
        if (this.state.isWrapped(left) || this.state.isWrapped(right)) {

            const left_c  = this.state.getConcrete(left),
                  right_c = this.state.getConcrete(right);

            //We also consider boxed primatives to be primative
            const is_primative = typeof(left_c) != 'object' || (left_c instanceof Number || left_c instanceof String || left_c instanceof Boolean);
            const is_null = left_c === undefined || right_c === undefined || left_c === null || right_c === null;
            const is_real = typeof(left_c) == "number" ? (Number.isFinite(left_c) && Number.isFinite(right_c)) : true;

            //TODO: Work out how to check that boxed values are the same type
            const is_same_type = typeof(left_c) === typeof(right_c) || (!is_null && left_c.valueOf() == right_c.valueOf());

            if (!is_same_type || !is_primative || is_null || !is_real) {
                Log.log("Concretizing binary " + op + " on operands of differing types. Type coercion not yet implemented symbolically. (" + ObjectHelper.asString(left_c) + ", " + ObjectHelper.asString(right_c) + ') (' + typeof left_c + ', ' + typeof right_c + ')');
                left = left_c;
                right = right_c;
            } else {
                Log.logHigh('Not concretizing ' + op + ' ' + left + ' ' + right + ' ' + typeof left_c + ' ' + typeof right_c);
            }

        }

        // Don't evaluate natively when args are symbolic
        return {
            op: op,
            left: left,
            right: right,
            skip: this.state.isWrapped(left) || this.state.isWrapped(right)
        };
    }

    binary(iid, op, left, right, result_c, isOpAssign, isSwitchCaseComparison, isComputed) {
        this.state.coverage.touch(iid);

        Log.logHigh('Op ' + op + ' left ' + ObjectHelper.asString(left) + ' right ' + ObjectHelper.asString(right) + ' result_c ' + ObjectHelper.asString(result_c) + ' at ' + this._location(iid));

        let result;

        if (this.state.isSymbolic(left) || this.state.isSymbolic(right)) {
            result = this.state.binary(op, left, right);
        } else {
            result = result_c;
        }

        return {
            result: result
        }
    }

    unaryPre(iid, op, left) {
        this.state.coverage.touch(iid);

        // Don't evaluate natively when args are symbolic
        return {
            op: op,
            left: left,
            skip: this.state.isWrapped(left)
        }
    }

    unary(iid, op, left, result_c) {
        this.state.coverage.touch(iid);

        Log.logHigh('Unary ' + op + ' left ' + ObjectHelper.asString(left) + ' result ' + ObjectHelper.asString(result_c));

        return {
            result: this.state.unary(op, left)
        };
    }

    conditional(iid, result) {
        this.state.coverage.touch_cnd(iid, this.state.getConcrete(result));
        Log.logHigh(`Evaluating conditional ${ObjectHelper.asString(result)}`);

        if (this.state.isSymbolic(result)) {
            Log.logMid(`Evaluating symbolic condition ${this.state.asSymbolic(result)} at ${this._location(iid)}`);
            this.state.conditional(this.state.toBool(result));
        }

        return { result: this.state.getConcrete(result) };
    }

    instrumentCodePre(iid, code) {

        try {
            code = Tropigate(code);
        } catch (e) {
            throw `Tropigate failed because ${e} on program ${code} at ${e.stack}`;
        }

        return { code: code, skip: false };
    }

    instrumentCode(iid, code, newAst) {
        return { result: code };
    }

    runInstrumentedFunctionBody(iid) {
        this.state.coverage.touch(iid);
    }

    onReady(cb) {
        cb();
    }
}

export default SymbolicExecution;
<|endoftext|>


<commit_before>var React = require('react-native');
var ChallengeShow = require('./ChallengeShow');
var CreateChallenge = require('./CreateChallenge');
var posts = require('../Utils/posts');
var Icon = require('react-native-vector-icons/FontAwesome');

var {
	StyleSheet,
	Navigator,
	TouchableHighlight,
	ListView,
	View,
	Component,
	Text,
  TextInput,
  DeviceEventEmitter,
} = React;

class GroupChallenges extends Component {
  constructor(props) {
    super(props);
    var ds = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      challengeName: '',
      challengeDescription: '',
      btnLocation: 0,
      dataSource: ds.cloneWithRows(this.props.group.challenges)
    }
  }

  goToChallenge(challenge) {
    this.props.navigator.push({
      component: ChallengeShow,
      passProps: {
        challenge: challenge,
        user: this.props.user,
        refreshChallenges: this.getChallenges.bind(this)
      }
    });
  }

  handleSubmit() {
    this.props.navigator.push({
      component: CreateChallenge,
      passProps: { startDate: new Date(), endDate: new Date(), challenges: this.props.group.challenges, user: this.props.user, group: this.props.group, refreshChallenges: this.getChallenges.bind(this)}
    });
  }

  getChallenges() {
    fetch("http://grouvie.herokuapp.com/groups/" + this.props.group.id + "/challenges")
      .then((response) => response.json())
        .then((responseData) => {
          this.setState({
            dataSource: this.state.dataSource.cloneWithRows(responseData),
            loaded: true
        });
      })
      .done();
  }

  addNewChallengeButton() {
    return (
      <View>
        <TouchableHighlight
          style={styles.button}
          onPress={this.handleSubmit.bind(this)}
          underlayColor="#88d4f5">
            <Text style={styles.buttonText}>Create Challenge</Text>
        </TouchableHighlight>
      </View>
    )
  }

  challengeStatusStyling(challenge) {
    var obj = {
      backgroundColor: 'gray'
    };

    for (var i=0;i < challenge.participations.length; i++) {
      if (challenge.participations[i].user_id === this.props.user.id && challenge.participations[i].completed === true) {
          obj.backgroundColor = 'green'
      }
      else if (challenge.participations[i].user_id === this.props.user.id) {
          obj.backgroundColor = '#ffdb4d'
      }
    }
    return obj;
  }

  challengeStatusIcon(challenge) {
    var statusIcon = <Icon name="check" color="gray" style={{fontSize: 30}}/>;

    for (var i=0;i < challenge.participations.length; i++) {
      if (challenge.participations[i].user_id === this.props.user.id && challenge.participations[i].completed === true) {
        return <Icon name="check-circle-o" color="green" style={{fontSize: 60}}/>;
      }
      else if (challenge.participations[i].user_id === this.props.user.id) {
        return <Icon name="circle-o" color="#c3c3c3" style={{fontSize: 60}}/>;
      }
      else {
        statusIcon = '';
      }
    }

  }

  renderRow(challenge) {
    return (
      <View >
          <TouchableHighlight onPress={() => this.goToChallenge(challenge)} underlayColor="#B3B6BF">
            <View style={styles.rowContainer}>
              <View style={styles.leftContainer}>
                <Text style={styles.name}>{challenge.name}</Text>
                <Text style={styles.challengeDescription}>{challenge.description}</Text>
                <Text style={styles.challengeDate}>{new Date(challenge.start_date).toDateString().substr(0,10) + " - " + new Date(challenge.end_date).toDateString().substr(0,10)}</Text>
              </View>
              <Text style={styles.statusIcon}>{this.challengeStatusIcon(challenge)}</Text>
            </View>
          </TouchableHighlight>
      </View>
    );
  }

  render(){
    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={this.renderRow.bind(this)} />
        <View>{this.addNewChallengeButton()}</View>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 50,
    backgroundColor: 'white',
  },
  rowContainer: {
    backgroundColor: 'white',
    borderBottomColor: '#cccccc',
    borderBottomWidth: 1,
    padding: 5,
    backgroundColor: '#fff',
    flex: 1,
    flexDirection: 'row',
  },
  leftContainer: {
    flex: 1,
  },
  statusIcon: {
    textAlign: 'center',
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: 10,
  },
  name: {
    fontSize: 25,
    paddingBottom: 5,
    fontWeight: 'bold',
    textAlign: 'left',
    color: '#444444'
  },
  challengeDescription: {
    color: '#444444',
    fontSize: 18,
    textAlign: 'left',
  },
  challengeDate: {
    color: '#444444',
    fontSize: 12,
    textAlign: 'left',
  },
  button: {
    height: 60,
    backgroundColor: '#4800a8',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 30
  },
  // challengeStatus: {
  //   width: 60,
  //   borderWidth: 1,
  //   borderColor: 'pink',
  // }
});

module.exports = GroupChallenges;
<commit_msg>light code cleanup on GroupChallenge page<commit_after>var React = require('react-native');
var ChallengeShow = require('./ChallengeShow');
var CreateChallenge = require('./CreateChallenge');
var posts = require('../Utils/posts');
var Icon = require('react-native-vector-icons/FontAwesome');

var {
	StyleSheet,
	Navigator,
	TouchableHighlight,
	ListView,
	View,
	Component,
	Text,
  TextInput,
  DeviceEventEmitter,
} = React;

class GroupChallenges extends Component {
  constructor(props) {
    super(props);
    var ds = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      challengeName: '',
      challengeDescription: '',
      btnLocation: 0,
      dataSource: ds.cloneWithRows(this.props.group.challenges)
    }
  }

  goToChallenge(challenge) {
    this.props.navigator.push({
      component: ChallengeShow,
      passProps: {
        challenge: challenge,
        user: this.props.user,
        refreshChallenges: this.getChallenges.bind(this)
      }
    });
  }

  handleSubmit() {
    this.props.navigator.push({
      component: CreateChallenge,
      passProps: { startDate: new Date(), endDate: new Date(), challenges: this.props.group.challenges, user: this.props.user, group: this.props.group, refreshChallenges: this.getChallenges.bind(this)}
    });
  }

  getChallenges() {
    fetch("http://grouvie.herokuapp.com/groups/" + this.props.group.id + "/challenges")
      .then((response) => response.json())
        .then((responseData) => {
          this.setState({
            dataSource: this.state.dataSource.cloneWithRows(responseData),
            loaded: true
        });
      })
      .done();
  }

  addNewChallengeButton() {
    return (
      <View>
        <TouchableHighlight
          style={styles.button}
          onPress={this.handleSubmit.bind(this)}
          underlayColor="#88d4f5">
            <Text style={styles.buttonText}>Create Challenge</Text>
        </TouchableHighlight>
      </View>
    )
  }

  challengeStatusIcon(challenge) {
    var statusIcon = <Icon name="check" color="gray" style={{fontSize: 30}}/>;

    for (var i=0;i < challenge.participations.length; i++) {
      if (challenge.participations[i].user_id === this.props.user.id && challenge.participations[i].completed === true) {
        return <Icon name="check-circle-o" color="green" style={{fontSize: 60}}/>;
      }
      else if (challenge.participations[i].user_id === this.props.user.id) {
        return <Icon name="circle-o" color="#c3c3c3" style={{fontSize: 60}}/>;
      }
      else {
        statusIcon = '';
      }
    }
  }

  renderRow(challenge) {
    return (
      <View >
          <TouchableHighlight onPress={() => this.goToChallenge(challenge)} underlayColor="#B3B6BF">
            <View style={styles.rowContainer}>
              <View style={styles.leftContainer}>
                <Text style={styles.name}>{challenge.name}</Text>
                <Text style={styles.challengeDescription}>{challenge.description}</Text>
                <Text style={styles.challengeDate}>{new Date(challenge.start_date).toDateString().substr(0,10) + " - " + new Date(challenge.end_date).toDateString().substr(0,10)}</Text>
              </View>
              <Text style={styles.statusIcon}>{this.challengeStatusIcon(challenge)}</Text>
            </View>
          </TouchableHighlight>
      </View>
    );
  }

  render(){
    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={this.renderRow.bind(this)} />
        <View>{this.addNewChallengeButton()}</View>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 50,
    backgroundColor: 'white',
  },
  rowContainer: {
    backgroundColor: 'white',
    borderBottomColor: '#cccccc',
    borderBottomWidth: 1,
    padding: 5,
    backgroundColor: '#fff',
    flex: 1,
    flexDirection: 'row',
  },
  leftContainer: {
    flex: 1,
  },
  statusIcon: {
    textAlign: 'center',
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: 10,
  },
  name: {
    fontSize: 25,
    paddingBottom: 5,
    fontWeight: 'bold',
    textAlign: 'left',
    color: '#444444'
  },
  challengeDescription: {
    color: '#444444',
    fontSize: 18,
    textAlign: 'left',
  },
  challengeDate: {
    color: '#444444',
    fontSize: 12,
    textAlign: 'left',
  },
  button: {
    height: 60,
    backgroundColor: '#4800a8',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 30
  },
});

module.exports = GroupChallenges;
<|endoftext|>


<commit_before>odoo.define("website_event.tour", function (require) {
    "use strict";

    var core = require("web.core");
    var tour = require("web_tour.tour");

    var _t = core._t;

    tour.register("event", {
        url: "/",
    }, [tour.STEPS.WEBSITE_NEW_PAGE, {
        trigger: "a[data-action=new_event]",
        content: _t("Click here to create a new event."),
        position: "bottom",
    }, {
        trigger: '.modal-dialog #editor_new_event input[type=text]',
        content: _t("Create a name for your new event and click \"Continue\". e.g: Technical Training"),
        position: "right",
    }, {
        trigger: '.modal-footer button.btn-primary.btn-continue',
        extra_trigger: '#editor_new_event input[type=text][value!=""]',
        content: _t("Click Continue to create the event."),
        position: "right",
    }, {
        trigger: "#snippet_structure .oe_snippet:eq(2) .oe_snippet_thumbnail",
        content: _t("Drag this block and drop it in your page."),
        position: "bottom",
        run: "drag_and_drop",
    }, {
        trigger: "button[data-action=save]",
        content: _t("Once you click on save, your event is updated."),
        position: "bottom",
    }, {
        trigger: ".js_publish_management .js_publish_btn",
        extra_trigger: "body:not(.editor_enable)",
        content: _t("Click to publish your event."),
        position: "top",
    }, {
        trigger: ".css_edit_dynamic",
        extra_trigger: ".js_publish_management .js_publish_btn .css_unpublish:visible",
        content: _t("Click here to customize your event further."),
        position: "bottom",
    }]);
});
<commit_msg>[FIX] website_event: wait drag and drop to be finished<commit_after>odoo.define("website_event.tour", function (require) {
    "use strict";

    var core = require("web.core");
    var tour = require("web_tour.tour");

    var _t = core._t;

    tour.register("event", {
        url: "/",
    }, [tour.STEPS.WEBSITE_NEW_PAGE, {
        trigger: "a[data-action=new_event]",
        content: _t("Click here to create a new event."),
        position: "bottom",
    }, {
        trigger: '.modal-dialog #editor_new_event input[type=text]',
        content: _t("Create a name for your new event and click \"Continue\". e.g: Technical Training"),
        position: "right",
    }, {
        trigger: '.modal-footer button.btn-primary.btn-continue',
        extra_trigger: '#editor_new_event input[type=text][value!=""]',
        content: _t("Click Continue to create the event."),
        position: "right",
    }, {
        trigger: "#snippet_structure .oe_snippet:eq(2) .oe_snippet_thumbnail",
        content: _t("Drag this block and drop it in your page."),
        position: "bottom",
        run: "drag_and_drop",
    }, {
        trigger: "button[data-action=save]",
        content: _t("Once you click on save, your event is updated."),
        position: "bottom",
        extra_trigger: ".o_dirty",
    }, {
        trigger: ".js_publish_management .js_publish_btn",
        extra_trigger: "body:not(.editor_enable)",
        content: _t("Click to publish your event."),
        position: "top",
    }, {
        trigger: ".css_edit_dynamic",
        extra_trigger: ".js_publish_management .js_publish_btn .css_unpublish:visible",
        content: _t("Click here to customize your event further."),
        position: "bottom",
    }]);
});
<|endoftext|>