<commit_before>FBL.ns(function() { with (FBL) {
// ************************************************************************************************

// ************************************************************************************************
// Context

FBL.Context = function(win){
    this.window = win.window;
    this.document = win.document;

    // Some windows in IE, like iframe, doesn't have the eval() method
    if (isIE && !this.window.eval)
    {
        // But after executing the following line the method magically appears!
        this.window.execScript("null");
        // Just to make sure the "magic" really happened
        if (!this.window.eval)
            throw new Error("Firebug Error: eval() method not found in this window");
    }

    // Create a new "black-box" eval() method that runs in the global namespace
    // of the context window, without exposing the local variables declared
    // by the function that calls it
    this.eval = this.window.eval("new Function('" +
            "try{ return window.eval.apply(window,arguments) }catch(E){ E."+evalError+"=true; return E }" +
        "')");
};

FBL.Context.prototype =
{

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Evalutation Method

    /**
     * Evaluates an expression in the current context window.
     *
     * @param {String}   expr           expression to be evaluated
     *
     * @param {String}   context        string indicating the global location
     *                                  of the object that will be used as the
     *                                  context. The context is referred in
     *                                  the expression as the "this" keyword.
     *                                  If no context is informed, the "window"
     *                                  context is used.
     *
     * @param {String}   api            string indicating the global location
     *                                  of the object that will be used as the
     *                                  api of the evaluation.
     *
     * @param {Function} errorHandler(message) error handler to be called
     *                                         if the evaluation fails.
     */
    evaluate: function(expr, context, api, errorHandler)
    {
        context = context || "window";

        var cmd = api ?
            "(function(arguments){ with("+api+"){ return "+expr+" } }).call("+context+",undefined)" :
            "(function(arguments){ return "+expr+" }).call("+context+",undefined)" ;

        var r = this.eval(cmd);
        if (r && r[evalError])
        {
            cmd = api ?
                "(function(arguments){ with("+api+"){ "+expr+" } }).call("+context+",undefined)" :
                "(function(arguments){ "+expr+" }).call("+context+",undefined)" ;

            r = this.eval(cmd);
            if (r && r[evalError])
            {
                if (errorHandler)
                    r = errorHandler(r.message || r)
                else
                    r = r.message || r;
            }
        }

        return r;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Window Methods

    getWindowSize: function()
    {
        var width=0, height=0, el;

        if (typeof this.window.innerWidth == "number")
        {
            width = this.window.innerWidth;
            height = this.window.innerHeight;
        }
        else if ((el=this.document.documentElement) && (el.clientHeight || el.clientWidth))
        {
            width = el.clientWidth;
            height = el.clientHeight;
        }
        else if ((el=this.document.body) && (el.clientHeight || el.clientWidth))
        {
            width = el.clientWidth;
            height = el.clientHeight;
        }

        return {width: width, height: height};
    },

    getWindowScrollSize: function()
    {
        var width=0, height=0, el;

        if (!isIEQuiksMode && (el=this.document.documentElement) &&
           (el.scrollHeight || el.scrollWidth))
        {
            width = el.scrollWidth;
            height = el.scrollHeight;
        }
        else if ((el=this.document.body) && (el.scrollHeight || el.scrollWidth))
        {
            width = el.scrollWidth;
            height = el.scrollHeight;
        }

        return {width: width, height: height};
    },

    getWindowScrollPosition: function()
    {
        var top=0, left=0, el;

        if(typeof this.window.pageYOffset == "number")
        {
            top = this.window.pageYOffset;
            left = this.window.pageXOffset;
        }
        else if((el=this.document.body) && (el.scrollTop || el.scrollLeft))
        {
            top = el.scrollTop;
            left = el.scrollLeft;
        }
        else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft))
        {
            top = el.scrollTop;
            left = el.scrollLeft;
        }

        return {top:top, left:left};
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Element Methods

    getElementFromPoint: function(x, y)
    {
        if (isOpera || isSafari)
        {
            var scroll = this.getWindowScrollPosition();
            return this.document.elementFromPoint(x + scroll.left, y + scroll.top);
        }
        else
            return this.document.elementFromPoint(x, y);
    },

    getElementPosition: function(el)
    {
        var left = 0
        var top = 0;

        do
        {
            left += el.offsetLeft;
            top += el.offsetTop;
        }
        while (el = el.offsetParent);

        return {left:left, top:top};
    },

    getElementBox: function(el)
    {
        var result = {};

        if (el.getBoundingClientRect)
        {
            var rect = el.getBoundingClientRect();

            // fix IE problem with offset when not in fullscreen mode
            var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0;

            var scroll = this.getWindowScrollPosition();

            result.top = Math.round(rect.top - offset + scroll.top);
            result.left = Math.round(rect.left - offset + scroll.left);
            result.height = Math.round(rect.bottom - rect.top);
            result.width = Math.round(rect.right - rect.left);
        }
        else
        {
            var position = this.getElementPosition(el);

            result.top = position.top;
            result.left = position.left;
            result.height = el.offsetHeight;
            result.width = el.offsetWidth;
        }

        return result;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Measurement Methods

    getMeasurement: function(el, name)
    {
        var result = {value: 0, unit: "px"};

        var cssValue = this.getCSS(el, name);

        if (!cssValue) return result;
        if (cssValue.toLowerCase() == "auto") return result;

        var reMeasure = /(\d+\.?\d*)(.*)/;
        var m = cssValue.match(reMeasure);

        if (m)
        {
            result.value = m[1]-0;
            result.unit = m[2].toLowerCase();
        }

        return result;
    },

    getMeasurementInPixels: function(el, name)
    {
        if (!el) return null;

        var m = this.getMeasurement(el, name);
        var value = m.value;
        var unit = m.unit;

        if (unit == "px")
            return value;

        else if (unit == "pt")
            return this.pointsToPixels(name, value);

        if (unit == "em")
            return this.emToPixels(el, value);

        else if (unit == "%")
            return this.percentToPixels(el, value);
    },

    getMeasurementBox: function(el, name)
    {
        var sufixes = ["Top", "Left", "Bottom", "Right"];
        var result = [];

        for(var i=0, sufix; sufix=sufixes[i]; i++)
            result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix));

        return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
    },

    getFontSizeInPixels: function(el)
    {
        var size = this.getMeasurement(el, "fontSize");

        if (size.unit == "px") return size.value;

        // get font size, the dirty way
        var computeDirtyFontSize = function(el, calibration)
        {
            var div = this.document.createElement("div");
            var divStyle = offscreenStyle;

            if (calibration)
                divStyle +=  " font-size:"+calibration+"px;";

            div.style.cssText = divStyle;
            div.innerHTML = "A";
            el.appendChild(div);

            var value = div.offsetHeight;
            el.removeChild(div);
            return value;
        }

        // Calibration fails in some environments, so we're using a static value
        // based in the test case result.
        var rate = 200 / 225;
        //var calibrationBase = 200;
        //var calibrationValue = computeDirtyFontSize(el, calibrationBase);
        //var rate = calibrationBase / calibrationValue;

        var value = computeDirtyFontSize(el);

        return value * rate;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Unit Funtions

    pointsToPixels: function(name, value, returnFloat)
    {
        var axis = /Top$|Bottom$/.test(name) ? "y" : "x";

        var result = value * pixelsPerInch[axis] / 72;

        return returnFloat ? result : Math.round(result);
    },

    emToPixels: function(el, value)
    {
        if (!el) return null;

        var fontSize = this.getFontSizeInPixels(el);

        return Math.round(value * fontSize);
    },

    exToPixels: function(el, value)
    {
        if (!el) return null;

        // get ex value, the dirty way
        var div = this.document.createElement("div");
        div.style.cssText = offscreenStyle + "width:"+value + "ex;";

        el.appendChild(div);
        var value = div.offsetWidth;
        el.removeChild(div);

        return value;
    },

    percentToPixels: function(el, value)
    {
        if (!el) return null;

        // get % value, the dirty way
        var div = this.document.createElement("div");
        div.style.cssText = offscreenStyle + "width:"+value + "%;";

        el.appendChild(div);
        var value = div.offsetWidth;
        el.removeChild(div);

        return value;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    getCSS: isIE ? function(el, name)
    {
        return el.currentStyle[name] || el.style[name] || undefined;
    }
    : function(el, name)
    {
        return this.document.defaultView.getComputedStyle(el,null)[name]
            || el.style[name] || undefined;
    }

};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Internal variables

var evalError = "___firebug_evaluation_error___";
var pixelsPerInch;

var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";

// ************************************************************************************************
// Measurement Functions

var calculatePixelsPerInch = function calculatePixelsPerInch()
{
    var inch = this.document.createElement("div");
    inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;";
    this.document.body.appendChild(inch);

    pixelsPerInch = {
        x: inch.offsetWidth,
        y: inch.offsetHeight
    };

    this.document.body.removeChild(inch);
};

// ************************************************************************************************
}});<commit_msg>Restored an old feature used in the prototype, a hack to discover the auto margin values in pixels in IE, and removing calculatePixelsPerInch that is now part of the lib.js.<commit_after>FBL.ns(function() { with (FBL) {
// ************************************************************************************************

// ************************************************************************************************
// Context

FBL.Context = function(win){
    this.window = win.window;
    this.document = win.document;

    // Some windows in IE, like iframe, doesn't have the eval() method
    if (isIE && !this.window.eval)
    {
        // But after executing the following line the method magically appears!
        this.window.execScript("null");
        // Just to make sure the "magic" really happened
        if (!this.window.eval)
            throw new Error("Firebug Error: eval() method not found in this window");
    }

    // Create a new "black-box" eval() method that runs in the global namespace
    // of the context window, without exposing the local variables declared
    // by the function that calls it
    this.eval = this.window.eval("new Function('" +
            "try{ return window.eval.apply(window,arguments) }catch(E){ E."+evalError+"=true; return E }" +
        "')");
};

FBL.Context.prototype =
{

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Evalutation Method

    /**
     * Evaluates an expression in the current context window.
     *
     * @param {String}   expr           expression to be evaluated
     *
     * @param {String}   context        string indicating the global location
     *                                  of the object that will be used as the
     *                                  context. The context is referred in
     *                                  the expression as the "this" keyword.
     *                                  If no context is informed, the "window"
     *                                  context is used.
     *
     * @param {String}   api            string indicating the global location
     *                                  of the object that will be used as the
     *                                  api of the evaluation.
     *
     * @param {Function} errorHandler(message) error handler to be called
     *                                         if the evaluation fails.
     */
    evaluate: function(expr, context, api, errorHandler)
    {
        context = context || "window";

        var cmd = api ?
            "(function(arguments){ with("+api+"){ return "+expr+" } }).call("+context+",undefined)" :
            "(function(arguments){ return "+expr+" }).call("+context+",undefined)" ;

        var r = this.eval(cmd);
        if (r && r[evalError])
        {
            cmd = api ?
                "(function(arguments){ with("+api+"){ "+expr+" } }).call("+context+",undefined)" :
                "(function(arguments){ "+expr+" }).call("+context+",undefined)" ;

            r = this.eval(cmd);
            if (r && r[evalError])
            {
                if (errorHandler)
                    r = errorHandler(r.message || r)
                else
                    r = r.message || r;
            }
        }

        return r;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Window Methods

    getWindowSize: function()
    {
        var width=0, height=0, el;

        if (typeof this.window.innerWidth == "number")
        {
            width = this.window.innerWidth;
            height = this.window.innerHeight;
        }
        else if ((el=this.document.documentElement) && (el.clientHeight || el.clientWidth))
        {
            width = el.clientWidth;
            height = el.clientHeight;
        }
        else if ((el=this.document.body) && (el.clientHeight || el.clientWidth))
        {
            width = el.clientWidth;
            height = el.clientHeight;
        }

        return {width: width, height: height};
    },

    getWindowScrollSize: function()
    {
        var width=0, height=0, el;

        if (!isIEQuiksMode && (el=this.document.documentElement) &&
           (el.scrollHeight || el.scrollWidth))
        {
            width = el.scrollWidth;
            height = el.scrollHeight;
        }
        else if ((el=this.document.body) && (el.scrollHeight || el.scrollWidth))
        {
            width = el.scrollWidth;
            height = el.scrollHeight;
        }

        return {width: width, height: height};
    },

    getWindowScrollPosition: function()
    {
        var top=0, left=0, el;

        if(typeof this.window.pageYOffset == "number")
        {
            top = this.window.pageYOffset;
            left = this.window.pageXOffset;
        }
        else if((el=this.document.body) && (el.scrollTop || el.scrollLeft))
        {
            top = el.scrollTop;
            left = el.scrollLeft;
        }
        else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft))
        {
            top = el.scrollTop;
            left = el.scrollLeft;
        }

        return {top:top, left:left};
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Element Methods

    getElementFromPoint: function(x, y)
    {
        if (isOpera || isSafari)
        {
            var scroll = this.getWindowScrollPosition();
            return this.document.elementFromPoint(x + scroll.left, y + scroll.top);
        }
        else
            return this.document.elementFromPoint(x, y);
    },

    getElementPosition: function(el)
    {
        var left = 0
        var top = 0;

        do
        {
            left += el.offsetLeft;
            top += el.offsetTop;
        }
        while (el = el.offsetParent);

        return {left:left, top:top};
    },

    getElementBox: function(el)
    {
        var result = {};

        if (el.getBoundingClientRect)
        {
            var rect = el.getBoundingClientRect();

            // fix IE problem with offset when not in fullscreen mode
            var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0;

            var scroll = this.getWindowScrollPosition();

            result.top = Math.round(rect.top - offset + scroll.top);
            result.left = Math.round(rect.left - offset + scroll.left);
            result.height = Math.round(rect.bottom - rect.top);
            result.width = Math.round(rect.right - rect.left);
        }
        else
        {
            var position = this.getElementPosition(el);

            result.top = position.top;
            result.left = position.left;
            result.height = el.offsetHeight;
            result.width = el.offsetWidth;
        }

        return result;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Measurement Methods

    getMeasurement: function(el, name)
    {
        var result = {value: 0, unit: "px"};

        var cssValue = this.getCSS(el, name);

        if (!cssValue) return result;
        if (cssValue.toLowerCase() == "auto") return result;

        var reMeasure = /(\d+\.?\d*)(.*)/;
        var m = cssValue.match(reMeasure);

        if (m)
        {
            result.value = m[1]-0;
            result.unit = m[2].toLowerCase();
        }

        return result;
    },

    getMeasurementInPixels: function(el, name)
    {
        if (!el) return null;

        var m = this.getMeasurement(el, name);
        var value = m.value;
        var unit = m.unit;

        if (unit == "px")
            return value;

        else if (unit == "pt")
            return this.pointsToPixels(name, value);

        if (unit == "em")
            return this.emToPixels(el, value);

        else if (unit == "%")
            return this.percentToPixels(el, value);
    },

    getMeasurementBox1: function(el, name)
    {
        var sufixes = ["Top", "Left", "Bottom", "Right"];
        var result = [];

        for(var i=0, sufix; sufix=sufixes[i]; i++)
            result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix));

        return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
    },

    getMeasurementBox: function(el, name)
    {
        var sufixes = ["Top", "Left", "Bottom", "Right"];
        var result = [];

        if (document.all)
        {
            var propName, cssValue;
            var autoMargin = null;

            for(var i=0, sufix; sufix=sufixes[i]; i++)
            {
                propName = name + sufix;

                cssValue = el.currentStyle[propName] || el.style[propName];

                if (cssValue == "auto")
                {
                    autoMargin = autoMargin || this.getCSSAutoMarginBox(el);
                    result[i] = autoMargin[sufix.toLowerCase()];
                }
                else
                    result[i] = this.getMeasurementInPixels(el, propName);

            }

        }
        else
        {
            for(var i=0, sufix; sufix=sufixes[i]; i++)
                result[i] = this.getMeasurementInPixels(el, name + sufix);
        }

        return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
    },

    getCSSAutoMarginBox: function(el)
    {
        if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1)
            return {top:0, left:0, bottom:0, right:0};

        var box = document.createElement("div");
        box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;";

        var clone = el.cloneNode(false);
        var text = document.createTextNode(" ");
        clone.appendChild(text);

        box.appendChild(clone);

        document.body.appendChild(box);

        var marginTop = clone.offsetTop - box.offsetTop - 1;
        var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop;

        var marginLeft = clone.offsetLeft - box.offsetLeft - 1;
        var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft;

        document.body.removeChild(box);

        return {top:marginTop, left:marginLeft, bottom:marginBottom, right:marginRight};
    },

    getFontSizeInPixels: function(el)
    {
        var size = this.getMeasurement(el, "fontSize");

        if (size.unit == "px") return size.value;

        // get font size, the dirty way
        var computeDirtyFontSize = function(el, calibration)
        {
            var div = this.document.createElement("div");
            var divStyle = offscreenStyle;

            if (calibration)
                divStyle +=  " font-size:"+calibration+"px;";

            div.style.cssText = divStyle;
            div.innerHTML = "A";
            el.appendChild(div);

            var value = div.offsetHeight;
            el.removeChild(div);
            return value;
        }

        // Calibration fails in some environments, so we're using a static value
        // based in the test case result.
        var rate = 200 / 225;
        //var calibrationBase = 200;
        //var calibrationValue = computeDirtyFontSize(el, calibrationBase);
        //var rate = calibrationBase / calibrationValue;

        var value = computeDirtyFontSize(el);

        return value * rate;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Unit Funtions

    pointsToPixels: function(name, value, returnFloat)
    {
        var axis = /Top$|Bottom$/.test(name) ? "y" : "x";

        var result = value * pixelsPerInch[axis] / 72;

        return returnFloat ? result : Math.round(result);
    },

    emToPixels: function(el, value)
    {
        if (!el) return null;

        var fontSize = this.getFontSizeInPixels(el);

        return Math.round(value * fontSize);
    },

    exToPixels: function(el, value)
    {
        if (!el) return null;

        // get ex value, the dirty way
        var div = this.document.createElement("div");
        div.style.cssText = offscreenStyle + "width:"+value + "ex;";

        el.appendChild(div);
        var value = div.offsetWidth;
        el.removeChild(div);

        return value;
    },

    percentToPixels: function(el, value)
    {
        if (!el) return null;

        // get % value, the dirty way
        var div = this.document.createElement("div");
        div.style.cssText = offscreenStyle + "width:"+value + "%;";

        el.appendChild(div);
        var value = div.offsetWidth;
        el.removeChild(div);

        return value;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    getCSS: isIE ? function(el, name)
    {
        return el.currentStyle[name] || el.style[name] || undefined;
    }
    : function(el, name)
    {
        return this.document.defaultView.getComputedStyle(el,null)[name]
            || el.style[name] || undefined;
    }

};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Internal variables

var evalError = "___firebug_evaluation_error___";
var pixelsPerInch;

var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";

// ************************************************************************************************
}});<|endoftext|>


<commit_before>'use strict';

(function() {

	var MODULE = angular.module('osgi.enroute.trains', [ 'ngRoute',
			'ngResource', 'enJsonrpc', 'enEasse', 'enMarkdown' ]);

	var resolveBefore;
	var alerts = [];
	var trains = {
		events : [],
		segments : {},
		locations: {},
		passengers: {},
		rfids: {},
		ep : null,
		destinations : []
	};
	var stations = {
		events : [],
		passengers: {}
	}

	function error(msg) {
		alerts.push({
			msg : msg,
			type : 'danger'
		});
	}

	MODULE.config(function($routeProvider, en$jsonrpcProvider) {
		en$jsonrpcProvider.setNotification({
			error : error
		})
		resolveBefore = {
			trainsEndpoint : en$jsonrpcProvider.endpoint("trains")
		};

		$routeProvider.when('/', {
			controller : mainProvider,
			templateUrl : '/osgi.enroute.trains/main/htm/home.htm',
			resolve : resolveBefore
		});
		$routeProvider.when('/about', {
			templateUrl : '/osgi.enroute.trains/main/htm/about.htm',
			resolve : resolveBefore
		});
		$routeProvider.otherwise('/');

	});

	MODULE.run(function($rootScope, $location, en$easse, en$jsonrpc) {
		var track = {};

		$rootScope.alerts = alerts;
		$rootScope.trains = trains;
		$rootScope.track = track;
		$rootScope.stations = stations;

		en$easse.handle("osgi/trains/observation", function(e) {
			$rootScope.$applyAsync(function() {
				trains.events.push(e);
				if ( trains.events.length > 10)
					trains.events.splice(0,1);

				if ( e.train  ) {
					var set = trains.rfids[ e.train ] || {};
					set.train = e.train;
					set.segment= e.segment;
					set.speed=  e.speed;
					trains.rfids[ e.train ] = set;
				}

				switch(e.type) {
				case "LOCATED":
					trains.locations[e.train]=e.segment;
					break;

				case "SWITCH": {
						var s = track[ e.segment ];
						if ( angular.isDefined(s) )
							s.alt = e.alternate;
					}
					break;

				case "SIGNAL": {
						var s = track[ e.segment ];
						if ( angular.isDefined(s) )
							s.color = e.signal;
					}
				case "ASSIGNMENT": {
						if ( trains.rfids[ e.train ] )
							trains.rfids[ e.train  ].assignment = e.assignment;
					}
					break;

				}
			});
		}, function(e) {
			alerts.push({
				type : 'error',
				msg : e
			});
		});

		en$easse.handle("osgi/trains/station", function(e) {
			$rootScope.$applyAsync(function() {
				switch(e.type) {
				case "CHECK_IN":
					trains.ep.getPerson(e.personId).then( function(person) {
						e.message = person.firstName+" "+person.lastName+" checked in at "+e.station;
						e.profilepic = person.picture ? person.picture : "img/user.jpg";
						e.website = person.website;
						stations.events.push(e);
						if ( stations.events.length > 13)
							stations.events.splice(0,1);
					});
					break;
				case "CHECK_OUT":
					trains.ep.getPerson(e.personId).then( function(person) {
						e.message = person.firstName+" "+person.lastName+" checked out at "+e.station;
						e.profilepic = person.picture ? person.picture : "img/user.jpg";
						e.website = person.website;
						stations.events.push(e);
						if ( stations.events.length > 13)
							stations.events.splice(0,1);
					});
					break;
				case "ARRIVAL":
				case "DEPARTURE":
					trains.ep.getTrains().then( function(t) {
						t.forEach( function(d) {
							trains.ep.getPassengersOnTrain(d).then( function(p) {
								trains.passengers[d] = p;
							});
						});
					});
					break;
				default:
					break;
				}

				trains.ep.getPassengersInStation(e.station).then( function(p) {
					stations.passengers[e.station] = p;
				});

			});
		}, function(e) {
			alerts.push({
				type : 'error',
				msg : e
			});
		});

		resolveBefore.trainsEndpoint().then(function(ep) {
			trains.ep = ep;
			trains.ep.getPositions().then( function(pos) {
				angular.copy(pos, track);
			});

			trains.ep.getStations().then( function(s) {
				s.forEach( function(station) {
					trains.destinations.push(station);

					trains.ep.getPassengersInStation(station.name).then( function(p) {
						stations.passengers[station.name] = p;
					});
				});
			});

			trains.ep.getTrains().then( function(t) {
				t.forEach( function(d) {
					trains.rfids[d] = { train: d };

					trains.ep.getPassengersOnTrain(d).then( function(p) {
						trains.passengers[d] = p;
					});
				});
			});
		});

		$rootScope.closeAlert = function(index) {
			alerts.splice(index, 1);
		};
		$rootScope.page = function() {
			return $location.path();
		}

		$rootScope.getPassengersOnTrain = function(train){
			return trains.passengers[train];
		}
	});

	var mainProvider = function($scope) {
		$scope.assign = trains.ep.assign;
		$scope.rfid= function(segment,train) {
			console.log(segment + " " + train);
			trains.ep.setPosition( train, segment);

		}
	}

})();
<commit_msg>only update segment info if segment is set<commit_after>'use strict';

(function() {

	var MODULE = angular.module('osgi.enroute.trains', [ 'ngRoute',
			'ngResource', 'enJsonrpc', 'enEasse', 'enMarkdown' ]);

	var resolveBefore;
	var alerts = [];
	var trains = {
		events : [],
		segments : {},
		locations: {},
		passengers: {},
		rfids: {},
		ep : null,
		destinations : []
	};
	var stations = {
		events : [],
		passengers: {}
	}

	function error(msg) {
		alerts.push({
			msg : msg,
			type : 'danger'
		});
	}

	MODULE.config(function($routeProvider, en$jsonrpcProvider) {
		en$jsonrpcProvider.setNotification({
			error : error
		})
		resolveBefore = {
			trainsEndpoint : en$jsonrpcProvider.endpoint("trains")
		};

		$routeProvider.when('/', {
			controller : mainProvider,
			templateUrl : '/osgi.enroute.trains/main/htm/home.htm',
			resolve : resolveBefore
		});
		$routeProvider.when('/about', {
			templateUrl : '/osgi.enroute.trains/main/htm/about.htm',
			resolve : resolveBefore
		});
		$routeProvider.otherwise('/');

	});

	MODULE.run(function($rootScope, $location, en$easse, en$jsonrpc) {
		var track = {};

		$rootScope.alerts = alerts;
		$rootScope.trains = trains;
		$rootScope.track = track;
		$rootScope.stations = stations;

		en$easse.handle("osgi/trains/observation", function(e) {
			$rootScope.$applyAsync(function() {
				trains.events.push(e);
				if ( trains.events.length > 10)
					trains.events.splice(0,1);

				if ( e.train && e.segment  ) {
					var set = trains.rfids[ e.train ] || {};
					set.train = e.train;
					set.segment= e.segment;
					set.speed=  e.speed;
					trains.rfids[ e.train ] = set;
				}

				switch(e.type) {
				case "LOCATED":
					trains.locations[e.train]=e.segment;
					break;

				case "SWITCH": {
						var s = track[ e.segment ];
						if ( angular.isDefined(s) )
							s.alt = e.alternate;
					}
					break;

				case "SIGNAL": {
						var s = track[ e.segment ];
						if ( angular.isDefined(s) )
							s.color = e.signal;
					}
				case "ASSIGNMENT": {
						if ( trains.rfids[ e.train ] )
							trains.rfids[ e.train  ].assignment = e.assignment;
					}
					break;

				}
			});
		}, function(e) {
			alerts.push({
				type : 'error',
				msg : e
			});
		});

		en$easse.handle("osgi/trains/station", function(e) {
			$rootScope.$applyAsync(function() {
				switch(e.type) {
				case "CHECK_IN":
					trains.ep.getPerson(e.personId).then( function(person) {
						e.message = person.firstName+" "+person.lastName+" checked in at "+e.station;
						e.profilepic = person.picture ? person.picture : "img/user.jpg";
						e.website = person.website;
						stations.events.push(e);
						if ( stations.events.length > 13)
							stations.events.splice(0,1);
					});
					break;
				case "CHECK_OUT":
					trains.ep.getPerson(e.personId).then( function(person) {
						e.message = person.firstName+" "+person.lastName+" checked out at "+e.station;
						e.profilepic = person.picture ? person.picture : "img/user.jpg";
						e.website = person.website;
						stations.events.push(e);
						if ( stations.events.length > 13)
							stations.events.splice(0,1);
					});
					break;
				case "ARRIVAL":
				case "DEPARTURE":
					trains.ep.getTrains().then( function(t) {
						t.forEach( function(d) {
							trains.ep.getPassengersOnTrain(d).then( function(p) {
								trains.passengers[d] = p;
							});
						});
					});
					break;
				default:
					break;
				}

				trains.ep.getPassengersInStation(e.station).then( function(p) {
					stations.passengers[e.station] = p;
				});

			});
		}, function(e) {
			alerts.push({
				type : 'error',
				msg : e
			});
		});

		resolveBefore.trainsEndpoint().then(function(ep) {
			trains.ep = ep;
			trains.ep.getPositions().then( function(pos) {
				angular.copy(pos, track);
			});

			trains.ep.getStations().then( function(s) {
				s.forEach( function(station) {
					trains.destinations.push(station);

					trains.ep.getPassengersInStation(station.name).then( function(p) {
						stations.passengers[station.name] = p;
					});
				});
			});

			trains.ep.getTrains().then( function(t) {
				t.forEach( function(d) {
					trains.rfids[d] = { train: d };

					trains.ep.getPassengersOnTrain(d).then( function(p) {
						trains.passengers[d] = p;
					});
				});
			});
		});

		$rootScope.closeAlert = function(index) {
			alerts.splice(index, 1);
		};
		$rootScope.page = function() {
			return $location.path();
		}

		$rootScope.getPassengersOnTrain = function(train){
			return trains.passengers[train];
		}
	});

	var mainProvider = function($scope) {
		$scope.assign = trains.ep.assign;
		$scope.rfid= function(segment,train) {
			console.log(segment + " " + train);
			trains.ep.setPosition( train, segment);

		}
	}

})();
<|endoftext|>


<commit_before>define([
    'jquery',
    'knockout',
    'underscore',
    'turf',
    'geohash',
    'views/base-manager',
    'models/node',
    'viewmodels/alert',
    'views/components/widgets/map/bin-feature-collection',
    'map-layer-manager-data',
    'arches',
    'bindings/mapbox-gl',
    'bindings/codemirror',
    'codemirror/mode/javascript/javascript',
    'datatype-config-components'
], function($, ko, _, turf, geohash, BaseManagerView, NodeModel, AlertViewModel, binFeatureCollection, data, arches) {
    var vm = {
        map: null,
        geomNodes: [],
        loading: ko.observable(false),
        minZoom: ko.observable(arches.mapDefaultMinZoom),
        maxZoom: ko.observable(arches.mapDefaultMaxZoom),
        pitch: ko.observable(0),
        bearing: ko.observable(0),
        iconFilter: ko.observable(''),
        selectedList: ko.observable()
    };

    vm.icons = ko.computed(function() {
        return _.filter(data.icons, function(icon) {
            return icon.name.indexOf(vm.iconFilter()) >= 0;
        });
    });
    var mapLayers = ko.observableArray($.extend(true, [], arches.mapLayers));
    _.each(mapLayers(), function(layer) {
        layer._layer = ko.observable(JSON.stringify(layer));
        layer.layerJSON = ko.observable(JSON.stringify(layer.layer_definitions, null, '\t'));
        layer.activated = ko.observable(layer.activated);
        layer.addtomap = ko.observable(layer.addtomap);
        layer.name = ko.observable(layer.name);
        layer.icon = ko.observable(layer.icon);
        layer.legend = ko.observable(layer.legend);
        layer.centerX = ko.observable(layer.centerx);
        layer.centerY = ko.observable(layer.centery);
        layer.zoom = ko.observable(layer.zoom);
        layer.toJSON = ko.computed(function() {
            var layers;
            try {
                layers = JSON.parse(layer.layerJSON());
            }
            catch (e) {
                layers = [];
            }
            return JSON.stringify({
                "maplayerid": layer.maplayerid,
                "name": layer.name(),
                "layer_definitions": layers,
                "isoverlay": layer.isoverlay,
                "icon": layer.icon(),
                "legend": layer.legend(),
                "activated": layer.activated(),
                "addtomap": layer.addtomap(),
                "is_resource_layer": false,
                "centerx": layer.centerX(),
                "centery": layer.centerY(),
                "zoom": layer.zoom()
            });
        });
        layer.dirty = ko.computed(function() {
            return layer.toJSON() !== layer._layer();
        });
        layer.save = function() {
            vm.loading(true);
            $.ajax({
                type: "POST",
                url: window.location.pathname + '/' + layer.maplayerid,
                data: layer.toJSON(),
                success: function(response) {
                    layer._layer(layer.toJSON());
                    pageView.viewModel.loading(false);
                    var mapLayer = _.find(arches.mapLayers, function(mapLayer) {
                        return mapLayer.maplayerid === layer.maplayerid;
                    });
                    _.extend(mapLayer, JSON.parse(layer._layer()));
                    if (!mapLayer.isoverlay && mapLayer.addtomap) {
                        _.each(vm.basemaps(), function(basemap) {
                            if (basemap.maplayerid !== layer.maplayerid) {
                                basemap.addtomap(false);
                            }
                        });
                        _.each(arches.mapLayers, function(mapLayer) {
                            if (!mapLayer.isoverlay && mapLayer.maplayerid !== layer.maplayerid) {
                                mapLayer.addtomap = false;
                            }
                        });
                    }
                },
                error: function(response) {
                    pageView.viewModel.loading(false);
                }
            });
        };
        layer.reset = function() {
            var _layer = JSON.parse(layer._layer());
            layer.layerJSON(JSON.stringify(_layer.layer_definitions, null, '\t'));
            layer.activated(_layer.activated);
            layer.addtomap(_layer.addtomap),
            layer.name(_layer.name);
            layer.icon(_layer.icon);
            layer.centerX(_layer.centerx);
            layer.centerY(_layer.centery);
            layer.zoom(_layer.zoom);
            layer.legend(_layer.legend);
        };
        layer.delete = function() {
            pageView.viewModel.alert(new AlertViewModel('ep-alert-red', arches.confirmMaplayerDelete.title, arches.confirmMaplayerDelete.text, function() {
                return;
            }, function(){
                vm.loading(true);
                $.ajax({
                    type: "DELETE",
                    url: window.location.pathname + '/' + layer.maplayerid,
                    success: function(response) {
                        mapLayers.remove(layer);
                        arches.mapLayers = _.without(arches.mapLayers, _.findWhere(arches.mapLayers, {
                            maplayerid: layer.maplayerid
                        }));
                        var selection = null;
                        var layerList = ko.unwrap(vm.selectedList());
                        if (layerList && layerList.length > 0) {
                            selection = layerList[0];
                        }
                        vm.selection(selection);
                        pageView.viewModel.loading(false);
                    },
                    error: function(response) {
                        pageView.viewModel.loading(false);
                    }
                });
            }));
        };
    });

    vm.selectedBasemapName = ko.observable('');
    vm.basemaps = ko.computed(function() {
        return _.filter(mapLayers(), function(layer) {
            return !layer.isoverlay;
        });
    });
    vm.basemaps().forEach(function(basemap) {
        basemap.select = function() {
            vm.selectedBasemapName(basemap.name());
        };
    });
    var defaultBasemap = _.find(vm.basemaps(), function(basemap) {
        return basemap.addtomap();
    });
    if (!defaultBasemap) {
        defaultBasemap = vm.basemaps()[0];
    }
    if (defaultBasemap) {
        vm.selectedBasemapName(defaultBasemap.name());
    }
    vm.overlays = ko.computed(function() {
        return _.filter(mapLayers(), function(layer) {
            return layer.isoverlay && !layer.is_resource_layer;
        });
    });

    var getBasemapLayers = function() {
        return _.filter(vm.basemaps(), function(layer) {
            return layer.name() === vm.selectedBasemapName();
        }).reduce(function(layers, layer) {
            return layers.concat(layer.layer_definitions);
        }, []);
    };
    var sources = $.extend(true, {}, arches.mapSources);

    sources["search-results-hex"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };
    sources["search-results-points"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };
    sources["search-results-hashes"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };

    _.each(sources, function(sourceConfig, name) {
        if (sourceConfig.tiles) {
            sourceConfig.tiles.forEach(function(url, i) {
                if (url.startsWith('/')) {
                    sourceConfig.tiles[i] = window.location.origin + url;
                }
            });
        }
    });

    var datatypelookup = {};
    _.each(data.datatypes, function(datatype){
        datatypelookup[datatype.datatype] = datatype;
    }, this);

    _.each(data.geom_nodes, function(node) {
        vm.geomNodes.push(
            new NodeModel({
                url: arches.urls.node_layer,
                loading: vm.loading,
                permissions: data.node_permissions[node.nodeid],
                source: node,
                datatypelookup: datatypelookup,
                icons: data.icons,
                graph: undefined,
                layer: _.find(data.resource_map_layers, function(layer) {
                    return layer.nodeid === node.nodeid;
                }),
                mapSource: _.find(data.resource_map_sources, function(source) {
                    return source.nodeid === node.nodeid;
                }),
                graph: _.find(data.graphs, function(graph) {
                    return graph.graphid === node.graph_id;
                })
            })
        );
    });
    var selectedList;
    switch (window.location.hash) {
    case "#basemaps":
        selectedList = vm.basemaps;
        break;
    case "#overlays":
        selectedList = vm.overlays;
        break;
    default:
        selectedList = vm.geomNodes;
    }
    vm.selectedList(selectedList);
    vm.selection = ko.observable(ko.unwrap(selectedList)[0] || null);
    vm.selectedLayerJSON = ko.computed({
        read: function() {
            if (!vm.selection() || !vm.selection().maplayerid) {
                return '[]';
            }
            return vm.selection().layerJSON();
        },
        write: function(value) {
            if (vm.selection() && vm.selection().maplayerid) {
                vm.selection().layerJSON(value);
            }
        }
    });

    var displayLayers = JSON.parse(vm.selectedLayerJSON());
    var basemapLayers = getBasemapLayers();

    vm.mapStyle = {
        "version": 8,
        "name": "Basic",
        "metadata": {
            "mapbox:autocomposite": true,
            "mapbox:type": "template"
        },
        "sources": sources,
        "sprite": arches.mapboxSprites,
        "glyphs": arches.mapboxGlyphs,
        "layers": basemapLayers.concat(displayLayers)
    };

    var searchAggregations = ko.observable(null);
    var searchResults = ko.observable(null);
    var bins = binFeatureCollection(searchAggregations);

    var getSearchAggregationGeoJSON = function() {
        var agg = ko.unwrap(searchAggregations);
        if (!agg || !agg.geo_aggs.grid.buckets) {
            return {
                "type": "FeatureCollection",
                "features": []
            };
        }
        var features = [];
        _.each(agg.geo_aggs.grid.buckets, function(cell) {
            var pt = geohash.decode(cell.key);
            var feature = turf.point([pt.lon, pt.lat], {
                doc_count: cell.doc_count
            });
            features.push(feature);
        });
        var pointsFC = turf.featureCollection(features);

        var aggregated = turf.collect(ko.unwrap(bins), pointsFC, 'doc_count', 'doc_count');
        _.each(aggregated.features, function(feature) {
            feature.properties.doc_count = _.reduce(feature.properties.doc_count, function(i, ii) {
                return i + ii;
            }, 0);
        });

        return {
            points: pointsFC,
            agg: aggregated
        };
    };
    var updateSearchPointsGeoJSON = function() {
        var pointSource = vm.map.getSource('search-results-points');
        if (vm.map && pointSource) {
            var aggResults = ko.unwrap(searchResults);
            if (!aggResults || !aggResults.results) {
                return {
                    "type": "FeatureCollection",
                    "features": []
                };
            }

            var features = [];
            _.each(aggResults.results.hits.hits, function(result) {
                _.each(result._source.points, function(point) {
                    var feature = turf.point([point.point.lon, point.point.lat], _.extend(result._source, {
                        resourceinstanceid: result._id,
                        highlight: false
                    }));
                    features.push(feature);
                });
            });

            var pointsFC = turf.featureCollection(features);
            pointSource.setData(pointsFC);
        }
    };

    var updateSearchResultsLayer = function() {
        if (vm.map && searchAggregations()) {
            var aggSource = vm.map.getSource('search-results-hex');
            var hashSource = vm.map.getSource('search-results-hashes');
            if (aggSource && hashSource) {
                var aggData = getSearchAggregationGeoJSON();
                aggSource.setData(aggData.agg);
                hashSource.setData(aggData.points);
            }
            updateSearchPointsGeoJSON();
        }
    };

    vm.setupMap = function(map) {
        vm.map = map;
        map.on('moveend', function(e) {
            if (e.originalEvent) {
                var center = map.getCenter();
                var zoom = map.getZoom();
                if (vm.zoom() !== zoom) {
                    vm.zoom(zoom);
                }
                vm.centerX(center.lng);
                vm.centerY(center.lat);
            }
        });

        searchAggregations.subscribe(updateSearchResultsLayer);
        if (ko.isObservable(bins)) {
        	bins.subscribe(updateSearchResultsLayer);
        }
        updateSearchResultsLayer();
    };

    $.ajax({
        dataType: "json",
        url: arches.urls.search_results,
        data: {
            'paging-filter': 1
        },
        success: function(results) {
            results.results.aggregations.geo_aggs = results.results.aggregations.geo_aggs.inner.buckets[0];
            searchAggregations(results.results.aggregations);
            searchResults(results);
        }
    });

    var updateMapStyle = function() {
        var displayLayers;
        try {
            displayLayers = JSON.parse(vm.selectedLayerJSON());
        }
        catch (e) {
            displayLayers = [];
        }
        var basemapLayers = getBasemapLayers();
        if (vm.selection() && vm.selection().isoverlay) {
            vm.mapStyle.layers = basemapLayers.concat(displayLayers);
        } else {
            vm.mapStyle.layers = displayLayers;
        }
        if (vm.map) {
            vm.map.setStyle(vm.mapStyle);
            updateSearchResultsLayer();
        }
    };

    vm.selectedBasemapName.subscribe(updateMapStyle);
    vm.selection.subscribe(updateMapStyle);
    vm.selectedLayerJSON.subscribe(updateMapStyle);
    vm.selectedList.subscribe(function(selectedList) {
        var selection = null;
        var layerList = ko.unwrap(vm.selectedList());
        if (layerList && layerList.length > 0) {
            selection = layerList[0];
        }
        vm.selection(selection);
    });
    vm.listFilter = ko.observable('');
    vm.listItems = ko.computed(function() {
        var listFilter = vm.listFilter().toLowerCase();
        var layerList = ko.unwrap(vm.selectedList());
        return _.filter(layerList, function(item) {
            var name = item.nodeid ?
                (item.config.layerName() ? item.config.layerName() : item.layer.name) :
                item.name();
            name = name.toLowerCase();
            return name.indexOf(listFilter) > -1;
        });
    });
    var addMapConfig = function(key, defaultValue) {
        vm[key] = ko.computed({
            read: function() {
                var val;
                var selection = vm.selection();
                if (selection && selection[key]) {
                    val = selection[key]();
                }
                return val || defaultValue;
            },
            write: function(val) {
                var selection = vm.selection();
                val = val===defaultValue ? null : val;
                if (selection && selection[key]) {
                    selection[key](val);
                }
            }
        });
    };
    addMapConfig('centerX', arches.mapDefaultX);
    addMapConfig('centerY', arches.mapDefaultY);
    addMapConfig('zoom', arches.mapDefaultZoom);

    var pageView = new BaseManagerView({
        viewModel: vm
    });

    return pageView;
});
<commit_msg>lints, re: #4670<commit_after>define([
    'jquery',
    'knockout',
    'underscore',
    'turf',
    'geohash',
    'views/base-manager',
    'models/node',
    'viewmodels/alert',
    'views/components/widgets/map/bin-feature-collection',
    'map-layer-manager-data',
    'arches',
    'bindings/mapbox-gl',
    'bindings/codemirror',
    'codemirror/mode/javascript/javascript',
    'datatype-config-components'
], function($, ko, _, turf, geohash, BaseManagerView, NodeModel, AlertViewModel, binFeatureCollection, data, arches) {
    var vm = {
        map: null,
        geomNodes: [],
        loading: ko.observable(false),
        minZoom: ko.observable(arches.mapDefaultMinZoom),
        maxZoom: ko.observable(arches.mapDefaultMaxZoom),
        pitch: ko.observable(0),
        bearing: ko.observable(0),
        iconFilter: ko.observable(''),
        selectedList: ko.observable()
    };

    vm.icons = ko.computed(function() {
        return _.filter(data.icons, function(icon) {
            return icon.name.indexOf(vm.iconFilter()) >= 0;
        });
    });
    var mapLayers = ko.observableArray($.extend(true, [], arches.mapLayers));
    _.each(mapLayers(), function(layer) {
        layer._layer = ko.observable(JSON.stringify(layer));
        layer.layerJSON = ko.observable(JSON.stringify(layer.layer_definitions, null, '\t'));
        layer.activated = ko.observable(layer.activated);
        layer.addtomap = ko.observable(layer.addtomap);
        layer.name = ko.observable(layer.name);
        layer.icon = ko.observable(layer.icon);
        layer.legend = ko.observable(layer.legend);
        layer.centerX = ko.observable(layer.centerx);
        layer.centerY = ko.observable(layer.centery);
        layer.zoom = ko.observable(layer.zoom);
        layer.toJSON = ko.computed(function() {
            var layers;
            try {
                layers = JSON.parse(layer.layerJSON());
            }
            catch (e) {
                layers = [];
            }
            return JSON.stringify({
                "maplayerid": layer.maplayerid,
                "name": layer.name(),
                "layer_definitions": layers,
                "isoverlay": layer.isoverlay,
                "icon": layer.icon(),
                "legend": layer.legend(),
                "activated": layer.activated(),
                "addtomap": layer.addtomap(),
                "is_resource_layer": false,
                "centerx": layer.centerX(),
                "centery": layer.centerY(),
                "zoom": layer.zoom()
            });
        });
        layer.dirty = ko.computed(function() {
            return layer.toJSON() !== layer._layer();
        });
        layer.save = function() {
            vm.loading(true);
            $.ajax({
                type: "POST",
                url: window.location.pathname + '/' + layer.maplayerid,
                data: layer.toJSON(),
                success: function(response) {
                    layer._layer(layer.toJSON());
                    pageView.viewModel.loading(false);
                    var mapLayer = _.find(arches.mapLayers, function(mapLayer) {
                        return mapLayer.maplayerid === layer.maplayerid;
                    });
                    _.extend(mapLayer, JSON.parse(layer._layer()));
                    if (!mapLayer.isoverlay && mapLayer.addtomap) {
                        _.each(vm.basemaps(), function(basemap) {
                            if (basemap.maplayerid !== layer.maplayerid) {
                                basemap.addtomap(false);
                            }
                        });
                        _.each(arches.mapLayers, function(mapLayer) {
                            if (!mapLayer.isoverlay && mapLayer.maplayerid !== layer.maplayerid) {
                                mapLayer.addtomap = false;
                            }
                        });
                    }
                },
                error: function(response) {
                    pageView.viewModel.loading(false);
                }
            });
        };
        layer.reset = function() {
            var _layer = JSON.parse(layer._layer());
            layer.layerJSON(JSON.stringify(_layer.layer_definitions, null, '\t'));
            layer.activated(_layer.activated);
            layer.addtomap(_layer.addtomap),
            layer.name(_layer.name);
            layer.icon(_layer.icon);
            layer.centerX(_layer.centerx);
            layer.centerY(_layer.centery);
            layer.zoom(_layer.zoom);
            layer.legend(_layer.legend);
        };
        layer.delete = function() {
            pageView.viewModel.alert(new AlertViewModel('ep-alert-red', arches.confirmMaplayerDelete.title, arches.confirmMaplayerDelete.text, function() {
                return;
            }, function(){
                vm.loading(true);
                $.ajax({
                    type: "DELETE",
                    url: window.location.pathname + '/' + layer.maplayerid,
                    success: function(response) {
                        mapLayers.remove(layer);
                        arches.mapLayers = _.without(arches.mapLayers, _.findWhere(arches.mapLayers, {
                            maplayerid: layer.maplayerid
                        }));
                        var selection = null;
                        var layerList = ko.unwrap(vm.selectedList());
                        if (layerList && layerList.length > 0) {
                            selection = layerList[0];
                        }
                        vm.selection(selection);
                        pageView.viewModel.loading(false);
                    },
                    error: function(response) {
                        pageView.viewModel.loading(false);
                    }
                });
            }));
        };
    });

    vm.selectedBasemapName = ko.observable('');
    vm.basemaps = ko.computed(function() {
        return _.filter(mapLayers(), function(layer) {
            return !layer.isoverlay;
        });
    });
    vm.basemaps().forEach(function(basemap) {
        basemap.select = function() {
            vm.selectedBasemapName(basemap.name());
        };
    });
    var defaultBasemap = _.find(vm.basemaps(), function(basemap) {
        return basemap.addtomap();
    });
    if (!defaultBasemap) {
        defaultBasemap = vm.basemaps()[0];
    }
    if (defaultBasemap) {
        vm.selectedBasemapName(defaultBasemap.name());
    }
    vm.overlays = ko.computed(function() {
        return _.filter(mapLayers(), function(layer) {
            return layer.isoverlay && !layer.is_resource_layer;
        });
    });

    var getBasemapLayers = function() {
        return _.filter(vm.basemaps(), function(layer) {
            return layer.name() === vm.selectedBasemapName();
        }).reduce(function(layers, layer) {
            return layers.concat(layer.layer_definitions);
        }, []);
    };
    var sources = $.extend(true, {}, arches.mapSources);

    sources["search-results-hex"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };
    sources["search-results-points"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };
    sources["search-results-hashes"] = {
        "type": "geojson",
        "data": {
            "type": "FeatureCollection",
            "features": []
        }
    };

    _.each(sources, function(sourceConfig, name) {
        if (sourceConfig.tiles) {
            sourceConfig.tiles.forEach(function(url, i) {
                if (url.startsWith('/')) {
                    sourceConfig.tiles[i] = window.location.origin + url;
                }
            });
        }
    });

    var datatypelookup = {};
    _.each(data.datatypes, function(datatype){
        datatypelookup[datatype.datatype] = datatype;
    }, this);

    _.each(data.geom_nodes, function(node) {
        vm.geomNodes.push(
            new NodeModel({
                url: arches.urls.node_layer,
                loading: vm.loading,
                permissions: data.node_permissions[node.nodeid],
                source: node,
                datatypelookup: datatypelookup,
                icons: data.icons,
                graph: undefined,
                layer: _.find(data.resource_map_layers, function(layer) {
                    return layer.nodeid === node.nodeid;
                }),
                mapSource: _.find(data.resource_map_sources, function(source) {
                    return source.nodeid === node.nodeid;
                }),
                graph: _.find(data.graphs, function(graph) {
                    return graph.graphid === node.graph_id;
                })
            })
        );
    });
    var selectedList;
    switch (window.location.hash) {
    case "#basemaps":
        selectedList = vm.basemaps;
        break;
    case "#overlays":
        selectedList = vm.overlays;
        break;
    default:
        selectedList = vm.geomNodes;
    }
    vm.selectedList(selectedList);
    vm.selection = ko.observable(ko.unwrap(selectedList)[0] || null);
    vm.selectedLayerJSON = ko.computed({
        read: function() {
            if (!vm.selection() || !vm.selection().maplayerid) {
                return '[]';
            }
            return vm.selection().layerJSON();
        },
        write: function(value) {
            if (vm.selection() && vm.selection().maplayerid) {
                vm.selection().layerJSON(value);
            }
        }
    });

    var displayLayers = JSON.parse(vm.selectedLayerJSON());
    var basemapLayers = getBasemapLayers();

    vm.mapStyle = {
        "version": 8,
        "name": "Basic",
        "metadata": {
            "mapbox:autocomposite": true,
            "mapbox:type": "template"
        },
        "sources": sources,
        "sprite": arches.mapboxSprites,
        "glyphs": arches.mapboxGlyphs,
        "layers": basemapLayers.concat(displayLayers)
    };

    var searchAggregations = ko.observable(null);
    var searchResults = ko.observable(null);
    var bins = binFeatureCollection(searchAggregations);

    var getSearchAggregationGeoJSON = function() {
        var agg = ko.unwrap(searchAggregations);
        if (!agg || !agg.geo_aggs.grid.buckets) {
            return {
                "type": "FeatureCollection",
                "features": []
            };
        }
        var features = [];
        _.each(agg.geo_aggs.grid.buckets, function(cell) {
            var pt = geohash.decode(cell.key);
            var feature = turf.point([pt.lon, pt.lat], {
                doc_count: cell.doc_count
            });
            features.push(feature);
        });
        var pointsFC = turf.featureCollection(features);

        var aggregated = turf.collect(ko.unwrap(bins), pointsFC, 'doc_count', 'doc_count');
        _.each(aggregated.features, function(feature) {
            feature.properties.doc_count = _.reduce(feature.properties.doc_count, function(i, ii) {
                return i + ii;
            }, 0);
        });

        return {
            points: pointsFC,
            agg: aggregated
        };
    };
    var updateSearchPointsGeoJSON = function() {
        var pointSource = vm.map.getSource('search-results-points');
        if (vm.map && pointSource) {
            var aggResults = ko.unwrap(searchResults);
            if (!aggResults || !aggResults.results) {
                return {
                    "type": "FeatureCollection",
                    "features": []
                };
            }

            var features = [];
            _.each(aggResults.results.hits.hits, function(result) {
                _.each(result._source.points, function(point) {
                    var feature = turf.point([point.point.lon, point.point.lat], _.extend(result._source, {
                        resourceinstanceid: result._id,
                        highlight: false
                    }));
                    features.push(feature);
                });
            });

            var pointsFC = turf.featureCollection(features);
            pointSource.setData(pointsFC);
        }
    };

    var updateSearchResultsLayer = function() {
        if (vm.map && searchAggregations()) {
            var aggSource = vm.map.getSource('search-results-hex');
            var hashSource = vm.map.getSource('search-results-hashes');
            if (aggSource && hashSource) {
                var aggData = getSearchAggregationGeoJSON();
                aggSource.setData(aggData.agg);
                hashSource.setData(aggData.points);
            }
            updateSearchPointsGeoJSON();
        }
    };

    vm.setupMap = function(map) {
        vm.map = map;
        map.on('moveend', function(e) {
            if (e.originalEvent) {
                var center = map.getCenter();
                var zoom = map.getZoom();
                if (vm.zoom() !== zoom) {
                    vm.zoom(zoom);
                }
                vm.centerX(center.lng);
                vm.centerY(center.lat);
            }
        });

        searchAggregations.subscribe(updateSearchResultsLayer);
        if (ko.isObservable(bins)) {
        	bins.subscribe(updateSearchResultsLayer);
        }
        updateSearchResultsLayer();
    };

    $.ajax({
        dataType: "json",
        url: arches.urls.search_results,
        data: {
            'paging-filter': 1
        },
        success: function(results) {
            results.results.aggregations['geo_aggs'] = results.results.aggregations['geo_aggs'].inner.buckets[0];
            searchAggregations(results.results.aggregations);
            searchResults(results);
        }
    });

    var updateMapStyle = function() {
        var displayLayers;
        try {
            displayLayers = JSON.parse(vm.selectedLayerJSON());
        }
        catch (e) {
            displayLayers = [];
        }
        var basemapLayers = getBasemapLayers();
        if (vm.selection() && vm.selection().isoverlay) {
            vm.mapStyle.layers = basemapLayers.concat(displayLayers);
        } else {
            vm.mapStyle.layers = displayLayers;
        }
        if (vm.map) {
            vm.map.setStyle(vm.mapStyle);
            updateSearchResultsLayer();
        }
    };

    vm.selectedBasemapName.subscribe(updateMapStyle);
    vm.selection.subscribe(updateMapStyle);
    vm.selectedLayerJSON.subscribe(updateMapStyle);
    vm.selectedList.subscribe(function(selectedList) {
        var selection = null;
        var layerList = ko.unwrap(selectedList);
        if (layerList && layerList.length > 0) {
            selection = layerList[0];
        }
        vm.selection(selection);
    });
    vm.listFilter = ko.observable('');
    vm.listItems = ko.computed(function() {
        var listFilter = vm.listFilter().toLowerCase();
        var layerList = ko.unwrap(vm.selectedList());
        return _.filter(layerList, function(item) {
            var name = item.nodeid ?
                (item.config.layerName() ? item.config.layerName() : item.layer.name) :
                item.name();
            name = name.toLowerCase();
            return name.indexOf(listFilter) > -1;
        });
    });
    var addMapConfig = function(key, defaultValue) {
        vm[key] = ko.computed({
            read: function() {
                var val;
                var selection = vm.selection();
                if (selection && selection[key]) {
                    val = selection[key]();
                }
                return val || defaultValue;
            },
            write: function(val) {
                var selection = vm.selection();
                val = val===defaultValue ? null : val;
                if (selection && selection[key]) {
                    selection[key](val);
                }
            }
        });
    };
    addMapConfig('centerX', arches.mapDefaultX);
    addMapConfig('centerY', arches.mapDefaultY);
    addMapConfig('zoom', arches.mapDefaultZoom);

    var pageView = new BaseManagerView({
        viewModel: vm
    });

    return pageView;
});
<|endoftext|>


<commit_before>'use strict';

describe('bricksFactory test', function(){

    describe('when I call factory', function(){
        beforeEach(module('BrickInventoryApp.services'));
        beforeEach(module('BrickInventoryApp.loaders'));
        beforeEach(module('BrickInventoryApp.factories'));

        it('returns a list of bricks', inject(function(bricksFactory){

           expect( bricksFactory ).toBeDefined( )
           expect( bricksFactory.length ).toBeGreaterThan( 0 )

        }))

        it('and bricks have loaded attributes', inject(function(bricksFactory){

          var brick = bricksFactory[0]
          expect( brick.item ).toBeDefined( )
          expect( brick.item.itemType ).toBeDefined( )
          expect( brick.item.itemId ).toBeDefined( )
          expect( brick.item.itemName ).toBeDefined( )
          expect( brick.item.quantity ).toBeDefined( )
          expect( brick.item.colorId ).toBeDefined( )

        }))

        it('and bricks have additional attributes', inject(function(bricksFactory){

          var brick = bricksFactory[0]
          expect( brick.count ).toBeDefined( )
          expect( brick.show ).toBeDefined( )
          expect( brick.colorFilter ).toBeDefined( )
          expect( brick.shapeFilter ).toBeDefined( )

        }))

        it('and bricks have groupNames', inject(function(bricksFactory){

           expect( bricksFactory[0].item.groupName ).toBeDefined( ) ;
           //TODO chercher sur la valeur a un sens

        }))

        it('and bricks have colorNames', inject(function(bricksFactory){

           expect( bricksFactory[0].colorName ).toBeDefined( ) ;
          //TODO chercher sur la valeur a un sens

        }))
    })

});
<commit_msg>improved test on factory - check that groupName and colorName are meaningfull<commit_after>'use strict';

describe('bricksFactory test', function(){

    describe('when I call factory', function(){
        beforeEach(module('BrickInventoryApp.services'));
        beforeEach(module('BrickInventoryApp.loaders'));
        beforeEach(module('BrickInventoryApp.factories'));

        it('returns a list of bricks', inject(function(bricksFactory){

           expect( bricksFactory ).toBeDefined( )
           expect( bricksFactory.length ).toBeGreaterThan( 0 )

        }))

        it('and bricks have loaded attributes', inject(function(bricksFactory){

          var brick = bricksFactory[0]
          expect( brick.item ).toBeDefined( )
          expect( brick.item.itemType ).toBeDefined( )
          expect( brick.item.itemId ).toBeDefined( )
          expect( brick.item.itemName ).toBeDefined( )
          expect( brick.item.quantity ).toBeDefined( )
          expect( brick.item.colorId ).toBeDefined( )

        }))

        it('and bricks have additional attributes', inject(function(bricksFactory){

          var brick = bricksFactory[0]
          expect( brick.count ).toBeDefined( )
          expect( brick.show ).toBeDefined( )
          expect( brick.colorFilter ).toBeDefined( )
          expect( brick.shapeFilter ).toBeDefined( )

        }))

        it('and bricks have groupNames', inject(function(bricksFactory){

           var items = bricksFactory.filter( function(e) { return e.item.itemId == "3003" } )
           expect( items[0].item.groupName ).toBe( "Brick" ) ;

        }))

        it('and bricks have colorNames', inject(function(bricksFactory){

           var items = bricksFactory.filter( function(e) { return e.item.itemId == "3003" } )
           expect( items[0].colorName ).toBe( "Red" ) ;

        }))
    })

});
<|endoftext|>


<commit_before>var ELLY = ELLY || {};

ELLY.State = function() {
    this.objectProto = new THREE.Object3D();

};

ELLY.State.prototype = {
   constructor : ELLY.State
};

ELLY.System = (function() {
    var cubeGeometry = new THREE.CubeGeometry(1, 1, 1);
    var cubeMaterial = new THREE.MeshPhongMaterial({color: 0xcccccc});

    var m =  function(scene, maxDepth) {
        this.scene = scene;

        this.backlog = [];
        this.backlogBuild = [];

        this.maxDepth = maxDepth || 10;
        this.depth = 0;

        this.state = new ELLY.State();
        this.scene.add(this.state.objectProto);
    }

    m.prototype.constructor = m;

    m.prototype.rule = function(name, code) {

        this[name] = function(transforms, isRoot) {
            if (isRoot === true) {
                saveState = this.state;
                this.state = new ELLY.State();
                saveState.objectProto.add(this.state.objectProto);

                this.evalTransforms(transforms);
                if (typeof code == 'string' || code instanceof String) {
                    new Function(code).call(this);
                } else {
                    code.call(this);
                }
                this.state = saveState;
            } else if (this.depth < this.maxDepth) {
                this.backlogBuild.push([name, transforms, this.state]);
            }
            return this;            // method chain
        };
    };

    m.prototype.evalTransforms = function(transforms) {
        for(t in transforms) {
            if (t in this) {
                this[t].call(this, transforms[t]);
            } else {
                console.warn("Skipping unknown transform \"" + t +"\".")
            }
        }
    };

    /*
     * Start evaluation with rule "name"
     */
    m.prototype.trigger = function(name) {
        this.backlog.push([name, {}, this.state]);
        this.scene.add(this.state.objectProto);

        this.depth = 0;
        while (this.backlog.length > 0) {
//            console.debug("[ITERATION] D: " + this.depth + " Size: " + this.backlog.length);
            while (this.backlog.length > 0) {
//                console.debug("[RULE] " + this.backlog[0] + ":" + this.depth);
                var entry = this.backlog.shift();
                this.state = entry[2];
                this[entry[0]].call(this, entry[1], true);
            }
            this.depth++;
            this.backlog = this.backlogBuild;
            this.backlogBuild = [];
        }
    };

    /*
     * Move forward (scale sensitive)
     */
    m.prototype.move =  m.prototype.m = function(amount) {
        this.state.objectProto.position.x += amount;
        return this;
    };

    /*
     * Change scale by factor amount
     */
    m.prototype.scale =  m.prototype.s = function(amount) {
        this.state.objectProto.scale.multiplyScalar(amount);
        return this;
    };

    // pitch roll yaw
    m.prototype.roll = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.x += angle;
    };

    m.prototype.yaw = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.y += angle;
    };

    m.prototype.pitch = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.z += angle;
    };

    m.prototype.rule("cube", function() {

        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        this.state.objectProto.clone(cube);
        this.state.objectProto.parent.add(cube);

//        return this;
    });

    return m;

})();

<commit_msg>transition to omitting this.<commit_after>var ELLY = ELLY || {};

ELLY.State = function() {
    this.objectProto = new THREE.Object3D();

};

ELLY.System = (function() {
    var cubeGeometry = new THREE.CubeGeometry(1, 1, 1);
    var cubeMaterial = new THREE.MeshPhongMaterial({color: 0xcccccc});

    var system = function(scene, maxDepth) {
        this.scene = scene;

        this.backlog = [];
        this.backlogBuild = [];

        this.maxDepth = maxDepth || 10;
        this.depth = 0;

        this.state = new ELLY.State();
        this.scene.add(this.state.objectProto);
    }

    system.prototype.constructor = system;

    var that = this;

    var rulify = function (code) {
       currentF = function(transforms, isRoot) {
            if (isRoot === true) {
                saveState = this.state;
                this.state = new ELLY.State();
                saveState.objectProto.add(this.state.objectProto);
                this.evalTransforms(transforms);
                code.call(this);
                this.state = saveState;
            } else if (this.depth < this.maxDepth) {
                this.backlogBuild.push([currentF, transforms, this.state]);
            }
            return this;            // method chain
        };

        return currentF;
    };

    system.prototype.rule = function(name, code) {
        that[name] = this[name] = rulify(code);
    };

    system.prototype.evalTransforms = function(transforms) {
        for(t in transforms) {
            if (t in that) {
                that[t].call(this, transforms[t]);
            } else {
                console.warn("Skipping unknown transform \"" + t +"\".")
            }
        }
    };

    /*
     * Start evaluation with rule "name"
     */
    system.prototype.trigger = function(name) {
        this.backlog.push([that[name], {}, this.state]);
        this.scene.add(this.state.objectProto);

        this.depth = 0;
        while (this.backlog.length > 0) {
            console.debug("[ITERATION] D: " + this.depth + " Size: " + this.backlog.length);
            while (this.backlog.length > 0) {
                console.debug("[RULE] " + this.backlog[0] + ":" + this.depth);
                var entry = this.backlog.shift();
                this.state = entry[2];
                entry[0].call(this, entry[1],true);

            }
            this.depth++;
            this.backlog = this.backlogBuild;
            this.backlogBuild = [];
        }
    };

    /*
     * Move forward (scale sensitive)
     */
    var move = function(amount) {
        this.state.objectProto.position.x += amount;
        return this;
    };

    var m = move;

    /*
     * Change scale by factor amount
     */
    var scale = function(amount) {
        this.state.objectProto.scale.multiplyScalar(amount);
        return this;
    };

    var s = scale;

    // pitch roll yaw
    var roll = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.x += angle;
    };

    var yaw = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.y += angle;
    };

    var pitch = function(angle) {
        angle = angle * Math.PI / 180.0;
        this.state.objectProto.rotation.z += angle;
    };

    that.cuby = rulify(function() {
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        console.log("YEAH");
        this.state.objectProto.clone(cube);
        this.state.objectProto.parent.add(cube);

//        return this;
    });

    return system;

})();

<|endoftext|>


<commit_before>/**
 * Search Console dashboard utility functions.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import { each } from 'lodash';

/**
 * Internal dependencies
 */
import { changeToPercent, readableLargeNumber } from '../../../util';

function reduceSearchConsoleData( rows ) {
	const dataMap = [
		[
			{ type: 'string', label: 'Day' },
			{ type: 'number', label: 'Clicks' },
			{ type: 'number', label: 'Impressions' },
			{ type: 'number', label: 'CTR' },
			{ type: 'number', label: 'Position' },
		],
	];

	let totalClicks = 0;
	let totalImpressions = 0;
	let totalCTR = 0;
	let totalPosition = 0;
	const count = rows.length;
	each( rows, ( row ) => {
		const date = new Date( row.keys[ 0 ] );
		dataMap.push( [
			( date.getMonth() + 1 ) + '/' + date.getUTCDate(),
			row.clicks,
			row.impressions,
			row.ctr,
			row.position,
		] );
		totalClicks += row.clicks;
		totalImpressions += row.impressions;
		totalCTR += row.ctr;
		totalPosition += row.position;
	} );

	const totalClicksRaw = totalClicks;
	const totalImpressionsRaw = totalImpressions;

	totalClicks = readableLargeNumber( totalClicks );
	totalImpressions = readableLargeNumber( totalImpressions );

	const averageCTR = ( totalCTR / count * 100 ).toFixed( 1 );
	const averageCTRRaw = totalCTR / count;
	const averagePosition = ( totalPosition / count ).toFixed( 1 );

	return {
		dataMap,
		totalClicks,
		totalClicksRaw,
		totalImpressions,
		totalImpressionsRaw,
		averageCTR,
		averageCTRRaw,
		averagePosition,
	};
}

export const extractSearchConsoleDashboardData = ( rows ) => {
	// Split the results in two chunks.
	const half = Math.floor( rows.length / 2 );
	// Rows are from oldest to newest.
	const latestData = reduceSearchConsoleData( rows.slice( half ) );
	const olderData = reduceSearchConsoleData( rows.slice( 0, half ) );

	return {
		dataMap: latestData.dataMap,
		totalClicks: latestData.totalClicks,
		totalImpressions: latestData.totalImpressions,
		averageCTR: latestData.averageCTR,
		averagePosition: latestData.averagePosition,
		totalClicksChange: changeToPercent( olderData.totalClicksRaw, latestData.totalClicksRaw ),
		totalImpressionsChange: changeToPercent( olderData.totalImpressionsRaw, latestData.totalImpressionsRaw ),
		averageCTRChange: changeToPercent( olderData.averageCTRRaw, latestData.averageCTRRaw ),
		averagePositionChange: changeToPercent( olderData.averagePosition, latestData.averagePosition ),
	};
};

/**
 * Check for Zero data from Search Console API.
 *
 * @param {Object} data The data returned from the Search Console API call.
 * @return {boolean} Indicates zero data was returned from Search Console API call.
 */
export const isDataZeroSearchConsole = ( data ) => {
	if ( ! data.length ) {
		return true;
	}

	const processedData = extractSearchConsoleDashboardData( data );

	const {
		totalClicks,
		totalImpressions,
		averageCTR,
		averagePosition,
	} = processedData;

	return (
		0 === parseInt( totalClicks ) &&
			0 === parseInt( totalImpressions ) &&
			0 === parseInt( averageCTR ) &&
			0 === parseInt( averagePosition )
	);
};
<commit_msg>Ensure we don't divide by zero when extracting Search Console data.<commit_after>/**
 * Search Console dashboard utility functions.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import { each } from 'lodash';

/**
 * Internal dependencies
 */
import { changeToPercent, readableLargeNumber } from '../../../util';

function reduceSearchConsoleData( rows ) {
	const dataMap = [
		[
			{ type: 'string', label: 'Day' },
			{ type: 'number', label: 'Clicks' },
			{ type: 'number', label: 'Impressions' },
			{ type: 'number', label: 'CTR' },
			{ type: 'number', label: 'Position' },
		],
	];

	let totalClicks = 0;
	let totalImpressions = 0;
	let totalCTR = 0;
	let totalPosition = 0;
	const count = rows.length;
	each( rows, ( row ) => {
		const date = new Date( row.keys[ 0 ] );
		dataMap.push( [
			( date.getMonth() + 1 ) + '/' + date.getUTCDate(),
			row.clicks,
			row.impressions,
			row.ctr,
			row.position,
		] );
		totalClicks += row.clicks;
		totalImpressions += row.impressions;
		totalCTR += row.ctr;
		totalPosition += row.position;
	} );

	const totalClicksRaw = totalClicks;
	const totalImpressionsRaw = totalImpressions;

	totalClicks = readableLargeNumber( totalClicks );
	totalImpressions = readableLargeNumber( totalImpressions );

	// Do not divide by zero.
	const averageCTR = count > 0 ? ( totalCTR / count * 100 ).toFixed( 1 ) : '0.0';
	const averageCTRRaw = count > 0 ? totalCTR / count : 0.0;
	const averagePosition = count > 0 ? ( totalPosition / count ).toFixed( 1 ) : '0.0';

	return {
		dataMap,
		totalClicks,
		totalClicksRaw,
		totalImpressions,
		totalImpressionsRaw,
		averageCTR,
		averageCTRRaw,
		averagePosition,
	};
}

export const extractSearchConsoleDashboardData = ( rows ) => {
	// Split the results in two chunks.
	const half = Math.floor( rows.length / 2 );
	// Rows are from oldest to newest.
	const latestData = reduceSearchConsoleData( rows.slice( half ) );
	const olderData = reduceSearchConsoleData( rows.slice( 0, half ) );

	return {
		dataMap: latestData.dataMap,
		totalClicks: latestData.totalClicks,
		totalImpressions: latestData.totalImpressions,
		averageCTR: latestData.averageCTR,
		averagePosition: latestData.averagePosition,
		totalClicksChange: changeToPercent( olderData.totalClicksRaw, latestData.totalClicksRaw ),
		totalImpressionsChange: changeToPercent( olderData.totalImpressionsRaw, latestData.totalImpressionsRaw ),
		averageCTRChange: changeToPercent( olderData.averageCTRRaw, latestData.averageCTRRaw ),
		averagePositionChange: changeToPercent( olderData.averagePosition, latestData.averagePosition ),
	};
};

/**
 * Check for Zero data from Search Console API.
 *
 * @param {Object} data The data returned from the Search Console API call.
 * @return {boolean} Indicates zero data was returned from Search Console API call.
 */
export const isDataZeroSearchConsole = ( data ) => {
	if ( ! data.length ) {
		return true;
	}

	const processedData = extractSearchConsoleDashboardData( data );

	const {
		totalClicks,
		totalImpressions,
		averageCTR,
		averagePosition,
	} = processedData;

	return (
		0 === parseInt( totalClicks ) &&
			0 === parseInt( totalImpressions ) &&
			0 === parseInt( averageCTR ) &&
			0 === parseInt( averagePosition )
	);
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*jshint latedef:nofunc, node:true*/

// Modules
var fs = require('fs');
var path = require('path');
var dependencyPath = path.join(process.cwd(), 'node_modules');
// cordova-uglify module dependencies
var UglifyJS = require(path.join(dependencyPath, 'uglify-js'));
var CleanCSS = require(path.join(dependencyPath, 'clean-css'));
var ngAnnotate = require(path.join(dependencyPath, 'ng-annotate'));

// Process
var rootDir = process.argv[2];
var platformPath = path.join(rootDir, 'platforms');
var platforms = process.env.CORDOVA_PLATFORMS.split(',');
var cliCommand = process.env.CORDOVA_CMDLINE;

// Hook configuration
var configFilePath = path.join(rootDir, 'hooks/uglify-config.json');
var hookConfig = JSON.parse(fs.readFileSync(configFilePath));
var isRelease = hookConfig.alwaysRun || (cliCommand.indexOf('--release') > -1);
var recursiveFolderSearch = hookConfig.recursiveFolderSearch; // set this to false to manually indicate the folders to process
var foldersToProcess = hookConfig.foldersToProcess; // add other www folders in here if needed (ex. js/controllers)
var cssMinifier = new CleanCSS(hookConfig.cleanCssOptions);

// Exit
if (!isRelease) {
  return;
}

// Run uglifier
run();

/**
 * Run compression for all specified platforms.
 * @return {undefined}
 */
function run() {
  platforms.forEach(function(platform) {
    var wwwPath;

    switch (platform) {
      case 'android':
        wwwPath = path.join(platformPath, platform, 'assets', 'www');
        if (!fs.existsSync(wwwPath)) {
          wwwPath = path.join(platformPath, platform, 'app', 'src', 'main', 'assets', 'www');
        }
        break;

      case 'ios':
      case 'browser':
      case 'wp8':
      case 'windows':
        wwwPath = path.join(platformPath, platform, 'www');
        break;

      default:
        console.log('this hook only supports android, ios, wp8, windows, and browser currently');
        return;
    }

    processFolders(wwwPath);
  });
}

/**
 * Processes defined folders.
 * @param  {string} wwwPath - Path to www directory
 * @return {undefined}
 */
function processFolders(wwwPath) {
  foldersToProcess.forEach(function(folder) {
    processFiles(path.join(wwwPath, folder));
  });
}

/**
 * Processes files in directories.
 * @param  {string} dir - Directory path
 * @return {undefined}
 */
function processFiles(dir) {
  fs.readdir(dir, function(err, list) {
    if (err) {
      console.log('processFiles err: ' + err);

      return;
    }

    list.forEach(function(file) {
      file = path.join(dir, file);

      fs.stat(file, function(err, stat) {
        if (stat.isFile()) {
          compress(file);

          return;
        }

        if (recursiveFolderSearch && stat.isDirectory()) {
          processFiles(file);

          return;
        }
      });
    });
  });
}

/**
 * Compresses file.
 * @param  {string} file - File path
 * @return {undefined}
 */
function compress(file) {
  var ext = path.extname(file),
    res,
    source,
    result;

  switch (ext) {
    case '.js':
      console.log('uglifying js file ' + file);

      res = ngAnnotate(String(fs.readFileSync(file, 'utf8')), {
        add: true
      });
      result = UglifyJS.minify(res.src, hookConfig.uglifyJsOptions);
      fs.writeFileSync(file, result.code, 'utf8'); // overwrite the original unminified file
      break;

    case '.css':
      console.log('minifying css file ' + file);

      source = fs.readFileSync(file, 'utf8');
      result = cssMinifier.minify(source);
      fs.writeFileSync(file, result.styles, 'utf8'); // overwrite the original unminified file
      break;

    default:
      console.log('encountered a ' + ext + ' file, not compressing it');
      break;
  }
}
<commit_msg>Formatting nit<commit_after>/*jshint latedef:nofunc, node:true*/
/* eslint-env node */

module.exports = function(ctx) {
  'use strict';

  var fs = require('fs'),
    path = require('path'),
    UglifyJS = require('uglify-js'),
    CleanCSS = require('clean-css'),
    ngAnnotate = require('ng-annotate'),
    rootDir = ctx.opts.projectRoot,
    platformPath = path.join(rootDir, 'platforms'),
    platforms = ctx.opts.cordova.platforms,
    cliCommand = ctx.cmdLine,
    configFilePath = path.join(rootDir, 'hooks/uglify-config.json'),
    hookConfig = JSON.parse(fs.readFileSync(configFilePath)),
    isRelease = hookConfig.alwaysRun || cliCommand.indexOf('--release') > -1,
    recursiveFolderSearch = hookConfig.recursiveFolderSearch, // set this to false to manually indicate the folders to process
    foldersToProcess = hookConfig.foldersToProcess, // add other www folders in here if needed (ex. js/controllers)
    cssMinifier = new CleanCSS(hookConfig.cleanCssOptions);

  /**
   * Compresses file.
   * @param  {string} file - File path
   * @return {undefined}
   */
  function compress(file) {
    var ext = path.extname(file),
      res,
      source,
      result;

    switch (ext) {
      case '.js':
        console.log('uglifying js file ' + file);

        res = ngAnnotate(String(fs.readFileSync(file, 'utf8')), {
          add: true,
        });
        result = UglifyJS.minify(res.src, hookConfig.uglifyJsOptions);
        fs.writeFileSync(file, result.code, 'utf8'); // overwrite the original unminified file
        break;

      case '.css':
        console.log('minifying css file ' + file);

        source = fs.readFileSync(file, 'utf8');
        result = cssMinifier.minify(source);
        fs.writeFileSync(file, result.styles, 'utf8'); // overwrite the original unminified file
        break;

      default:
        console.log('encountered a ' + ext + ' file, not compressing it');
        break;
    }
  }

  /**
   * Processes files in directories.
   * @param  {string} dir - Directory path
   * @return {undefined}
   */
  function processFiles(dir) {
    fs.readdir(dir, function(err, list) {
      if (err) {
        console.log('processFiles err: ' + err);

        return;
      }

      list.forEach(function(file) {
        file = path.join(dir, file);

        fs.stat(file, function(err, stat) {
          if (stat.isFile()) {
            compress(file);
            return;
          }

          if (recursiveFolderSearch && stat.isDirectory()) {
            processFiles(file);
            return;
          }
        });
      });
    });
  }

  /**
   * Processes defined folders.
   * @param  {string} wwwPath - Path to www directory
   * @return {undefined}
   */
  function processFolders(wwwPath) {
    foldersToProcess.forEach(function(folder) {
      processFiles(path.join(wwwPath, folder));
    });
  }

  if (!isRelease) {
    return;
  }

  platforms.forEach(function(platform) {
    var wwwPath;

    switch (platform) {
      case 'android':
        wwwPath = path.join(platformPath, platform, 'assets', 'www');
        if (!fs.existsSync(wwwPath)) {
          wwwPath = path.join(
            platformPath,
            platform,
            'app',
            'src',
            'main',
            'assets',
            'www'
          );
        }
        break;

      case 'ios':
      case 'browser':
      case 'wp8':
      case 'windows':
        wwwPath = path.join(platformPath, platform, 'www');
        break;

      default:
        console.log(
          'this hook only supports android, ios, wp8, windows, and browser currently'
        );
        return;
    }

    processFolders(wwwPath);
  });
};
<|endoftext|>