<commit_before>
(function(){
    // Simple perfect bar chart
    // -------------------------

    var BarChart = Datawrapper.Visualizations.BarChart = function() {

    };

    _.extend(BarChart.prototype, Datawrapper.Visualizations.RaphaelChart.prototype, {

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

            this.setRoot(el);

            var me = this,
            sortBars = me.get('sort-values'),
            reverse = me.get('reverse-order'),
            useNegativeColor = me.get('negative-color', false),
            c = me.initCanvas({
                h: Math.max(me.getMaxChartHeight(el), 18 * 1.35 * me.chart.dataSeries().length)
            }),
            chart_width = c.w - c.lpad - c.rpad,
            series_gap = 0.05, // pull from theme
            row_gap = 0.01,
            row = 0, // pull from theme
            labelsInsideBars = me.get('labels-inside-bars', false);

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row');
            }
            if (row > me.chart.numRows() || row === undefined) row = 0;
            if (me.chart.numRows() > 1) me.chart.filterRow(row);

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

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

            c.lastBarY = 0;

            _.each(me.chart.dataSeries(sortBars, reverse), function(series, s) {
                _.each(series.data, function(val, r) {
                    var d = me.barDimensions(series, s, r);
                    var fill = me.getSeriesColor(series, r, useNegativeColor),
                        stroke = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();

                    if (labelsInsideBars) d.x -= 10;

                    me.registerSeriesElement(c.paper.rect(d.x, d.y, d.w, d.h).attr({
                        'stroke': stroke,
                        'fill': fill
                    }).data('strokeCol', stroke), series);

                    var lbl_x = val >= 0 ?
                            c.zero - 10
                            : c.zero + 10,
                        lbl_align = val >= 0 ? 'right' : 'left',
                        val_x = val >= 0 ?
                            d.x + d.w + 10
                            : d.x - 10,
                        val_align = val >= 0 ? 'left' : 'right',
                        show_lbl = true,
                        show_val = true,
                        lblClass = me.chart.hasHighlight() && me.chart.isHighlighted(series) ? ' highlighted' : '';

                    if (labelsInsideBars) {
                        lbl_x = val >= 0 ? d.x + 10 : d.x + d.w - 10;
                        val_x = val >= 0 ? d.x + d.w - 10 : d.x + 10;
                        lbl_align = val >= 0 ? 'left' : 'right';
                        val_align = val >= 0 ? 'right' : 'left';

                        // check if the label is bigger than the bar
                        var slblw = me.labelWidth(series.name, 'series')+10,
                            vlblw = me.labelWidth(me.chart.formatValue(val, true), 'value')+20;
                        if (slblw + vlblw > d.w) {
                            show_val = false;
                            if (slblw > d.w) show_lbl = false;
                            /*lbl_x = d.x + d.w + 10;
                            val_x = lbl_x + slblw + 10;
                            val_align = 'left';
                            if (val < 0) {
                                lbl_align = 'left';
                            }*/

                        }
                        if (me.invertLabel(fill)) lblClass += ' inverted';
                    }
                    if (show_val) {
                        me.registerSeriesLabel(me.label(val_x, d.y + d.h * 0.5, me.chart.formatValue(series.data[r], true),{
                            w: 40,
                            align: val_align,
                            cl: 'value' + lblClass
                        }), series);
                    }

                    if (show_lbl) {
                        me.registerSeriesLabel(me.label(lbl_x , d.y + d.h * 0.5, series.name,{
                            w: 160,
                            align: lbl_align,
                            cl: 'series' + lblClass
                        }), series);
                    }

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

            if (me.__domain[0] < 0) {
                var x = c.lpad + c.zero ;
                if (labelsInsideBars) x -= 10;
                me.path([['M', x, c.tpad], ['L', x, c.lastBarY ]], 'axis')
                    .attr(me.theme.yAxis);
            }

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

        initDimensions: function(r) {
            //
            var me = this, c = me.__canvas,
                dMin = 0, dMax = 0, w = c.w - c.lpad - c.rpad - 30;
            _.each(me.chart.dataSeries(), function(series) {
                dMin = Math.min(dMin, series._min());
                dMax = Math.max(dMax, series._max());
            });
            me.__domain = [dMin, dMax];
            me.__scales = {
                y: d3.scale.linear().domain([dMin, dMax])
            };
            /* 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];
            _.each(me.chart.dataSeries(), function(series, s) {
                var neg = series.data[r] < 0;
                largestVal[neg ? 1 : 0] = Math.max(largestVal[neg ? 1 : 0], Math.abs(series.data[r]));
            });
            _.each(me.chart.dataSeries(), function(series, s) {
                var val = series.data[r],
                    neg = val < 0,
                    t = neg ? 2 : 0,
                    bw;
                bw = Math.abs(val) / (largestVal[0] + largestVal[1]) * w;
                maxw[t] = Math.max(maxw[t], me.labelWidth(series.name, 'series') + 20);
                maxw[t+1] = Math.max(maxw[t+1], me.labelWidth(me.chart.formatValue(series.data[r], true), 'value') + 20 + bw);
            });

            c.left = 0;
            c.right = 0;
            c.zero = 10 + largestVal[1] / (largestVal[0] + largestVal[1]) * w;

            if (!me.get('labels-inside-bars', false)) {

                var maxNegBar = c.zero;
                //console.log('c.left', );
                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;
            }
            c.maxSeriesLabelWidth = [maxw[0], maxw[2]];
            c.maxValueLabelWidth = [maxw[1], maxw[3]];

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

        barDimensions: function(series, s, r) {
            var me = this, w, h, x, y, i, cw, n = me.chart.dataSeries().length,
                sc = me.__scales, c = me.__canvas, bw, pad = 0.35, vspace = 0.1,
                val = series.data[r];

            //
            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;
            }
            y = Math.round(c.tpad + s * (bw + bw * pad));
            return { w: w, h: h, x: x, y: y };
        },

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

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        hoverSeries: function(series) {
            var me = this;
            _.each(me.chart.dataSeries(), function(s) {
                _.each(me.__seriesLabels[s.name], function(lbl) {
                    if (series !== undefined && s.name == series.name) {
                        lbl.addClass('hover');
                    } else {
                        lbl.removeClass('hover');
                    }
                    _.each(me.__seriesElements[s.name], function(el) {
                        var fill = me.getSeriesColor(s, 0, me.get('negative-color', false)), stroke;
                        if (series !== undefined && s.name == series.name) fill = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();
                        stroke = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();
                        if (el.attrs.fill != fill || el.attrs.stroke != stroke)
                            el.animate({ fill: fill, stroke: stroke }, 50);
                    });
                });
            });
        },

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

}).call(this);<commit_msg>bar chart: minor fix<commit_after>
(function(){
    // Simple perfect bar chart
    // -------------------------

    var BarChart = Datawrapper.Visualizations.BarChart = function() {

    };

    _.extend(BarChart.prototype, Datawrapper.Visualizations.RaphaelChart.prototype, {

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

            this.setRoot(el);

            var me = this,
            sortBars = me.get('sort-values'),
            reverse = me.get('reverse-order'),
            useNegativeColor = me.get('negative-color', false),
            c = me.initCanvas({
                h: Math.max(me.getMaxChartHeight(el), 18 * 1.35 * me.chart.dataSeries().length)
            }),
            chart_width = c.w - c.lpad - c.rpad,
            series_gap = 0.05, // pull from theme
            row_gap = 0.01,
            row = 0, // pull from theme
            labelsInsideBars = me.get('labels-inside-bars', false);

            if (!_.isUndefined(me.get('selected-row'))) {
                row = me.get('selected-row');
            }
            if (row > me.chart.numRows() || row === undefined) row = 0;
            if (me.chart.numRows() > 1) me.chart.filterRow(row);

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

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

            c.lastBarY = 0;

            _.each(me.chart.dataSeries(sortBars, reverse), function(series, s) {
                _.each(series.data, function(val, r) {
                    var d = me.barDimensions(series, s, r);
                    var fill = me.getSeriesColor(series, r, useNegativeColor),
                        stroke = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();

                    if (labelsInsideBars) d.x -= 10;

                    me.registerSeriesElement(c.paper.rect(d.x, d.y, d.w, d.h).attr({
                        'stroke': stroke,
                        'fill': fill
                    }).data('strokeCol', stroke), series);

                    var lbl_x = val >= 0 ?
                            c.zero - 10
                            : c.zero + 10,
                        lbl_align = val >= 0 ? 'right' : 'left',
                        val_x = val >= 0 ?
                            d.x + d.w + 10
                            : d.x - 10,
                        val_align = val >= 0 ? 'left' : 'right',
                        show_lbl = true,
                        show_val = true,
                        lblClass = me.chart.hasHighlight() && me.chart.isHighlighted(series) ? ' highlighted' : '';

                    if (labelsInsideBars) {
                        lbl_x = val >= 0 ? d.x + 10 : d.x + d.w - 10;
                        val_x = val >= 0 ? d.x + d.w - 10 : d.x + 10;
                        lbl_align = val >= 0 ? 'left' : 'right';
                        val_align = val >= 0 ? 'right' : 'left';

                        // check if the label is bigger than the bar
                        var slblw = me.labelWidth(series.name, 'series')+10,
                            vlblw = me.labelWidth(me.chart.formatValue(val, true), 'value')+20;
                        if (slblw + vlblw > d.w) {
                            show_val = false;
                            if (slblw > d.w) show_lbl = false;
                            /*lbl_x = d.x + d.w + 10;
                            val_x = lbl_x + slblw + 10;
                            val_align = 'left';
                            if (val < 0) {
                                lbl_align = 'left';
                            }*/

                        }
                        if (me.invertLabel(fill)) lblClass += ' inverted';
                    }
                    if (show_val) {
                        me.registerSeriesLabel(me.label(val_x, d.y + d.h * 0.5, me.chart.formatValue(series.data[r], true),{
                            w: 40,
                            align: val_align,
                            cl: 'value' + lblClass
                        }), series);
                    }

                    if (show_lbl) {
                        me.registerSeriesLabel(me.label(lbl_x , d.y + d.h * 0.5, series.name,{
                            w: 160,
                            align: lbl_align,
                            cl: 'series' + lblClass
                        }), series);
                    }

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

            if (me.__domain[0] < 0) {
                var x = c.lpad + c.zero ;
                if (labelsInsideBars) x -= 10;
                me.path([['M', x, c.tpad], ['L', x, c.lastBarY ]], 'axis')
                    .attr(me.theme.yAxis);
            }

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

        initDimensions: function(r) {
            //
            var me = this, c = me.__canvas,
                dMin = 0, dMax = 0, w = c.w - c.lpad - c.rpad - 30;
            _.each(me.chart.dataSeries(), function(series) {
                dMin = Math.min(dMin, series._min());
                dMax = Math.max(dMax, series._max());
            });
            me.__domain = [dMin, dMax];
            me.__scales = {
                y: d3.scale.linear().domain([dMin, dMax])
            };
            /* 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];
            _.each(me.chart.dataSeries(), function(series, s) {
                var neg = series.data[r] < 0;
                largestVal[neg ? 1 : 0] = Math.max(largestVal[neg ? 1 : 0], Math.abs(series.data[r]));
            });
            _.each(me.chart.dataSeries(), function(series, s) {
                var val = series.data[r],
                    neg = val < 0,
                    t = neg ? 2 : 0,
                    bw;
                bw = Math.abs(val) / (largestVal[0] + largestVal[1]) * w;
                maxw[t] = Math.max(maxw[t], me.labelWidth(series.name, 'series') + 20);
                maxw[t+1] = Math.max(maxw[t+1], me.labelWidth(me.chart.formatValue(series.data[r], true), 'value') + 20 + bw);
            });

            c.left = 0;
            c.right = 0;
            c.zero = largestVal[1] / (largestVal[0] + largestVal[1]) * w;

            if (!me.get('labels-inside-bars', false)) {

                var maxNegBar = c.zero;
                //console.log('c.left', );
                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(series, s, r) {
            var me = this, w, h, x, y, i, cw, n = me.chart.dataSeries().length,
                sc = me.__scales, c = me.__canvas, bw, pad = 0.35, vspace = 0.1,
                val = series.data[r];

            //
            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;
            }
            y = Math.round(c.tpad + s * (bw + bw * pad));
            return { w: w, h: h, x: x, y: y };
        },

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

        showTooltip: function() {

        },

        hideTooltip: function() {

        },

        hoverSeries: function(series) {
            var me = this;
            _.each(me.chart.dataSeries(), function(s) {
                _.each(me.__seriesLabels[s.name], function(lbl) {
                    if (series !== undefined && s.name == series.name) {
                        lbl.addClass('hover');
                    } else {
                        lbl.removeClass('hover');
                    }
                    _.each(me.__seriesElements[s.name], function(el) {
                        var fill = me.getSeriesColor(s, 0, me.get('negative-color', false)), stroke;
                        if (series !== undefined && s.name == series.name) fill = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();
                        stroke = d3.cie.lch(d3.rgb(fill)).darker(0.6).toString();
                        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>/* jshint eqnull:true */

define(function(require, exports, module) {
    "use strict";

    var app = require("app");
    var AbstractView = require("modules/view/AbstractView");
    var PersonalModel = require("modules/model/personal/PersonalModel");
    var Snap = require("snap");

    var GlobalNavView = AbstractView.extend({
        template : require("ldsh!templates/{mode}/common/global-nav"),

        /**
         * 文字サイズ変更後のタイマー
         */
        fontTimer : null,
        beforeRendered : function() {
        },

        afterRendered : function() {
            this.updateBackHomeButton();
            var $target = $("[value='" + app.user.get("fontSize") + "']");
            var size = parseInt($target.attr('data-font-size'), 10);
            $('html, body').css('font-size', size + 'px');
        },

        initialize : function() {
            this.snapper = new Snap({
                element: $('#snap-content')[0],
                tapToClose: true,
                touchToDrag: false
            });
            $('#snap-content').data("snap",this.snapper);
        },

        /**
         * RadiationエンティティセットへのFetch成功時のイベントハンドラ。
         */
        onFetchRadiation: function() {
            var model = this.collection.at(0);
            var value = "-";
            if (model) {
                value = model.get("value");
            }
            $("#radiationValue").text(value + "μSv/h");
        },

        events : {
            'click [data-drawer-opener]': 'onClickDrawerOpener',
            'click [data-back-home]': 'onClickBackHome',
            'change #selectRadiation' : "onChangeRadiationStation",
            'click [data-font-size]': 'onClickFontSize'
        },

        /**
         *  今日の新聞に戻るボタンは
         *  topでは表示しない
         */
        updateBackHomeButton: function () {
            if (Backbone.history.fragment == 'top') {
                $('[data-back-home]').hide();
            } else {
                $('[data-back-home]').show();
            }
        },

        /**
         *  サンドイッチボタンがクリックされたら呼ばれる
         *  @param {Event} ev
         */
        onClickDrawerOpener: function (ev) {
            app.ga.trackEvent("新聞アプリ/全ページ共通", "ヘッダ部メニュー","");
            ev.preventDefault();
            this.snapper.open('left');
        },

        /**
         *  今日の新聞に戻るボタンが押されたら呼ばれる
         */
        onClickBackHome: function (ev) {
            ev.preventDefault();
            app.router.back();
        },

        /**
         *  フォントサイズ変更ボタンが押されたら呼ばれる
         */
        onClickFontSize: function (ev) {
            app.trigger('willChangeFontSize');

            var $target = $(ev.currentTarget);
            var size = parseInt($target.attr('data-font-size'), 10);
            app.ga.trackEvent("新聞アプリ/全ページ共通", "文字サイズ選択", parseInt(size));

            $('html, body').css('font-size', size + 'px');

            app.trigger('didChangeFontSize');

            // 連続で押下された場合にリクエストが多数飛ばないようにするため
            // 数秒後に文字サイズ登録リクエストを飛ばす。
            // この間に再度文字サイズを変更されると前回の登録処理は無効とする
            if (this.fontTimer !== null) {
                clearTimeout(this.fontTimer);
            }
            this.fontTimer = setTimeout($.proxy(function() {
                this.saveFontSize($target.attr("value"));
            },this),1500);

        },
        /**
         *  文字サイズの保存処理
         *  @param {String} fontSize 文字サイズ
         */
        saveFontSize: function (fontSize) {
            var model = app.user;
            model.set("fontSize",fontSize);
            model.set("etag","*");
            // 文字サイズのみの保存処理のため、成功時や失敗時に
            // その都度ユーザに通知しない
            model.save(null,{});
        },
    });

    module.exports = GlobalNavView;
});
<commit_msg>NAM-235 Conflict解消 担当：増田<commit_after>/* jshint eqnull:true */

define(function(require, exports, module) {
    "use strict";

    var app = require("app");
    var AbstractView = require("modules/view/AbstractView");
    var PersonalModel = require("modules/model/personal/PersonalModel");
    var Snap = require("snap");

    var GlobalNavView = AbstractView.extend({
        template : require("ldsh!templates/{mode}/common/global-nav"),

        /**
         * 文字サイズ変更後のタイマー
         */
        fontTimer : null,
        beforeRendered : function() {
        },

        afterRendered : function() {
            this.updateBackHomeButton();
            var $target = $("[value='" + app.user.get("fontSize") + "']");
            var size = parseInt($target.attr('data-font-size'), 10);
            $('html, body').css('font-size', size + 'px');
        },

        initialize : function() {
            this.snapper = new Snap({
                element: $('#snap-content')[0],
                tapToClose: true,
                touchToDrag: false
            });
            $('#snap-content').data("snap",this.snapper);
        },

        /**
         * RadiationエンティティセットへのFetch成功時のイベントハンドラ。
         */
        onFetchRadiation: function() {
            var model = this.collection.at(0);
            var value = "-";
            if (model) {
                value = model.get("value");
            }
            $("#radiationValue").text(value + "μSv/h");
        },

        events : {
            'click [data-drawer-opener]': 'onClickDrawerOpener',
            'click [data-back-home]': 'onClickBackHome',
            'change #selectRadiation' : "onChangeRadiationStation",
            'click [data-font-size]': 'onClickFontSize'
        },

        /**
         *  今日の新聞に戻るボタンは
         *  topでは表示しない
         */
        updateBackHomeButton: function () {
            if (Backbone.history.fragment == 'top') {
                $('[data-back-home]').hide();
            } else {
                $('[data-back-home]').show();
            }
        },

        /**
         *  サンドイッチボタンがクリックされたら呼ばれる
         *  @param {Event} ev
         */
        onClickDrawerOpener: function (ev) {
            app.ga.trackEvent("新聞アプリ/全ページ共通", "ヘッダ部メニュー","");
            ev.preventDefault();
            this.snapper.open('left');
        },

        /**
         *  今日の新聞に戻るボタンが押されたら呼ばれる
         */
        onClickBackHome: function (ev) {
            ev.preventDefault();
            app.router.back();
        },

        /**
         *  フォントサイズ変更ボタンが押されたら呼ばれる
         */
        onClickFontSize: function (ev) {
            app.trigger('willChangeFontSize');

            var $target = $(ev.currentTarget);
            var size = parseInt($target.attr('data-font-size'), 10);
            app.ga.trackEvent("新聞アプリ/全ページ共通", "文字サイズ選択", parseInt(size));
            $('html, body').css('font-size', size + 'px');

            app.trigger('didChangeFontSize');

            // 連続で押下された場合にリクエストが多数飛ばないようにするため
            // 数秒後に文字サイズ登録リクエストを飛ばす。
            // この間に再度文字サイズを変更されると前回の登録処理は無効とする
            if (this.fontTimer !== null) {
                clearTimeout(this.fontTimer);
            }
            this.fontTimer = setTimeout($.proxy(function() {
                this.saveFontSize($target.attr("value"));
            },this),1500);

        },
        /**
         *  文字サイズの保存処理
         *  @param {String} fontSize 文字サイズ
         */
        saveFontSize: function (fontSize) {
            var model = app.user;
            model.set("fontSize",fontSize);
            model.set("etag","*");
            // 文字サイズのみの保存処理のため、成功時や失敗時に
            // その都度ユーザに通知しない
            model.save(null,{});
        },
    });

    module.exports = GlobalNavView;
});
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;
var _ = require('underscore');
var path = require('path');
var fs = require('fs');
var Promise = require('bluebird');
var machine = require('../../utils/DockerMachineUtil');
var virtualBox = require('../../utils/VirtualBoxUtil');
var setupUtil = require('../../utils/SetupUtil');
var util = require('../../utils/Util');
var SetupStore = require('../SetupStore.js')

var _currentStep = null;
var _error = null;
var _cancelled = false;
var _retryPromise = null;
var _requiredSteps = [];

var _steps = [{
  name: 'download',
  title: 'Downloading VirtualBox',
  message: 'VirtualBox is being downloaded. You have selected the VirtualBox driver.',
  totalPercent: 35,
  percent: 0,
  run: function (progressCallback) {
    return setupUtil.download(virtualBox.url(), path.join(util.supportDir(), virtualBox.filename()), virtualBox.checksum(), percent => {
      progressCallback(percent);
    });
  }
}, {
  name: 'install',
  title: 'Installing VirtualBox',
  message: 'VirtualBox is being installed or upgraded in the background. We may need you to type in your password to continue.',
  totalPercent: 5,
  percent: 0,
  seconds: 5,
  run: Promise.coroutine(function* (progressCallback) {
    if (!virtualBox.installed()) {
      yield virtualBox.killall();
      progressCallback(50); // TODO: detect when the installation has started so we can simulate progress
      try {
        if (util.isWindows()) {
          yield util.exec([path.join(util.supportDir(), virtualBox.filename()), '-msiparams', 'REBOOT=ReallySuppress', 'LIMITUI=INSTALLUILEVEL_PROGRESSONLY']);
        } else {
          yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd()));
        }
      } catch (err) {
        throw null;
      }
    } else if (!util.isWindows() && !virtualBox.active()) {
      yield util.exec(setupUtil.macSudoCmd(util.escapePath('/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh') + ' restart'));
    }
  })
}, {
  name: 'init',
  title: 'Starting Docker VM',
  message: 'To run Docker containers on VirtualBox locally, Kitematic is starting a Linux virtual machine in VirtualBox. This may take a minute...',
  totalPercent: 60,
  percent: 0,
  seconds: 110,
  run: Promise.coroutine(function* (progressCallback) {
    setupUtil.simulateProgress(this.seconds, progressCallback);
    var exists = yield machine.exists();
    if (!exists || (yield machine.state()) === 'Error') {
      if (exists && (yield machine.state()) === 'Error') {
        yield machine.rm();
      }
      yield machine.create();
      return;
    }

    var isoversion = machine.isoversion();
    var packagejson = util.packagejson();
    if (!isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0) {
      yield machine.start();
      yield machine.upgrade();
    }
    if ((yield machine.state()) !== 'Running') {
      yield machine.start();
    }
  })
}];
<commit_msg>Readd functions for vbox setup<commit_after>var EventEmitter = require('events').EventEmitter;
var _ = require('underscore');
var path = require('path');
var fs = require('fs');
var Promise = require('bluebird');
var machine = require('../utils/DockerMachineUtil');
var virtualBox = require('../utils/VirtualBoxUtil');
var setupUtil = require('../utils/SetupUtil');
var util = require('../utils/Util');
var assign = require('object-assign');
var metrics = require('../utils/MetricsUtil');
var bugsnag = require('bugsnag-js');
var docker = require('../utils/DockerUtil');

var _currentStep = null;
var _error = null;
var _cancelled = false;
var _retryPromise = null;
var _requiredSteps = [];

var _steps = [{
  name: 'download',
  title: 'Downloading VirtualBox',
  message: 'VirtualBox is being downloaded. Kitematic requires VirtualBox to run containers.',
  totalPercent: 35,
  percent: 0,
  run: function (progressCallback) {
    return setupUtil.download(virtualBox.url(), path.join(util.supportDir(), virtualBox.filename()), virtualBox.checksum(), percent => {
      progressCallback(percent);
    });
  }
}, {
  name: 'install',
  title: 'Installing VirtualBox & Docker',
  message: 'VirtualBox & Docker are being installed or upgraded in the background. We may need you to type in your password to continue.',
  totalPercent: 5,
  percent: 0,
  seconds: 5,
  run: Promise.coroutine(function* (progressCallback) {
    if (!virtualBox.installed()) {
      yield virtualBox.killall();
      progressCallback(50); // TODO: detect when the installation has started so we can simulate progress
      try {
        if (util.isWindows()) {
          yield util.exec([path.join(util.supportDir(), virtualBox.filename()), '-msiparams', 'REBOOT=ReallySuppress', 'LIMITUI=INSTALLUILEVEL_PROGRESSONLY']);
        } else {
          yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd()));
        }
      } catch (err) {
        throw null;
      }
    } else if (!util.isWindows() && !virtualBox.active()) {
      yield util.exec(setupUtil.macSudoCmd(util.escapePath('/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh') + ' restart'));
    }
  })
}, {
  name: 'init',
  title: 'Starting Docker VM',
  message: 'To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...',
  totalPercent: 60,
  percent: 0,
  seconds: 110,
  run: Promise.coroutine(function* (progressCallback) {
    setupUtil.simulateProgress(this.seconds, progressCallback);
    var exists = yield machine.exists();
    if (!exists || (yield machine.state()) === 'Error') {
      if (exists && (yield machine.state()) === 'Error') {
        yield machine.rm();
      }
      yield machine.create();
      return;
    }

    var isoversion = machine.isoversion();
    var packagejson = util.packagejson();
    if (!isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0) {
      yield machine.start();
      yield machine.upgrade();
    }
    if ((yield machine.state()) !== 'Running') {
      yield machine.start();
    }
  })
}];

var SetupStore = assign(Object.create(EventEmitter.prototype), {
  PROGRESS_EVENT: 'setup_progress',
  STEP_EVENT: 'setup_step',
  ERROR_EVENT: 'setup_error',
  step: function () {
    return _currentStep;
  },
  steps: function () {
    return _.indexBy(_steps, 'name');
  },
  stepCount: function () {
    return _requiredSteps.length;
  },
  number: function () {
    return _.indexOf(_requiredSteps, _currentStep) + 1;
  },
  percent: function () {
    var sofar = 0;
    var totalPercent = _requiredSteps.reduce((prev, step) => prev + step.totalPercent, 0);
    _.each(_requiredSteps, step => {
      sofar += step.totalPercent * step.percent / 100;
    });
    return Math.min(Math.round(100 * sofar / totalPercent), 99);
  },
  error: function () {
    return _error;
  },
  cancelled: function () {
    return _cancelled;
  },
  retry: function (remove) {
    _error = null;
    _cancelled = false;
    if (!_retryPromise) {
      return;
    }
    this.emit(this.ERROR_EVENT);
    if (remove) {
      machine.rm().finally(() => {
        _retryPromise.resolve();
      });
    } else {
      machine.stop().finally(() => {
        _retryPromise.resolve();
      });
    }
  },
  setError: function (error) {
    _error = error;
    this.emit(this.ERROR_EVENT);
  },
  pause: function () {
    _retryPromise = Promise.defer();
    return _retryPromise.promise;
  },
  requiredSteps: Promise.coroutine(function* () {
    if (_requiredSteps.length) {
      return Promise.resolve(_requiredSteps);
    }
    var packagejson = util.packagejson();
    var isoversion = machine.isoversion();
    var required = {};
    var vboxfile = path.join(util.supportDir(), virtualBox.filename());
    var vboxNeedsInstall = !virtualBox.installed();

    required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== virtualBox.checksum());
    required.install = vboxNeedsInstall || (!util.isWindows() && !virtualBox.active());
    required.init = required.install || !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0;

    var exists = yield machine.exists();
    if (isoversion && util.compareVersions(isoversion, packagejson['docker-version']) < 0) {
      this.steps().init.seconds = 33;
    } else if (exists && (yield machine.state()) === 'Saved') {
      this.steps().init.seconds = 8;
    } else if (exists && (yield machine.state()) !== 'Error') {
      this.steps().init.seconds = 23;
    }

    _requiredSteps = _steps.filter(function (step) {
      return required[step.name];
    });
    return Promise.resolve(_requiredSteps);
  }),
  run: Promise.coroutine(function* () {
    metrics.track('Started Setup', {
      virtualbox: virtualBox.installed() ? yield virtualBox.version() : 'Not Installed'
    });
    var steps = yield this.requiredSteps();
    for (let step of steps) {
      _currentStep = step;
      step.percent = 0;
      while (true) {
        try {
          this.emit(this.STEP_EVENT);
          yield step.run(percent => {
            if (_currentStep) {
              step.percent = percent;
              this.emit(this.PROGRESS_EVENT);
            }
          });
          metrics.track('Setup Completed Step', {
            name: step.name
          });
          step.percent = 100;
          break;
        } catch (err) {
          if (err) {
            throw err;
          } else {
            metrics.track('Setup Cancelled');
            _cancelled = true;
            this.emit(this.STEP_EVENT);
          }
          yield this.pause();
        }
      }
    }
    _currentStep = null;
    return yield machine.ip();
  }),
  setup: Promise.coroutine(function * () {
    while (true) {
      try {
        var ip = yield this.run();
        if (!ip || !ip.length) {
          throw {
            message: 'Machine IP could not be fetched. Please retry the setup. If this fails please file a ticket on our GitHub repo.',
            machine: yield machine.info(),
            ip: ip
          };
        }
        docker.setup(ip, machine.name());
        yield docker.waitForConnection();
        metrics.track('Setup Finished');
        break;
      } catch (err) {
        err.message = util.removeSensitiveData(err.message);
        metrics.track('Setup Failed', {
          step: _currentStep,
        });
        console.log(err);
        bugsnag.notify('SetupError', err.message, {
          error: err,
          output: err.message
        }, 'info');
        _error = err;
        this.emit(this.ERROR_EVENT);
        yield this.pause();
      }
    }
  })
});

module.exports = SetupStore;
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {EnvironmentMixin} from '../../features/environment.js';
import ModelViewerElementBase, {$scene} from '../../model-viewer-base.js';
import {assetPath, textureMatchesMeta, timePasses, waitForEvent} from '../helpers.js';

const expect = chai.expect;
const BG_IMAGE_URL = assetPath('equirectangular.png');
const MODEL_URL = assetPath('reflective-sphere.gltf');

const skysphereUsingMap =
    (scene, url) => {
      const material = scene.skysphere.material;
      const color = material.color.getHexString();
      return textureMatchesMeta(material.map, {url: url}) && color === 'ffffff';
    }

const skysphereUsingColor =
    (scene, hex) => {
      const {color, map} = scene.skysphere.material;
      // Invert gamma correct to match passed in hex
      const gammaCorrectedColor = color.clone().convertLinearToGamma(2.2);

      return map == null && gammaCorrectedColor.getHexString() === hex;
    }

/**
 * Takes a scene and a meta object and returns a
 * boolean indicating whether or not the scene's model has an
 * environment map applied that matches the meta object.
 *
 * @see textureMatchesMeta
 * @param {THREE.Scene} scene
 * @param {Object} meta
 */
const modelUsingEnvmap = (scene, meta) => {
  let found = false;
  scene.model.traverse(object => {
    if (!object.material || !object.material.envMap) {
      return;
    }

    if (textureMatchesMeta(object.material.envMap, meta)) {
      found = true;
    }
  });
  return found;
};

/**
 * Takes a model object and a meta object and returns
 * a promise that resolves when the model's environment map has
 * been set to a texture that has `userData` that matches
 * the passed in `meta`.
 *
 * @see textureMatchesMeta
 * @param {Model} model
 * @param {Object} meta
 */
const waitForEnvmap = (model, meta) => waitForEvent(
    model,
    'envmap-change',
    e => textureMatchesMeta(e.value, {...meta, type: 'EnvironmentMap'}));

/**
 * Returns a promise that resolves when a given element is loaded
 * and has an environment map set that matches the passed in meta.
 * @see textureMatchesMeta
 */
const waitForLoadAndEnvmap = (scene, element, meta) => Promise.all(
    [waitForEvent(element, 'load'), waitForEnvmap(scene.model, meta)]);

suite('ModelViewerElementBase with EnvironmentMixin', () => {
  let nextId = 0;
  let tagName;
  let ModelViewerElement;
  let element;
  let scene;

  setup(() => {
    tagName = `model-viewer-environment-${nextId++}`;
    ModelViewerElement = class extends EnvironmentMixin
    (ModelViewerElementBase) {
      static get is() {
        return tagName;
      }
    };
    customElements.define(tagName, ModelViewerElement);
    element = new ModelViewerElement();
    scene = element[$scene];
  });

  teardown(() => element.parentNode && element.parentNode.removeChild(element));

  test(
      'has default skysphere if no background-image or background-color',
      () => {
        expect(skysphereUsingColor(scene, 'ffffff')).to.be.equal(true);
      });

  test(
      'has default skysphere if no background-image or background-color when in DOM',
      async () => {
        document.body.appendChild(element);
        await timePasses();
        expect(skysphereUsingColor(scene, 'ffffff')).to.be.equal(true);
      });

  suite('with a background-image property', () => {
    suite('and a src property', () => {
      setup(async () => {
        let onLoad = waitForLoadAndEnvmap(scene, element, {url: BG_IMAGE_URL});
        element.src = MODEL_URL;
        element.backgroundImage = BG_IMAGE_URL;
        await onLoad;
      });

      test('displays skysphere with the correct map', async function() {
        expect(skysphereUsingMap(scene, element.backgroundImage)).to.be.ok;
      });

      test('applies the image as an environment map', async function() {
        expect(modelUsingEnvmap(scene, {
          url: element.backgroundImage
        })).to.be.ok;
      });
    });
  });

  suite('with a background-color property', () => {
    suite('and a src property', () => {
      setup(async () => {
        let onLoad = waitForLoadAndEnvmap(scene, element, {url: null});
        element.src = MODEL_URL;
        element.backgroundColor = '#ff0077';
        await onLoad;
      });

      test('displays skysphere with the correct color', async function() {
        expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
      });

      test('applies a generated environment map on model', async function() {
        expect(modelUsingEnvmap(scene, {url: null})).to.be.ok;
      });

      test(
          'displays skysphere with correct color after attaching to DOM',
          async function() {
            document.body.appendChild(element);
            await timePasses();
            expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
          });
    });
  });

  suite('with background-color and background-image properties', () => {
    setup(async () => {
      let onLoad = waitForLoadAndEnvmap(scene, element, {url: BG_IMAGE_URL});
      element.setAttribute('src', MODEL_URL);
      element.setAttribute('background-color', '#ff0077');
      element.setAttribute('background-image', BG_IMAGE_URL);
      await onLoad;
    });

    test('displays skysphere with background-image', async function() {
      expect(skysphereUsingMap(scene, element.backgroundImage)).to.be.ok;
    });

    test('applies background-image envmap on model', async function() {
      expect(modelUsingEnvmap(scene, {url: element.backgroundImage})).to.be.ok;
    });

    suite('and background-image subsequently removed', () => {
      setup(async () => {
        let envmapChanged = waitForEnvmap(scene.model, {url: null});
        element.removeAttribute('background-image');
        await envmapChanged;
      });

      test('displays skysphere with background-color', async function() {
        expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
      });

      test('reapplies generated envmap on model', async function() {
        expect(modelUsingEnvmap(scene, {url: null})).to.be.ok;
      });
    });
  });
});
<commit_msg>Test directional light tinting<commit_after>/*
 * Copyright 2018 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {EnvironmentMixin} from '../../features/environment.js';
import ModelViewerElementBase, {$scene} from '../../model-viewer-base.js';
import {assetPath, textureMatchesMeta, timePasses, waitForEvent} from '../helpers.js';

const expect = chai.expect;
const BG_IMAGE_URL = assetPath('equirectangular.png');
const MODEL_URL = assetPath('reflective-sphere.gltf');

const skysphereUsingMap =
    (scene, url) => {
      const material = scene.skysphere.material;
      const color = material.color.getHexString();
      return textureMatchesMeta(material.map, {url: url}) && color === 'ffffff';
    }

const skysphereUsingColor =
    (scene, hex) => {
      const {color, map} = scene.skysphere.material;
      // Invert gamma correct to match passed in hex
      const gammaCorrectedColor = color.clone().convertLinearToGamma(2.2);

      return map == null && gammaCorrectedColor.getHexString() === hex;
    }

/**
 * Takes a scene and a meta object and returns a
 * boolean indicating whether or not the scene's model has an
 * environment map applied that matches the meta object.
 *
 * @see textureMatchesMeta
 * @param {THREE.Scene} scene
 * @param {Object} meta
 */
const modelUsingEnvmap = (scene, meta) => {
  let found = false;
  scene.model.traverse(object => {
    if (!object.material || !object.material.envMap) {
      return;
    }

    if (textureMatchesMeta(object.material.envMap, meta)) {
      found = true;
    }
  });
  return found;
};

/**
 * Takes a model object and a meta object and returns
 * a promise that resolves when the model's environment map has
 * been set to a texture that has `userData` that matches
 * the passed in `meta`.
 *
 * @see textureMatchesMeta
 * @param {Model} model
 * @param {Object} meta
 */
const waitForEnvmap = (model, meta) => waitForEvent(
    model,
    'envmap-change',
    e => textureMatchesMeta(e.value, {...meta, type: 'EnvironmentMap'}));

/**
 * Returns a promise that resolves when a given element is loaded
 * and has an environment map set that matches the passed in meta.
 * @see textureMatchesMeta
 */
const waitForLoadAndEnvmap = (scene, element, meta) => Promise.all(
    [waitForEvent(element, 'load'), waitForEnvmap(scene.model, meta)]);

suite('ModelViewerElementBase with EnvironmentMixin', () => {
  let nextId = 0;
  let tagName;
  let ModelViewerElement;
  let element;
  let scene;

  setup(() => {
    tagName = `model-viewer-environment-${nextId++}`;
    ModelViewerElement = class extends EnvironmentMixin
    (ModelViewerElementBase) {
      static get is() {
        return tagName;
      }
    };
    customElements.define(tagName, ModelViewerElement);
    element = new ModelViewerElement();
    scene = element[$scene];
  });

  teardown(() => element.parentNode && element.parentNode.removeChild(element));

  test(
      'has default skysphere if no background-image or background-color',
      () => {
        expect(skysphereUsingColor(scene, 'ffffff')).to.be.equal(true);
      });

  test(
      'has default skysphere if no background-image or background-color when in DOM',
      async () => {
        document.body.appendChild(element);
        await timePasses();
        expect(skysphereUsingColor(scene, 'ffffff')).to.be.equal(true);
      });

  suite('with a background-image property', () => {
    suite('and a src property', () => {
      setup(async () => {
        let onLoad = waitForLoadAndEnvmap(scene, element, {url: BG_IMAGE_URL});
        element.src = MODEL_URL;
        element.backgroundImage = BG_IMAGE_URL;
        await onLoad;
      });

      test('displays skysphere with the correct map', async function() {
        expect(skysphereUsingMap(scene, element.backgroundImage)).to.be.ok;
      });

      test('applies the image as an environment map', async function() {
        expect(modelUsingEnvmap(scene, {
          url: element.backgroundImage
        })).to.be.ok;
      });

      suite('and a background-color property', () => {
        setup(async () => {
          element.backgroundColor = '#ff0077';
          await timePasses();
        });

        test('the directional light is white', () => {
          const lightColor =
              scene.shadowLight.color.getHexString().toLowerCase();
          expect(lightColor).to.be.equal('ffffff');
        });
      });
    });
  });

  suite('with a background-color property', () => {
    suite('and a src property', () => {
      setup(async () => {
        let onLoad = waitForLoadAndEnvmap(scene, element, {url: null});
        element.src = MODEL_URL;
        element.backgroundColor = '#ff0077';
        await onLoad;
      });

      test('displays skysphere with the correct color', async function() {
        expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
      });

      test('applies a generated environment map on model', async function() {
        expect(modelUsingEnvmap(scene, {url: null})).to.be.ok;
      });

      test(
          'displays skysphere with correct color after attaching to DOM',
          async function() {
            document.body.appendChild(element);
            await timePasses();
            expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
          });
      test('the directional light is tinted', () => {
        const lightColor = scene.shadowLight.color.getHexString().toLowerCase();
        expect(lightColor).to.not.be.equal('ffffff');
      });
    });
  });

  suite('with background-color and background-image properties', () => {
    setup(async () => {
      let onLoad = waitForLoadAndEnvmap(scene, element, {url: BG_IMAGE_URL});
      element.setAttribute('src', MODEL_URL);
      element.setAttribute('background-color', '#ff0077');
      element.setAttribute('background-image', BG_IMAGE_URL);
      await onLoad;
    });

    test('displays skysphere with background-image', async function() {
      expect(skysphereUsingMap(scene, element.backgroundImage)).to.be.ok;
    });

    test('applies background-image envmap on model', async function() {
      expect(modelUsingEnvmap(scene, {url: element.backgroundImage})).to.be.ok;
    });

    suite('and background-image subsequently removed', () => {
      setup(async () => {
        let envmapChanged = waitForEnvmap(scene.model, {url: null});
        element.removeAttribute('background-image');
        await envmapChanged;
      });

      test('displays skysphere with background-color', async function() {
        expect(skysphereUsingColor(scene, 'ff0077')).to.be.ok;
      });

      test('reapplies generated envmap on model', async function() {
        expect(modelUsingEnvmap(scene, {url: null})).to.be.ok;
      });
    });
  });
});
<|endoftext|>


<commit_before>test(
  'ObjectsTest',

  [
    'ephox.boulder.api.Objects',
    'ephox.compass.Arr',
    'ephox.compass.Obj',
    'ephox.numerosity.api.JSON',
    'ephox.perhaps.Result',
    'ephox.wrap.Jsc'
  ],

  function (Objects, Arr, Obj, Json, Result, Jsc) {
    var smallSet = Jsc.nestring;

    var check = function (arb, checker) {
      Jsc.check(
        Jsc.forall(arb, function (input) {
          checker(input);
          return true;
        })
      );
    };

    var testNarrow = function () {
      var narrowGen = Jsc.bless({
        generator: Jsc.dict(smallSet).generator.flatMap(function (obj) {
          var keys = Obj.keys(obj);
          return keys.length === 0 ? Jsc.constant( { obj: obj, fields: [ ] }).generator : Jsc.array(Jsc.elements(keys)).generator.map(function (fields) {
            return {
              obj: obj,
              fields: fields
            };
          });
        })
      });

      check(narrowGen, function (input) {
        var narrowed = Objects.narrow(input.obj, input.fields);
        Obj.each(narrowed, function (_, k) {
          if (!Arr.contains(input.fields, k)) throw 'Narrowed object contained property: ' + k + ' which was not in fields: [' + input.fields.join(', ') + ']';
        });
        return true;
      });

      // Sanity test.
      var actual = Objects.narrow({ a: 'a', b: 'b', c: 'c' }, [ 'a', 'c', 'e' ]);
      assert.eq({ a: 'a', c: 'c' }, actual);
    };

    var testReaders = function () {
      // TODO: Think of a good way to property test.
      var subject = { alpha: 'Alpha' };

      assert.eq('Alpha', Objects.readOpt('alpha')(subject).getOrDie('readOpt(alpha) => some(Alpha)'), 'readOpt(alpha) => some(Alpha)');
      assert.eq(true, Objects.readOpt('beta')(subject).isNone(), 'readOpt(beta) => none');

      assert.eq('Alpha', Objects.readOr('alpha', 'fallback')(subject), 'readOr(alpha) => Alpha');
      assert.eq('fallback', Objects.readOr('beta', 'fallback')(subject), 'readOr(beta) => fallback');

      assert.eq('Alpha', Objects.readOptFrom(subject, 'alpha').getOrDie('readOptFrom(alpha) => some(Alpha)'), 'readOptFrom(alpha) => some(Alpha)');
      assert.eq(true, Objects.readOptFrom(subject, 'beta').isNone(), 'readOptFrom(beta) => none');
    };

    var testConsolidate = function () {
      var checkErr = function (label, expected, objs, base) {
        Objects.consolidate(objs, base).fold(function (err) {
          assert.eq(expected, err);
        }, function (val) {
          assert.fail(label + '\nExpected error(' + Json.stringify(expected) + '), but was: ' + Json.stringify(val));
        });
      };

      var checkVal = function (label, expected, objs, base) {
        Objects.consolidate(objs, base).fold(function (err) {
          assert.fail(label + '\nExpected value(' + Json.stringify(expected) + '), but was error(' + Json.stringify(err) + ')');
        }, function (val) {
          assert.eq(expected, val);
        });
      };

      checkVal(
        'empty objects',
        { },
        [ ], {}
      );

      checkErr(
        '[ failure ] ]',
        [ 'failure.1' ],
        [
          Result.error([ 'failure.1' ])
        ], {}
      );

      checkErr(
        '[ failure {1,2,3} ]',
        [ 'failure.1', 'failure.2', 'failure.3' ],
        [
          Result.error([ 'failure.1' ]),
          Result.error([ 'failure.2' ]),
          Result.error([ 'failure.3' ])
        ], {}
      );

      checkVal(
        '[ value.a ]',
        { a: 'A' },
        [
          Result.value({ a: 'A' })
        ], {}
      );

      checkVal(
        '[ value.{a,b,c} ]',
        { a: 'A' , b: 'B', c: 'C'},
        [
          Result.value({ a: 'A' }),
          Result.value({ b: 'B' }),
          Result.value({ c: 'C' })
        ], {}
      );

      checkErr(
        '[ value.a, failure.1, value.b ]',
        [ 'failure.1' ],
        [
          Result.value({ a: 'A' }),
          Result.error([ 'failure.1' ]),
          Result.value({ b: 'B' })
        ], {}
      );

      checkErr(
        '[ value.a, failure.1, value.b, failure.2, failure.3 ]',
        [ 'failure.1', 'failure.2', 'failure.3' ],
        [
          Result.value({ a: 'A' }),
          Result.error([ 'failure.1' ]),
          Result.value({ b: 'B' }),
          Result.error([ 'failure.2' ]),
          Result.error([ 'failure.3' ])
        ], {}
      );

      checkErr(
        '[ value.{a,b,c} ]',
        [ 'failure.last' ],
        [
          Result.value({ a: 'A' }),
          Result.value({ b: 'B' }),
          Result.value({ c: 'C' }),
          Result.error([ 'failure.last' ])
        ], {}
      );

      // some property-based tests
      var resultList = Jsc.bless({
        generator: Jsc.dict(smallSet).generator.flatMap(function (obj) {
          return Jsc.bool.generator.flatMap(function (flag) {
            return flag ? Jsc.constant(Result.value(obj)).generator : (function () {
              return Jsc.array(Jsc.nestring).generator.map(Result.error);
            })();
          });
        })
      });

      var inputList = Jsc.bless({
        generator: Jsc.array(resultList).generator.flatMap(function (results) {
          return Jsc.dict(smallSet).generator.map(function (base) {
            return {
              results: results,
              base: base
            };
          });
        })
      });

      // HERE.
      check(inputList, function (input) {
        var actual = Objects.consolidate(input.results, input.base);

        var hasError = Arr.exists(input.results, function (res) {
          return res.isError();
        });

        if (hasError) assert.eq(true, actual.isError(), 'Error contained in list, so should be error overall');
        else assert.eq(true, actual.isValue(), 'No errors in list, so should be value overall');
      });
    };

    testNarrow();
    testReaders();
    testConsolidate();
  }
);<commit_msg>VAN-10: cleanup<commit_after>test(
  'ObjectsTest',

  [
    'ephox.boulder.api.Objects',
    'ephox.compass.Arr',
    'ephox.compass.Obj',
    'ephox.numerosity.api.JSON',
    'ephox.perhaps.Result',
    'ephox.wrap.Jsc'
  ],

  function (Objects, Arr, Obj, Json, Result, Jsc) {
    var smallSet = Jsc.nestring;

    var check = function (arb, checker) {
      Jsc.check(
        Jsc.forall(arb, function (input) {
          checker(input);
          return true;
        })
      );
    };

    var testNarrow = function () {
      var narrowGen = Jsc.bless({
        generator: Jsc.dict(smallSet).generator.flatMap(function (obj) {
          var keys = Obj.keys(obj);
          return keys.length === 0 ? Jsc.constant( { obj: obj, fields: [ ] }).generator : Jsc.array(Jsc.elements(keys)).generator.map(function (fields) {
            return {
              obj: obj,
              fields: fields
            };
          });
        })
      });

      check(narrowGen, function (input) {
        var narrowed = Objects.narrow(input.obj, input.fields);
        Obj.each(narrowed, function (_, k) {
          if (!Arr.contains(input.fields, k)) throw 'Narrowed object contained property: ' + k + ' which was not in fields: [' + input.fields.join(', ') + ']';
        });
        return true;
      });

      // Sanity test.
      var actual = Objects.narrow({ a: 'a', b: 'b', c: 'c' }, [ 'a', 'c', 'e' ]);
      assert.eq({ a: 'a', c: 'c' }, actual);
    };

    var testReaders = function () {
      // TODO: Think of a good way to property test.
      var subject = { alpha: 'Alpha' };

      assert.eq('Alpha', Objects.readOpt('alpha')(subject).getOrDie('readOpt(alpha) => some(Alpha)'), 'readOpt(alpha) => some(Alpha)');
      assert.eq(true, Objects.readOpt('beta')(subject).isNone(), 'readOpt(beta) => none');

      assert.eq('Alpha', Objects.readOr('alpha', 'fallback')(subject), 'readOr(alpha) => Alpha');
      assert.eq('fallback', Objects.readOr('beta', 'fallback')(subject), 'readOr(beta) => fallback');

      assert.eq('Alpha', Objects.readOptFrom(subject, 'alpha').getOrDie('readOptFrom(alpha) => some(Alpha)'), 'readOptFrom(alpha) => some(Alpha)');
      assert.eq(true, Objects.readOptFrom(subject, 'beta').isNone(), 'readOptFrom(beta) => none');
    };

    var testConsolidate = function () {
      var checkErr = function (label, expected, objs, base) {
        Objects.consolidate(objs, base).fold(function (err) {
          assert.eq(expected, err);
        }, function (val) {
          assert.fail(label + '\nExpected error(' + Json.stringify(expected) + '), but was: ' + Json.stringify(val));
        });
      };

      var checkVal = function (label, expected, objs, base) {
        Objects.consolidate(objs, base).fold(function (err) {
          assert.fail(label + '\nExpected value(' + Json.stringify(expected) + '), but was error(' + Json.stringify(err) + ')');
        }, function (val) {
          assert.eq(expected, val);
        });
      };

      checkVal(
        'empty objects',
        { },
        [ ], {}
      );

      checkErr(
        '[ failure ] ]',
        [ 'failure.1' ],
        [
          Result.error([ 'failure.1' ])
        ], {}
      );

      checkErr(
        '[ failure {1,2,3} ]',
        [ 'failure.1', 'failure.2', 'failure.3' ],
        [
          Result.error([ 'failure.1' ]),
          Result.error([ 'failure.2' ]),
          Result.error([ 'failure.3' ])
        ], {}
      );

      checkVal(
        '[ value.a ]',
        { a: 'A' },
        [
          Result.value({ a: 'A' })
        ], {}
      );

      checkVal(
        '[ value.{a,b,c} ]',
        { a: 'A' , b: 'B', c: 'C'},
        [
          Result.value({ a: 'A' }),
          Result.value({ b: 'B' }),
          Result.value({ c: 'C' })
        ], {}
      );

      checkErr(
        '[ value.a, failure.1, value.b ]',
        [ 'failure.1' ],
        [
          Result.value({ a: 'A' }),
          Result.error([ 'failure.1' ]),
          Result.value({ b: 'B' })
        ], {}
      );

      checkErr(
        '[ value.a, failure.1, value.b, failure.2, failure.3 ]',
        [ 'failure.1', 'failure.2', 'failure.3' ],
        [
          Result.value({ a: 'A' }),
          Result.error([ 'failure.1' ]),
          Result.value({ b: 'B' }),
          Result.error([ 'failure.2' ]),
          Result.error([ 'failure.3' ])
        ], {}
      );

      checkErr(
        '[ value.{a,b,c} ]',
        [ 'failure.last' ],
        [
          Result.value({ a: 'A' }),
          Result.value({ b: 'B' }),
          Result.value({ c: 'C' }),
          Result.error([ 'failure.last' ])
        ], {}
      );

      // some property-based tests
      var resultList = Jsc.bless({
        generator: Jsc.dict(smallSet).generator.flatMap(function (obj) {
          return Jsc.bool.generator.flatMap(function (flag) {
            return flag ? Jsc.constant(Result.value(obj)).generator : (function () {
              return Jsc.array(Jsc.nestring).generator.map(Result.error);
            })();
          });
        })
      });

      var inputList = Jsc.bless({
        generator: Jsc.array(resultList).generator.flatMap(function (results) {
          return Jsc.dict(smallSet).generator.map(function (base) {
            return {
              results: results,
              base: base
            };
          });
        })
      });

      check(inputList, function (input) {
        var actual = Objects.consolidate(input.results, input.base);

        var hasError = Arr.exists(input.results, function (res) {
          return res.isError();
        });

        if (hasError) assert.eq(true, actual.isError(), 'Error contained in list, so should be error overall');
        else assert.eq(true, actual.isValue(), 'No errors in list, so should be value overall');
      });
    };

    testNarrow();
    testReaders();
    testConsolidate();
  }
);<|endoftext|>


<commit_before>// Selects all of the checkboxes given the value of the check all box.
function selectall() {
    var id = "#id_selected";
    if ($(id).attr('checked'))
        setCheckedRows(true);
    else
        setCheckedRows(false);
}

// Given the row/column, this will return the value at that cell in the table.
function getValueFromCell(row, column)
{
    return $('#metadataFormTable')[0].rows[row+1].cells[column+1].childNodes[0].value;
}

// Given the row/column, this sets the value in that cell to what value is.
function setValueFromCell(row, column, value)
{
    $('#metadataFormTable')[0].rows[row+1].cells[column+1].childNodes[0].value = value;
}

// This returns an bool array that represents what checkboxes are checked.
function checkedRows() {
    var rows = $("#metadataFormTable tr").length;
    var checkedRows = new Array();
    for (var i = 0; i < rows; i++)
    {
        var id = "#id_form-" + i + "-selected";
        if ($(id).attr('checked') != null)
            checkedRows[i] = true;
        else
            checkedRows[i] = false;
    }
    return checkedRows;
}

// Takes a boolean value that sets all of the checkboxes to that value.
function setCheckedRows(checked) {
    var rows = $("#metadataFormTable tr").length;
    for (var i = 0; i < rows; i++)
    {
        var id = "#id_form-" + i + "-selected";
        $(id).attr("checked", checked);
    }
}

// This will handle updating all checked rows in the form. This is called whenever a user
// types in one of the text fields.
function updateCheckedRowFields(row, column) {
    var checked = checkedRows();
    if (checked[row] == false) return;
    var input = getValueFromCell(row, column);
    for (var i = 0; i < checked.length; i++)
    {
        if(checked[i] == true) setValueFromCell(i, column, input);
    }
}

// Update indicators that a value in the form has changed.
function updateMetadataChangeStatus(fieldId) {

    // Un-disable the Save Edits button
    $('#id_metadata_form_save_button').prop('disabled', false);

    // Update text next to the Save button
    $('#id_metadata_save_status').text("There are unsaved changes");

    // Add warning when trying to navigate away
    util.pageLeaveWarningEnable("You have unsaved changes.");

    // Style the changed field differently, so the user can keep track of
    // what's changed
    $(fieldId).addClass('changed').removeClass('error');
}

// This initializes the form with the correct bindings.
function setUpBindings(params) {
    var rows = $("#metadataFormTable tr").length;
    var columns = $("#metadataFormTable tr")[0].cells.length;
    var id;
    for (var i = 1; i < rows; i++)
    {
        // This row should correspond to an image.

        for (var j = 3; j < columns; j++)
        {
            // This column should correspond to an editable field.

            id = '#' + $('#metadataFormTable')[0].rows[i].cells[j].childNodes[0].getAttribute('id');

            if (j == 3)
            {
                // This is the date field.
                $(id).datepicker({ dateFormat: 'yy-mm-dd' });
                setRowColumnBindingsChange({id: id, isDate: true});
            }
            else
            {
                setRowColumnBindingsChange({id: id, isDate: false});
                setRowColumnBindingsKeyUp(id);
            }
        }
    }

    // When the top checkbox is checked/unchecked, check/uncheck
    // all the checkboxes
    id = "#id_selected";
    $(id).bind("change", function() {
        selectall();
    });

    // When the metadata save button is clicked...
    id = '#id_metadata_form_save_button';
    $(id).bind("click", submitMetadataForm.curry(params.metadataSaveAjaxUrl));

/*  For later use (ajax)
    id = "#id_view";
    $(id).bind("change", function() {
        ajax(ajax_url);
    });*/
}

// Given the id, this will set a key-up binding that calls
// updateCheckedRowFields with the given row and column of the table form.
function setRowColumnBindingsKeyUp(id) {
    $(id).bind("keyup", function() {
        var row_index = $(this).parent().parent().index('tr');
        var col_index = $(this).parent().index('tr:eq('+row_index+') td');
        updateCheckedRowFields(row_index-1, col_index-1);
    });
}

function setRowColumnBindingsChange(params) {
    if (params.isDate === true) {
        $(params.id).bind("change", function() {
            // Update indicators that a value in the form
            // has changed.
            updateMetadataChangeStatus(params.id);

            // Update checked rows.
            var row_index = $(this).parent().parent().index('tr');
            var col_index = $(this).parent().index('tr:eq('+row_index+') td');
            updateCheckedRowFields(row_index-1, col_index-1);
        });
    }
    else {
        $(params.id).bind("change", function() {
            // Update indicators that a value in the form
            // has changed.
            updateMetadataChangeStatus(params.id);
        });
    }
}

// Submit the metadata form (using Ajax).
function submitMetadataForm(metadataSaveAjaxUrl) {
    // Disable the save button
    $('#id_metadata_form_save_button').prop('disabled', true);

    // Remove any error messages from a previous edit attempt
    $('ul#id_metadata_errors_list').empty();

    // Update text next to the Save button
    $('#id_metadata_save_status').text("Now saving...");

    // Submit the metadata form with Ajax
    $.ajax({
        // Data to send in the request
        data: $('#id_metadata_form').serialize(),

        // Callback on successful response
        success: metadataSaveAjaxResponseHandler,

        type: 'POST',

        // URL to make request to
        url: metadataSaveAjaxUrl
    });
}

// This function runs when the metadata-save-via-Ajax returns from
// the server side.
function metadataSaveAjaxResponseHandler(response) {
    console.log(response.status);

    // Update text next to the Save button
    if (response.status === 'success') {
        $('#id_metadata_save_status').text("All changes saved");

        // Disable "You have unsaved changes" warning when trying to navigate away
        util.pageLeaveWarningDisable();

        // Remove field stylings
        $('#id_metadata_form input[type="text"]').removeClass('changed', 'error');
    }
    else {  // 'error'
        $('#id_metadata_save_status').text("There were error(s); couldn't save");

        var $errorsList = $('ul#id_metadata_errors_list');
        var numOfErrors = response.errors.length;

        for (var i = 0; i < numOfErrors; i++) {
            // Display the error message(s) next to the Save button
            $errorsList.append($('<li>').text(
                response.errors[i].errorMessage
            ));
            // Style the field to indicate an error
            $('#' + response.errors[i].fieldId).addClass('error').removeClass('changed');
        }
    }
}

/* For later use (ajax)
function ajax(url) {

    var checked = $("#id_view").attr('checked');
    $.ajax({
        type: "POST",
        url:url,
        data: {
            'checked': checked
        },
        success: function(data){
            $("#result").val(data.result);
        },
        error: function(request){
            console.log(request.responseText);
        }
    });
}
*/

function initMetadataForm(params) {
    // Initialize save status
    $('#id_metadata_save_status').text("All changes saved");
    $('#id_metadata_form_save_button').prop('disabled', true);

    // Set up event bindings
    setUpBindings(params);
}<commit_msg>Browse metadata form: When filling in fields via the multi-edit checkboxes, the fields filled by the multi-edit now get outlined in blue (indicating changes), as they should.<commit_after>// Selects all of the checkboxes given the value of the check all box.
function selectall() {
    var id = "#id_selected";
    if ($(id).attr('checked'))
        setCheckedRows(true);
    else
        setCheckedRows(false);
}

// Given the row/column, this will return the value at that cell in the table.
function getValueFromCell(row, column)
{
    return $('#metadataFormTable')[0].rows[row+1].cells[column+1].childNodes[0].value;
}

// Given the row/column, this sets the value in that cell to what value is.
function setValueFromCell(row, column, value)
{
    var field = $('#metadataFormTable')[0].rows[row+1].cells[column+1].childNodes[0];

    // Check if the old and new values are different; if so, mark the cell
    // as changed.
    if (field.value !== value) {
        updateMetadataChangeStatus($(field));
    }
    // Set the new value.
    field.value = value;
}

// This returns an bool array that represents what checkboxes are checked.
function checkedRows() {
    var rows = $("#metadataFormTable tr").length;
    var checkedRows = new Array();
    for (var i = 0; i < rows; i++)
    {
        var id = "#id_form-" + i + "-selected";
        if ($(id).attr('checked') != null)
            checkedRows[i] = true;
        else
            checkedRows[i] = false;
    }
    return checkedRows;
}

// Takes a boolean value that sets all of the checkboxes to that value.
function setCheckedRows(checked) {
    var rows = $("#metadataFormTable tr").length;
    for (var i = 0; i < rows; i++)
    {
        var id = "#id_form-" + i + "-selected";
        $(id).attr("checked", checked);
    }
}

// This will handle updating all checked rows in the form. This is called whenever a user
// types in one of the text fields.
function updateCheckedRowFields(row, column) {
    var checked = checkedRows();
    if (checked[row] == false) return;
    var input = getValueFromCell(row, column);
    for (var i = 0; i < checked.length; i++)
    {
        if(checked[i] == true) setValueFromCell(i, column, input);
    }
}

// Update indicators that a value in the form has changed.
function updateMetadataChangeStatus($field) {

    // Un-disable the Save Edits button
    $('#id_metadata_form_save_button').prop('disabled', false);

    // Update text next to the Save button
    $('#id_metadata_save_status').text("There are unsaved changes");

    // Add warning when trying to navigate away
    util.pageLeaveWarningEnable("You have unsaved changes.");

    // Style the changed field differently, so the user can keep track of
    // what's changed
    $field.addClass('changed').removeClass('error');
}

// This initializes the form with the correct bindings.
function setUpBindings(params) {
    var rows = $("#metadataFormTable tr").length;
    var columns = $("#metadataFormTable tr")[0].cells.length;
    var id;
    for (var i = 1; i < rows; i++)
    {
        // This row should correspond to an image.

        for (var j = 3; j < columns; j++)
        {
            // This column should correspond to an editable field.

            id = '#' + $('#metadataFormTable')[0].rows[i].cells[j].childNodes[0].getAttribute('id');

            if (j == 3)
            {
                // This is the date field.
                $(id).datepicker({ dateFormat: 'yy-mm-dd' });
                setRowColumnBindingsChange({id: id, isDate: true});
            }
            else
            {
                setRowColumnBindingsChange({id: id, isDate: false});
                setRowColumnBindingsKeyUp(id);
            }
        }
    }

    // When the top checkbox is checked/unchecked, check/uncheck
    // all the checkboxes
    id = "#id_selected";
    $(id).bind("change", function() {
        selectall();
    });

    // When the metadata save button is clicked...
    id = '#id_metadata_form_save_button';
    $(id).bind("click", submitMetadataForm.curry(params.metadataSaveAjaxUrl));

/*  For later use (ajax)
    id = "#id_view";
    $(id).bind("change", function() {
        ajax(ajax_url);
    });*/
}

// Given the id, this will set a key-up binding that calls
// updateCheckedRowFields with the given row and column of the table form.
function setRowColumnBindingsKeyUp(id) {
    $(id).bind("keyup", function() {
        var row_index = $(this).parent().parent().index('tr');
        var col_index = $(this).parent().index('tr:eq('+row_index+') td');
        updateCheckedRowFields(row_index-1, col_index-1);
    });
}

function setRowColumnBindingsChange(params) {
    var $field = $(params.id);

    if (params.isDate === true) {
        $field.bind("change", function() {
            // Update indicators that a value in the form
            // has changed.
            updateMetadataChangeStatus($(this));

            // Update checked rows.
            var row_index = $(this).parent().parent().index('tr');
            var col_index = $(this).parent().index('tr:eq('+row_index+') td');
            updateCheckedRowFields(row_index-1, col_index-1);
        });
    }
    else {
        $field.bind("change", function() {
            // Update indicators that a value in the form
            // has changed.
            updateMetadataChangeStatus($(this));
        });
    }
}

// Submit the metadata form (using Ajax).
function submitMetadataForm(metadataSaveAjaxUrl) {
    // Disable the save button
    $('#id_metadata_form_save_button').prop('disabled', true);

    // Remove any error messages from a previous edit attempt
    $('ul#id_metadata_errors_list').empty();

    // Update text next to the Save button
    $('#id_metadata_save_status').text("Now saving...");

    // Submit the metadata form with Ajax
    $.ajax({
        // Data to send in the request
        data: $('#id_metadata_form').serialize(),

        // Callback on successful response
        success: metadataSaveAjaxResponseHandler,

        type: 'POST',

        // URL to make request to
        url: metadataSaveAjaxUrl
    });
}

// This function runs when the metadata-save-via-Ajax returns from
// the server side.
function metadataSaveAjaxResponseHandler(response) {
    console.log(response.status);

    // Update text next to the Save button
    if (response.status === 'success') {
        $('#id_metadata_save_status').text("All changes saved");

        // Disable "You have unsaved changes" warning when trying to navigate away
        util.pageLeaveWarningDisable();

        // Remove field stylings
        $('#id_metadata_form input[type="text"]').removeClass('changed', 'error');
    }
    else {  // 'error'
        $('#id_metadata_save_status').text("There were error(s); couldn't save");

        var $errorsList = $('ul#id_metadata_errors_list');
        var numOfErrors = response.errors.length;

        for (var i = 0; i < numOfErrors; i++) {
            // Display the error message(s) next to the Save button
            $errorsList.append($('<li>').text(
                response.errors[i].errorMessage
            ));
            // Style the field to indicate an error
            $('#' + response.errors[i].fieldId).addClass('error').removeClass('changed');
        }
    }
}

/* For later use (ajax)
function ajax(url) {

    var checked = $("#id_view").attr('checked');
    $.ajax({
        type: "POST",
        url:url,
        data: {
            'checked': checked
        },
        success: function(data){
            $("#result").val(data.result);
        },
        error: function(request){
            console.log(request.responseText);
        }
    });
}
*/

function initMetadataForm(params) {
    // Initialize save status
    $('#id_metadata_save_status').text("All changes saved");
    $('#id_metadata_form_save_button').prop('disabled', true);

    // Set up event bindings
    setUpBindings(params);
}<|endoftext|>


<commit_before>import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
import modelList from '../../helpers/model-list';
import { initialize } from '../../../initializers/replace-promise';

initialize();
moduleForModel('curriculum-inventory-sequence-block', 'Unit | Model | CurriculumInventorySequenceBlock ', {
  needs: modelList
});

test('it exists', function(assert) {
  let model = this.subject();
  assert.ok(!!model);
});

test('get all ancestors of nested sequence block', function(assert) {
  assert.expect(3);
  let model = this.subject();
  let store = this.store();
  Ember.run(() => {
    let parentBlock = store.createRecord('curriculumInventorySequenceBlock', { 'children': [ model ] });
    let grandParent = store.createRecord('curriculumInventorySequenceBlock', { 'children': [ parentBlock ] });
    parentBlock.set('parent', grandParent);
    model.set('parent', parentBlock);
    model.get('allParents').then(ancestors => {
      assert.equal(ancestors.length, 2);
      assert.equal(ancestors[0], parentBlock);
      assert.equal(ancestors[1], grandParent);
    });
  });
});

test('list of ancestors is empty for top-level sequence block', function(assert) {
  assert.expect(1);
  let model = this.subject();
  Ember.run(() => {
    model.get('allParents').then(ancestors => {
      assert.equal(ancestors.length, 0);
    });
  });
});
<commit_msg>async/await for ci seq block test.<commit_after>import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
import modelList from '../../helpers/model-list';
import { initialize } from '../../../initializers/replace-promise';

const { run } = Ember;

initialize();
moduleForModel('curriculum-inventory-sequence-block', 'Unit | Model | CurriculumInventorySequenceBlock ', {
  needs: modelList
});

test('get all ancestors of nested sequence block', async function(assert) {
  assert.expect(3);
  const model = this.subject();
  const store = this.store();
  await run( async () => {
    const parentBlock = store.createRecord('curriculumInventorySequenceBlock', { 'children': [ model ] });
    let grandParent = store.createRecord('curriculumInventorySequenceBlock', { 'children': [ parentBlock ] });
    parentBlock.set('parent', grandParent);
    model.set('parent', parentBlock);
    const ancestors = await model.get('allParents');
    assert.equal(ancestors.length, 2);
    assert.equal(ancestors[0], parentBlock);
    assert.equal(ancestors[1], grandParent);
  });
});

test('list of ancestors is empty for top-level sequence block', async function(assert) {
  assert.expect(1);
  const model = this.subject();
  await run( async () => {
    const ancestors = await model.get('allParents');
    assert.equal(ancestors.length, 0);
  });
});
<|endoftext|>


<commit_before>'use strict';

// Configuring the Articles module
angular.module('articles').run(['Menus',
	function(Menus) {
		// Set top bar menu items
		Menus.addMenuItem('topbar', 'Articles', 'articles', 'dropdown', '/articles(/create)?');
		Menus.addSubMenuItem('topbar', 'articles', 'List Articles', 'articles');
		Menus.addSubMenuItem('topbar', 'articles', 'New Article', 'articles/create');
	}
]);<commit_msg>hide articles from menu, maybe use them later<commit_after>'use strict';

// Configuring the Articles module
angular.module('articles').run(['Menus',
	function(Menus) {
		// Set top bar menu items
		/*
		Menus.addMenuItem('topbar', 'Articles', 'articles', 'dropdown', '/articles(/create)?');
		Menus.addSubMenuItem('topbar', 'articles', 'List Articles', 'articles');
		Menus.addSubMenuItem('topbar', 'articles', 'New Article', 'articles/create');
		*/
	}
]);<|endoftext|>


<commit_before>function ProductsController(productService) {
  const vm = this;
  vm.products = [];
  vm.fetch = productService.fetch;
}

ProductsController.$inject = ['productService'];

export {ProductsController};
<commit_msg>see test pass and see regression fail with message: TypeError: Cannot read property 'fetch' of undefined<commit_after>function ProductsController(productService) {
  const vm = this;
  vm.products = [];
  vm.fetch = productService.fetch;

  vm.fetch().then((products) => {
    vm.products = products;
  });
}

ProductsController.$inject = ['productService'];

export {ProductsController};
<|endoftext|>