<commit_before>/*global global*/
/**
 * @author Christian Johansen (christian@cjohansen.no) and contributors
 * @license BSD
 *
 * Copyright (c) 2010-2014 Christian Johansen
 */

(function (global) {
    "use strict";

    // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
    // browsers, a number.
    // see https://github.com/cjohansen/Sinon.JS/pull/436

    var NOOP = function () { return undefined; };
    var timeoutResult = setTimeout(NOOP, 0);
    var addTimerReturnsObject = typeof timeoutResult === "object";
    clearTimeout(timeoutResult);

    var NativeDate = Date;
    var uniqueTimerId = 1;

    /**
     * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
     * number of milliseconds. This is used to support human-readable strings passed
     * to clock.tick()
     */
    function parseTime(str) {
        if (!str) {
            return 0;
        }

        var strings = str.split(":");
        var l = strings.length, i = l;
        var ms = 0, parsed;

        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
            throw new Error("tick only understands numbers and 'h:m:s'");
        }

        while (i--) {
            parsed = parseInt(strings[i], 10);

            if (parsed >= 60) {
                throw new Error("Invalid time " + str);
            }

            ms += parsed * Math.pow(60, (l - i - 1));
        }

        return ms * 1000;
    }

    /**
     * Used to grok the `now` parameter to createClock.
     */
    function getEpoch(epoch) {
        if (!epoch) { return 0; }
        if (typeof epoch.getTime === "function") { return epoch.getTime(); }
        if (typeof epoch === "number") { return epoch; }
        throw new TypeError("now should be milliseconds since UNIX epoch");
    }

    function inRange(from, to, timer) {
        return timer && timer.callAt >= from && timer.callAt <= to;
    }

    function mirrorDateProperties(target, source) {
        var prop;

        if (source.now) {
            target.now = function now() {
                return target.clock.now;
            };
        } else {
            delete target.now;
        }

        if (source.toSource) {
            target.toSource = function toSource() {
                return source.toSource();
            };
        } else {
            delete target.toSource;
        }

        target.toString = function toString() {
            return source.toString();
        };

        target.prototype = source.prototype;
        target.parse = source.parse;
        target.UTC = source.UTC;
        target.prototype.toUTCString = source.prototype.toUTCString;

        for (prop in source) {
            if (source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }

        return target;
    }

    function createDate() {
        function ClockDate(year, month, date, hour, minute, second, ms) {
            // Defensive and verbose to avoid potential harm in passing
            // explicit undefined when user does not pass argument
            switch (arguments.length) {
            case 0:
                return new NativeDate(ClockDate.clock.now);
            case 1:
                return new NativeDate(year);
            case 2:
                return new NativeDate(year, month);
            case 3:
                return new NativeDate(year, month, date);
            case 4:
                return new NativeDate(year, month, date, hour);
            case 5:
                return new NativeDate(year, month, date, hour, minute);
            case 6:
                return new NativeDate(year, month, date, hour, minute, second);
            default:
                return new NativeDate(year, month, date, hour, minute, second, ms);
            }
        }

        return mirrorDateProperties(ClockDate, NativeDate);
    }

    function addTimer(clock, timer) {
        if (timer.func === undefined) {
            throw new Error("Callback must be provided to timer calls");
        }

        if (!clock.timers) {
            clock.timers = {};
        }

        timer.id = uniqueTimerId++;
        timer.createdAt = clock.now;
        timer.callAt = clock.now + (timer.delay || (clock.duringTick ? 1 : 0));

        clock.timers[timer.id] = timer;

        if (addTimerReturnsObject) {
            return {
                id: timer.id,
                ref: NOOP,
                unref: NOOP
            };
        }

        return timer.id;
    }

    function compareTimers(a, b) {
        // Sort first by absolute timing
        if (a.callAt < b.callAt) {
            return -1;
        }
        if (a.callAt > b.callAt) {
            return 1;
        }

        // Sort next by immediate, immediate timers take precedence
        if (a.immediate && !b.immediate) {
            return -1;
        }
        if (!a.immediate && b.immediate) {
            return 1;
        }

        // Sort next by creation time, earlier-created timers take precedence
        if (a.createdAt < b.createdAt) {
            return -1;
        }
        if (a.createdAt > b.createdAt) {
            return 1;
        }

        // Sort next by id, lower-id timers take precedence
        if (a.id < b.id) {
            return -1;
        }
        if (a.id > b.id) {
            return 1;
        }

        // As timer ids are unique, no fallback `0` is necessary
    }

    function firstTimerInRange(clock, from, to) {
        var timers = clock.timers,
            timer = null,
            id,
            isInRange;

        for (id in timers) {
            if (timers.hasOwnProperty(id)) {
                isInRange = inRange(from, to, timers[id]);

                if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) {
                    timer = timers[id];
                }
            }
        }

        return timer;
    }

    function callTimer(clock, timer) {
        var exception;

        if (typeof timer.interval === "number") {
            clock.timers[timer.id].callAt += timer.interval;
        } else {
            delete clock.timers[timer.id];
        }

        try {
            if (typeof timer.func === "function") {
                timer.func.apply(null, timer.args);
            } else {
                eval(timer.func);
            }
        } catch (e) {
            exception = e;
        }

        if (!clock.timers[timer.id]) {
            if (exception) {
                throw exception;
            }
            return;
        }

        if (exception) {
            throw exception;
        }
    }

    function uninstall(clock, target) {
        var method,
            i,
            l;

        for (i = 0, l = clock.methods.length; i < l; i++) {
            method = clock.methods[i];

            if (target[method].hadOwnProperty) {
                target[method] = clock["_" + method];
            } else {
                try {
                    delete target[method];
                } catch (ignore) {}
            }
        }

        // Prevent multiple executions which will completely remove these props
        clock.methods = [];
    }

    function hijackMethod(target, method, clock) {
        var prop;

        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
        clock["_" + method] = target[method];

        if (method === "Date") {
            var date = mirrorDateProperties(clock[method], target[method]);
            target[method] = date;
        } else {
            target[method] = function () {
                return clock[method].apply(clock, arguments);
            };

            for (prop in clock[method]) {
                if (clock[method].hasOwnProperty(prop)) {
                    target[method][prop] = clock[method][prop];
                }
            }
        }

        target[method].clock = clock;
    }

    var timers = {
        setTimeout: setTimeout,
        clearTimeout: clearTimeout,
        setImmediate: global.setImmediate,
        clearImmediate: global.clearImmediate,
        setInterval: setInterval,
        clearInterval: clearInterval,
        Date: Date
    };

    var keys = Object.keys || function (obj) {
        var ks = [],
            key;

        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                ks.push(key);
            }
        }

        return ks;
    };

    exports.timers = timers;

    function createClock(now) {
        var clock = {
            now: getEpoch(now),
            timeouts: {},
            Date: createDate()
        };

        clock.Date.clock = clock;

        clock.setTimeout = function setTimeout(func, timeout) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 2),
                delay: timeout
            });
        };

        clock.clearTimeout = function clearTimeout(timerId) {
            if (!timerId) {
                // null appears to be allowed in most browsers, and appears to be
                // relied upon by some libraries, like Bootstrap carousel
                return;
            }

            if (!clock.timers) {
                clock.timers = [];
            }

            // in Node, timerId is an object with .ref()/.unref(), and
            // its .id field is the actual timer id.
            if (typeof timerId === "object") {
                timerId = timerId.id;
            }

            if (clock.timers.hasOwnProperty(timerId)) {
                delete clock.timers[timerId];
            }
        };

        clock.setInterval = function setInterval(func, timeout) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 2),
                delay: timeout,
                interval: timeout
            });
        };

        clock.clearInterval = function clearInterval(timerId) {
            clock.clearTimeout(timerId);
        };

        clock.setImmediate = function setImmediate(func) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 1),
                immediate: true
            });
        };

        clock.clearImmediate = function clearImmediate(timerId) {
            clock.clearTimeout(timerId);
        };

        clock.tick = function tick(ms) {
            ms = typeof ms === "number" ? ms : parseTime(ms);
            var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
            var timer = firstTimerInRange(clock, tickFrom, tickTo);

            clock.duringTick = true;

            var firstException;
            while (timer && tickFrom <= tickTo) {
                if (clock.timers[timer.id]) {
                    tickFrom = clock.now = timer.callAt;
                    try {
                        callTimer(clock, timer);
                    } catch (e) {
                        firstException = firstException || e;
                    }
                }

                timer = firstTimerInRange(clock, previous, tickTo);
                previous = tickFrom;
            }

            clock.duringTick = false;
            clock.now = tickTo;

            if (firstException) {
                throw firstException;
            }

            return clock.now;
        };

        clock.reset = function reset() {
            clock.timers = {};
        };

        return clock;
    }
    exports.createClock = createClock;

    function detectKnownFailSituation(methods) {
        if (methods.indexOf("Date") < 0) { return; }

        if (methods.indexOf("setTimeout") < 0) {
            throw new Error("Native setTimeout will not work when Date is faked");
        }

        if (methods.indexOf("setImmediate") < 0) {
            throw new Error("Native setImmediate will not work when Date is faked");
        }
    }

    exports.install = function install(target, now, toFake) {
        var i,
            l;

        if (typeof target === "number") {
            toFake = now;
            now = target;
            target = null;
        }

        if (!target) {
            target = global;
        }

        var clock = createClock(now);

        clock.uninstall = function () {
            uninstall(clock, target);
        };

        clock.methods = toFake || [];

        if (clock.methods.length === 0) {
            clock.methods = keys(timers);
        }

        detectKnownFailSituation(clock.methods);

        for (i = 0, l = clock.methods.length; i < l; i++) {
            hijackMethod(target, clock.methods[i], clock);
        }

        return clock;
    };

}(global || this));
<commit_msg>Fix Sinon.JS issue 624<commit_after>/*global global*/
/**
 * @author Christian Johansen (christian@cjohansen.no) and contributors
 * @license BSD
 *
 * Copyright (c) 2010-2014 Christian Johansen
 */

(function (global) {
    "use strict";

    // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
    // browsers, a number.
    // see https://github.com/cjohansen/Sinon.JS/pull/436

    var NOOP = function () { return undefined; };
    var timeoutResult = setTimeout(NOOP, 0);
    var addTimerReturnsObject = typeof timeoutResult === "object";
    clearTimeout(timeoutResult);

    var NativeDate = Date;
    var uniqueTimerId = 1;

    /**
     * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
     * number of milliseconds. This is used to support human-readable strings passed
     * to clock.tick()
     */
    function parseTime(str) {
        if (!str) {
            return 0;
        }

        var strings = str.split(":");
        var l = strings.length, i = l;
        var ms = 0, parsed;

        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
            throw new Error("tick only understands numbers and 'h:m:s'");
        }

        while (i--) {
            parsed = parseInt(strings[i], 10);

            if (parsed >= 60) {
                throw new Error("Invalid time " + str);
            }

            ms += parsed * Math.pow(60, (l - i - 1));
        }

        return ms * 1000;
    }

    /**
     * Used to grok the `now` parameter to createClock.
     */
    function getEpoch(epoch) {
        if (!epoch) { return 0; }
        if (typeof epoch.getTime === "function") { return epoch.getTime(); }
        if (typeof epoch === "number") { return epoch; }
        throw new TypeError("now should be milliseconds since UNIX epoch");
    }

    function inRange(from, to, timer) {
        return timer && timer.callAt >= from && timer.callAt <= to;
    }

    function mirrorDateProperties(target, source) {
        var prop;
        for (prop in source) {
            if (source.hasOwnProperty(prop)) {
                target[prop] = source[prop];
            }
        }

        // set special now implementation
        if (source.now) {
            target.now = function now() {
                return target.clock.now;
            };
        } else {
            delete target.now;
        }

        // set special toSource implementation
        if (source.toSource) {
            target.toSource = function toSource() {
                return source.toSource();
            };
        } else {
            delete target.toSource;
        }

        // set special toString implementation
        target.toString = function toString() {
            return source.toString();
        };

        target.prototype = source.prototype;
        target.parse = source.parse;
        target.UTC = source.UTC;
        target.prototype.toUTCString = source.prototype.toUTCString;

        return target;
    }

    function createDate() {
        function ClockDate(year, month, date, hour, minute, second, ms) {
            // Defensive and verbose to avoid potential harm in passing
            // explicit undefined when user does not pass argument
            switch (arguments.length) {
            case 0:
                return new NativeDate(ClockDate.clock.now);
            case 1:
                return new NativeDate(year);
            case 2:
                return new NativeDate(year, month);
            case 3:
                return new NativeDate(year, month, date);
            case 4:
                return new NativeDate(year, month, date, hour);
            case 5:
                return new NativeDate(year, month, date, hour, minute);
            case 6:
                return new NativeDate(year, month, date, hour, minute, second);
            default:
                return new NativeDate(year, month, date, hour, minute, second, ms);
            }
        }

        return mirrorDateProperties(ClockDate, NativeDate);
    }

    function addTimer(clock, timer) {
        if (timer.func === undefined) {
            throw new Error("Callback must be provided to timer calls");
        }

        if (!clock.timers) {
            clock.timers = {};
        }

        timer.id = uniqueTimerId++;
        timer.createdAt = clock.now;
        timer.callAt = clock.now + (timer.delay || (clock.duringTick ? 1 : 0));

        clock.timers[timer.id] = timer;

        if (addTimerReturnsObject) {
            return {
                id: timer.id,
                ref: NOOP,
                unref: NOOP
            };
        }

        return timer.id;
    }

    function compareTimers(a, b) {
        // Sort first by absolute timing
        if (a.callAt < b.callAt) {
            return -1;
        }
        if (a.callAt > b.callAt) {
            return 1;
        }

        // Sort next by immediate, immediate timers take precedence
        if (a.immediate && !b.immediate) {
            return -1;
        }
        if (!a.immediate && b.immediate) {
            return 1;
        }

        // Sort next by creation time, earlier-created timers take precedence
        if (a.createdAt < b.createdAt) {
            return -1;
        }
        if (a.createdAt > b.createdAt) {
            return 1;
        }

        // Sort next by id, lower-id timers take precedence
        if (a.id < b.id) {
            return -1;
        }
        if (a.id > b.id) {
            return 1;
        }

        // As timer ids are unique, no fallback `0` is necessary
    }

    function firstTimerInRange(clock, from, to) {
        var timers = clock.timers,
            timer = null,
            id,
            isInRange;

        for (id in timers) {
            if (timers.hasOwnProperty(id)) {
                isInRange = inRange(from, to, timers[id]);

                if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) {
                    timer = timers[id];
                }
            }
        }

        return timer;
    }

    function callTimer(clock, timer) {
        var exception;

        if (typeof timer.interval === "number") {
            clock.timers[timer.id].callAt += timer.interval;
        } else {
            delete clock.timers[timer.id];
        }

        try {
            if (typeof timer.func === "function") {
                timer.func.apply(null, timer.args);
            } else {
                eval(timer.func);
            }
        } catch (e) {
            exception = e;
        }

        if (!clock.timers[timer.id]) {
            if (exception) {
                throw exception;
            }
            return;
        }

        if (exception) {
            throw exception;
        }
    }

    function uninstall(clock, target) {
        var method,
            i,
            l;

        for (i = 0, l = clock.methods.length; i < l; i++) {
            method = clock.methods[i];

            if (target[method].hadOwnProperty) {
                target[method] = clock["_" + method];
            } else {
                try {
                    delete target[method];
                } catch (ignore) {}
            }
        }

        // Prevent multiple executions which will completely remove these props
        clock.methods = [];
    }

    function hijackMethod(target, method, clock) {
        var prop;

        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
        clock["_" + method] = target[method];

        if (method === "Date") {
            var date = mirrorDateProperties(clock[method], target[method]);
            target[method] = date;
        } else {
            target[method] = function () {
                return clock[method].apply(clock, arguments);
            };

            for (prop in clock[method]) {
                if (clock[method].hasOwnProperty(prop)) {
                    target[method][prop] = clock[method][prop];
                }
            }
        }

        target[method].clock = clock;
    }

    var timers = {
        setTimeout: setTimeout,
        clearTimeout: clearTimeout,
        setImmediate: global.setImmediate,
        clearImmediate: global.clearImmediate,
        setInterval: setInterval,
        clearInterval: clearInterval,
        Date: Date
    };

    var keys = Object.keys || function (obj) {
        var ks = [],
            key;

        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                ks.push(key);
            }
        }

        return ks;
    };

    exports.timers = timers;

    function createClock(now) {
        var clock = {
            now: getEpoch(now),
            timeouts: {},
            Date: createDate()
        };

        clock.Date.clock = clock;

        clock.setTimeout = function setTimeout(func, timeout) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 2),
                delay: timeout
            });
        };

        clock.clearTimeout = function clearTimeout(timerId) {
            if (!timerId) {
                // null appears to be allowed in most browsers, and appears to be
                // relied upon by some libraries, like Bootstrap carousel
                return;
            }

            if (!clock.timers) {
                clock.timers = [];
            }

            // in Node, timerId is an object with .ref()/.unref(), and
            // its .id field is the actual timer id.
            if (typeof timerId === "object") {
                timerId = timerId.id;
            }

            if (clock.timers.hasOwnProperty(timerId)) {
                delete clock.timers[timerId];
            }
        };

        clock.setInterval = function setInterval(func, timeout) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 2),
                delay: timeout,
                interval: timeout
            });
        };

        clock.clearInterval = function clearInterval(timerId) {
            clock.clearTimeout(timerId);
        };

        clock.setImmediate = function setImmediate(func) {
            return addTimer(clock, {
                func: func,
                args: Array.prototype.slice.call(arguments, 1),
                immediate: true
            });
        };

        clock.clearImmediate = function clearImmediate(timerId) {
            clock.clearTimeout(timerId);
        };

        clock.tick = function tick(ms) {
            ms = typeof ms === "number" ? ms : parseTime(ms);
            var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
            var timer = firstTimerInRange(clock, tickFrom, tickTo);

            clock.duringTick = true;

            var firstException;
            while (timer && tickFrom <= tickTo) {
                if (clock.timers[timer.id]) {
                    tickFrom = clock.now = timer.callAt;
                    try {
                        callTimer(clock, timer);
                    } catch (e) {
                        firstException = firstException || e;
                    }
                }

                timer = firstTimerInRange(clock, previous, tickTo);
                previous = tickFrom;
            }

            clock.duringTick = false;
            clock.now = tickTo;

            if (firstException) {
                throw firstException;
            }

            return clock.now;
        };

        clock.reset = function reset() {
            clock.timers = {};
        };

        return clock;
    }
    exports.createClock = createClock;

    function detectKnownFailSituation(methods) {
        if (methods.indexOf("Date") < 0) { return; }

        if (methods.indexOf("setTimeout") < 0) {
            throw new Error("Native setTimeout will not work when Date is faked");
        }

        if (methods.indexOf("setImmediate") < 0) {
            throw new Error("Native setImmediate will not work when Date is faked");
        }
    }

    exports.install = function install(target, now, toFake) {
        var i,
            l;

        if (typeof target === "number") {
            toFake = now;
            now = target;
            target = null;
        }

        if (!target) {
            target = global;
        }

        var clock = createClock(now);

        clock.uninstall = function () {
            uninstall(clock, target);
        };

        clock.methods = toFake || [];

        if (clock.methods.length === 0) {
            clock.methods = keys(timers);
        }

        detectKnownFailSituation(clock.methods);

        for (i = 0, l = clock.methods.length; i < l; i++) {
            hijackMethod(target, clock.methods[i], clock);
        }

        return clock;
    };

}(global || this));
<|endoftext|>


<commit_before>function SNotification(opts) {
	return $.webos.notification(opts);
}
SNotification.element = $('

', { 'class': 'notifications-area' }).css('display', 'none').appendTo(W.UserInterface.current.element);
SNotification.container = $('

', { 'class': 'notification-container' }).appendTo(SNotification.element);
SNotification.indicators = $('

').appendTo(SNotification.element);
SNotification.showContainer = function() {
	SNotification.showedStack++;
	if (SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = true;
	SNotification.element.stop().fadeIn('fast');
};
SNotification.autoShowContainer = function() {
	if (SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = true;
	SNotification.element.stop().fadeIn('fast');
};
SNotification.hideContainer = function() {
	SNotification.showedStack = (SNotification.showedStack > 0) ? SNotification.showedStack - 1 : 0;
	if (SNotification.showedStack > 0 || !SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = false;
	SNotification.element.stop().fadeOut('fast');
};
SNotification.autoHideContainer = function() {
	if (SNotification.showedStack > 0 || !SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = false;
	SNotification.element.stop().fadeOut('fast');
};
SNotification.isContainerVisible = function() {
	return SNotification.element.is(':visible');
};
SNotification.showedStack = 0;

$(window).mousemove(function(e) {
	if (e.pageX <= $(document).width() - 3 || e.pageY <= $(document).height() - 3) {
		return;
	}

	if (SNotification.isContainerVisible()) {
		return;
	}

	if (SNotification.showed) {
		return;
	}

	SNotification.autoShowContainer();
});
SNotification.element.mouseleave(function() {
	if (SNotification.showed) {
		var timer = setTimeout(function() {
			SNotification.autoHideContainer();
		}, 700);
		SNotification.element.one('mouseenter', function() {
			clearTimeout(timer);
		});
	}
});

//Notification
var notificationProperties = $.webos.extend($.webos.properties.get('container'), {
	options: {
		title: 'Message',
		message: '',
		icon: new SIcon('/usr/share/images/gnome/light.png'),
		life: 7,
		buttons: []
	},
	_name: 'notification',
	_create: function() {
		var that = this;

		this.options._components.header = $('

', { 'class': 'header' }).appendTo(this.element);
		$('', { src: SIcon.toIcon(this.options.icon).realpath(24), alt: '', 'class': 'icon' }).appendTo(this.options._components.header);
		$('').html(this.options.title+' : ').appendTo(this.options._components.header);
		this.options._components.details = $('', { 'class': 'details' }).html(this.options.message).appendTo(this.options._components.header);
		this.options._components.content = $('

', { 'class': 'content' }).hide().appendTo(this.element);
		this.options._components.message = $('

', { 'class': 'message' }).html(this.options.message).appendTo(this.options._components.content);

		if (this.options.buttons.length > 0) {
			var buttonContainer = $.w.buttonContainer().appendTo(this.options._components.content);
			for (var i = 0; i < this.options.buttons.length; i++) {
				this.options.buttons[i].appendTo(buttonContainer);
			}
		}

		this.element.hover(function() {
			clearTimeout(that.options._timer);
			that.options._components.details.stop().fadeOut('fast');
			that.options._components.content.stop().slideDown('fast');
		}, function() {
			that.options._components.details.stop().fadeIn('fast');
			that.options._components.content.stop().slideUp('fast');
			that._startTimer();
		}).click(function(e) {
			that.dismiss();
		});

		if (SNotification.container.children().length > 0) {
			var waitForDismissFn = function(e) {
				if (typeof e != 'undefined') {
					SNotification.container.unbind('notificationdismiss', waitForDismissFn);
				}
				if (typeof e == 'undefined' || SNotification.container.children().not(e.target).length > 0) {
					SNotification.container.bind('notificationdismiss', waitForDismissFn);
				} else {
					that._show();
				}
			};
			waitForDismissFn();
		} else {
			that._show();
		}
	},
	_show: function() {
		SNotification.showContainer();

		this.element.appendTo(SNotification.container);

		var height = this.element.outerHeight();
		this.element.css('top', height).animate({
			top: '-='+height
		}, 'fast');

		this._startTimer();
	},
	_startTimer: function() {
		var that = this;
		this.options._timer = setTimeout(function() {
			that.dismiss();
		}, this.options.life * 1000);
	},
	dismiss: function() {
		var that = this;

		this.element.animate({
			top: '+='+this.element.outerHeight()
		}, 'fast', function() {
			SNotification.hideContainer();
			that._trigger('dismiss');
			that.element.remove();
		});
	}
});
$.webos.widget('notification', notificationProperties);

$.webos.notification = function(options) {
	return $('

').notification(options);
};

function SAppIndicator(options) {
	this.options = options;

	var that = this;

	this.element = $('

').appendTo(SNotification.indicators);
	var indicator = $('

', { 'class': 'indicator' }).appendTo(this.element);
	$('', { src: SIcon.toIcon(options.icon).realpath(22), 'class': 'icon' }).appendTo(indicator);
	$('', { 'class': 'title' }).html(options.title).appendTo(indicator);
	var menu;
	if (typeof options.menu != 'undefined') {
		menu = options.menu.appendTo(this.element);
	} else {
		menu = $('

').appendTo(this.element);
	}

	this.remove = function() {
		this.element.remove();
	};

	if (typeof options.click != 'undefined') {
		indicator.click(options.click);
	}

	if (!SNotification.isContainerVisible()) {
		SNotification.showContainer();
		var timer = setTimeout(function() {
			if (SNotification.showed) {
				SNotification.hideContainer();
			}
		}, 2000);
		SNotification.element.one('mouseenter', function() {
			clearTimeout(timer);
			SNotification.showed++;
		});
		SNotification.showed--;
	}

	indicator.css('width', '22px').mouseenter(function() {
		if (indicator.is('.expanded')) {
			return;
		}
		SNotification.container.children('li').children('.indicator.expanded').removeClass('expanded').stop().animate({
			width: '22px'
		}, 'fast');
		indicator.addClass('expanded').css('width', 'auto');
		var width = indicator.width();
		indicator.css('width', '22px').stop().animate({
			width: width
		}, 'fast');
	});

	indicator.click(function(e) {
		if (that.element.children('ul').children().length > 0) {
			var hideMenuFn = function() {
				if (!$.fx.off) {
					menu.animate({
						bottom: '+=20',
						opacity: 0
					}, 'fast', function() {
						$(this).hide();
					});
				} else {
					menu.hide();
				}
				that.element.removeClass('active');

				SNotification.showed++;
			};

			that.element.toggleClass('active');
			if (that.element.is('.active')) {
				var position = that.element.offset();
				var subMenuPosition = {
					bottom: (position.top - $(document).height()) + that.element.outerHeight() + 23,
					left: position.left
				};
				menu.css(subMenuPosition).show();

				var subMenuOffset = menu.offset();
				var maxX = subMenuOffset.left + (menu.outerWidth() + menu.outerWidth(true)) / 2;

				if(maxX > $(document).width()) { // Si le menu est trop a droite, on le decale a gauche
					subMenuPosition.left = subMenuPosition.left - (maxX - $(document).width());
					menu.css('left', subMenuPosition.left);
				}

				//Effets
				if (!$.fx.off) {
					menu.css({ top: subMenuPosition.top + 20, opacity: 0 }).animate({
						bottom: '+=20',
						opacity: 1
					}, 'fast');
				} else {
					menu.css('opacity', 1);
				}

				$(document).one('click', function() {
					$(document).one('click', function() {
						hideMenuFn();
					});
				});

				SNotification.showed--;
			} else {
				hideMenuFn();
			}
		}
	});
}

function SIndicator(item) {
	item.appendTo(SIndicator.container);

	this.remove = function() {
		item.remove();
	};
}

SIndicator.container = $('

', { 'class': 'menu' });<commit_msg>Resolution d'un bug lors de l'enchainement de deux notifications.<commit_after>function SNotification(opts) {
	return $.webos.notification(opts);
}
SNotification.element = $('

', { 'class': 'notifications-area' }).css('display', 'none').appendTo(W.UserInterface.current.element);
SNotification.container = $('

', { 'class': 'notification-container' }).appendTo(SNotification.element);
SNotification.indicators = $('

').appendTo(SNotification.element);
SNotification.showContainer = function() {
	SNotification.showedStack++;
	if (SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = true;
	SNotification.element.stop().fadeIn('fast');
};
SNotification.autoShowContainer = function() {
	if (SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = true;
	SNotification.element.stop().fadeIn('fast');
};
SNotification.hideContainer = function() {
	SNotification.showedStack = (SNotification.showedStack > 0) ? SNotification.showedStack - 1 : 0;
	if (SNotification.showedStack > 0 || !SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = false;
	SNotification.element.stop().fadeOut('fast');
};
SNotification.autoHideContainer = function() {
	if (SNotification.showedStack > 0 || !SNotification.isContainerVisible()) {
		return;
	}
	SNotification.showed = false;
	SNotification.element.stop().fadeOut('fast');
};
SNotification.isContainerVisible = function() {
	return SNotification.element.is(':visible');
};
SNotification.showedStack = 0;

$(window).mousemove(function(e) {
	if (e.pageX <= $(document).width() - 3 || e.pageY <= $(document).height() - 3) {
		return;
	}

	if (SNotification.isContainerVisible()) {
		return;
	}

	if (SNotification.showed) {
		return;
	}

	SNotification.autoShowContainer();
});
SNotification.element.mouseleave(function() {
	if (SNotification.showed) {
		var timer = setTimeout(function() {
			SNotification.autoHideContainer();
		}, 700);
		SNotification.element.one('mouseenter', function() {
			clearTimeout(timer);
		});
	}
});

//Notification
var notificationProperties = $.webos.extend($.webos.properties.get('container'), {
	options: {
		title: 'Message',
		message: '',
		icon: new SIcon('/usr/share/images/gnome/light.png'),
		life: 7,
		buttons: []
	},
	_name: 'notification',
	_create: function() {
		var that = this;

		this.options._components.header = $('

', { 'class': 'header' }).appendTo(this.element);
		$('', { src: SIcon.toIcon(this.options.icon).realpath(24), alt: '', 'class': 'icon' }).appendTo(this.options._components.header);
		$('').html(this.options.title+' : ').appendTo(this.options._components.header);
		this.options._components.details = $('', { 'class': 'details' }).html(this.options.message).appendTo(this.options._components.header);
		this.options._components.content = $('

', { 'class': 'content' }).hide().appendTo(this.element);
		this.options._components.message = $('

', { 'class': 'message' }).html(this.options.message).appendTo(this.options._components.content);

		if (this.options.buttons.length > 0) {
			var buttonContainer = $.w.buttonContainer().appendTo(this.options._components.content);
			for (var i = 0; i < this.options.buttons.length; i++) {
				this.options.buttons[i].appendTo(buttonContainer);
			}
		}

		this.element.hover(function() {
			clearTimeout(that.options._timer);
			that.options._components.details.stop().fadeOut('fast');
			that.options._components.content.stop().slideDown('fast');
		}, function() {
			that.options._components.details.stop().fadeIn('fast');
			that.options._components.content.stop().slideUp('fast');
			that._startTimer();
		}).click(function(e) {
			that.dismiss();
		});

		if (SNotification.container.children().length > 0) {
			var waitForDismissFn = function(e) {
				if (!e) {
					SNotification.container.bind('notificationdismiss', waitForDismissFn);
				} else if (SNotification.container.children().not(e.target).length == 0) {
					SNotification.container.unbind('notificationdismiss', waitForDismissFn);
					that._show();
				}
			};
			waitForDismissFn();
		} else {
			that._show();
		}
	},
	_show: function() {
		SNotification.showContainer();

		this.element.appendTo(SNotification.container);

		var height = this.element.outerHeight();
		this.element.css('top', height).animate({
			top: '-='+height
		}, 'fast');

		this._startTimer();
	},
	_startTimer: function() {
		var that = this;
		this.options._timer = setTimeout(function() {
			that.dismiss();
		}, this.options.life * 1000);
	},
	dismiss: function() {
		var that = this;

		this.element.animate({
			top: '+='+this.element.outerHeight()
		}, 'fast', function() {
			that._trigger('dismiss');
			that.element.remove();
			SNotification.hideContainer();
		});
	}
});
$.webos.widget('notification', notificationProperties);

$.webos.notification = function(options) {
	return $('

').notification(options);
};

function SAppIndicator(options) {
	this.options = options;

	var that = this;

	this.element = $('

').appendTo(SNotification.indicators);
	var indicator = $('

', { 'class': 'indicator' }).appendTo(this.element);
	$('', { src: SIcon.toIcon(options.icon).realpath(22), 'class': 'icon' }).appendTo(indicator);
	$('', { 'class': 'title' }).html(options.title).appendTo(indicator);
	var menu;
	if (typeof options.menu != 'undefined') {
		menu = options.menu.appendTo(this.element);
	} else {
		menu = $('

').appendTo(this.element);
	}

	this.remove = function() {
		this.element.remove();
	};

	if (typeof options.click != 'undefined') {
		indicator.click(options.click);
	}

	if (!SNotification.isContainerVisible()) {
		SNotification.showContainer();
		var timer = setTimeout(function() {
			if (SNotification.showed) {
				SNotification.hideContainer();
			}
		}, 2000);
		SNotification.element.one('mouseenter', function() {
			clearTimeout(timer);
			SNotification.showed++;
		});
		SNotification.showed--;
	}

	indicator.css('width', '22px').mouseenter(function() {
		if (indicator.is('.expanded')) {
			return;
		}
		SNotification.container.children('li').children('.indicator.expanded').removeClass('expanded').stop().animate({
			width: '22px'
		}, 'fast');
		indicator.addClass('expanded').css('width', 'auto');
		var width = indicator.width();
		indicator.css('width', '22px').stop().animate({
			width: width
		}, 'fast');
	});

	indicator.click(function(e) {
		if (that.element.children('ul').children().length > 0) {
			var hideMenuFn = function() {
				if (!$.fx.off) {
					menu.animate({
						bottom: '+=20',
						opacity: 0
					}, 'fast', function() {
						$(this).hide();
					});
				} else {
					menu.hide();
				}
				that.element.removeClass('active');

				SNotification.showed++;
			};

			that.element.toggleClass('active');
			if (that.element.is('.active')) {
				var position = that.element.offset();
				var subMenuPosition = {
					bottom: (position.top - $(document).height()) + that.element.outerHeight() + 23,
					left: position.left
				};
				menu.css(subMenuPosition).show();

				var subMenuOffset = menu.offset();
				var maxX = subMenuOffset.left + (menu.outerWidth() + menu.outerWidth(true)) / 2;

				if(maxX > $(document).width()) { // Si le menu est trop a droite, on le decale a gauche
					subMenuPosition.left = subMenuPosition.left - (maxX - $(document).width());
					menu.css('left', subMenuPosition.left);
				}

				//Effets
				if (!$.fx.off) {
					menu.css({ top: subMenuPosition.top + 20, opacity: 0 }).animate({
						bottom: '+=20',
						opacity: 1
					}, 'fast');
				} else {
					menu.css('opacity', 1);
				}

				$(document).one('click', function() {
					$(document).one('click', function() {
						hideMenuFn();
					});
				});

				SNotification.showed--;
			} else {
				hideMenuFn();
			}
		}
	});
}

function SIndicator(item) {
	item.appendTo(SIndicator.container);

	this.remove = function() {
		item.remove();
	};
}

SIndicator.container = $('

', { 'class': 'menu' });<|endoftext|>


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

const argv = require('minimist')(process.argv.slice(2));
const shellUtils = require('./../lib/shell-utils');

let sleep = 'sleep 5';
if (process.platform === 'win32') sleep = 'sleep -s 5';

let blueprint = 'https://github.com/takeoff-env/takeoff-blueprint-basic.git';
let environment = 'takeoff';

if (argv.blueprint) {
    blueprint = argv.blueprint;
}

if (argv.env) {
    environment = argv.env;
}

const commands = [
    { cmd: `mkdir -p envs/${environment}`, message: 'Creating environment' },
    { cmd: `git clone ${blueprint} envs/${environment}`, message: 'Cloning default environment' },
    argv.lerna ? { cmd: `lerna bootstrap`, message: 'Bootstrapping environments', cwd: `envs/${environment}` } : undefined,
    {
        cmd: `docker-compose -f docker/docker-compose.yml build --no-cache`,
        message: 'Running Docker Compose Build',
        cwd: `envs/${environment}`
    },
    {
        cmd: `docker-compose -f docker/docker-compose.yml up -d db`,
        message: 'Triggering database creation',
        cwd: `envs/${environment}`
    },
    { cmd: `${sleep}`, message: 'Waiting for database' },
    {
        cmd: `docker-compose -f docker/docker-compose.yml stop db`,
        message: 'Shutting down database',
        cwd: `envs/${environment}`
    }
].filter(f => f);

shellUtils.series(
    commands,
    error => {
        if (error) {
            console.log(error);
            return console.error(`[Build]: ${error.message}`.trim());
        }
        console.log('Docker Compose Build Done');
    },
    data => {
        if (argv.v) {
            console.log(`[Build]: ${data}`.trim());
        }
    },
    data => {
        console.log(`[Build]: ${data}`.trim());
    }
);
<commit_msg>Command line improvements<commit_after>#!/usr/bin/env node

const argv = require('minimist')(process.argv.slice(2));
const shellUtils = require('./../lib/shell-utils');

let sleep = 'sleep 5';
if (process.platform === 'win32') sleep = 'sleep -s 5';

let blueprint = 'https://github.com/takeoff-env/takeoff-blueprint-basic.git';
let environment = 'takeoff';

if (argv.blueprint) {
    blueprint = argv.blueprint;
}

if (argv.env) {
    environment = argv.env;
}

const commands = [
    { cmd: `mkdir -p envs/${environment}`, message: 'Creating environment' },
    { cmd: `git clone ${blueprint} envs/${environment}`, message: 'Cloning default environment' },
    argv.submodule ? { cmd: `git submodule init`, message: `Initialising submodules`, cwd: `envs/${environment}`} : undefined,
    argv.submodule ? { cmd: `git submodule update`, message: `Cloning submodules`, cwd: `envs/${environment}`} : undefined,
    argv.lerna ? { cmd: `lerna bootstrap`, message: 'Bootstrapping environments', cwd: `envs/${environment}` } : undefined,
    {
        cmd: `docker-compose -f docker/docker-compose.yml build --no-cache`,
        message: 'Running Docker Compose Build',
        cwd: `envs/${environment}`
    },
    {
        cmd: `docker-compose -f docker/docker-compose.yml up -d db`,
        message: 'Triggering database creation',
        cwd: `envs/${environment}`
    },
    { cmd: `${sleep}`, message: 'Waiting for database' },
    {
        cmd: `docker-compose -f docker/docker-compose.yml stop db`,
        message: 'Shutting down database',
        cwd: `envs/${environment}`
    }
].filter(f => f);

shellUtils.series(
    commands,
    error => {
        if (error) {
            console.log(error);
            return console.error(`[Build]: ${error.message}`.trim());
        }
        console.log('Docker Compose Build Done');
    },
    data => {
        if (argv.v) {
            console.log(`[Build]: ${data}`.trim());
        }
    },
    data => {
        console.log(`[Build]: ${data}`.trim());
    }
);
<|endoftext|>


<commit_before>var f1 = require('f1');
var css = require('dom-style');
var on = require('dom-event');

var el = document.createElement('div');
var icon = document.createElement('div');
var line = document.createElement('div');
var text = document.createElement('div');

css( el, {

  position: 'absolute',
  width: '100px',
  height: '100px',
  left: '100px',
  top: '100px'
});

css( icon, {

  position: 'absolute',
  background: '#CAFE00',
  width: '20px',
  height: '20px'
});

css( line, {

  position: 'absolute',
  background: '#000',
  width: '100px',
  height: '1px'
});

css( text, {

  position: 'absolute'
});

text.innerHTML = 'Something';

document.body.appendChild(el);
el.appendChild(icon);
el.appendChild(line);
el.appendChild(text);

var ui = f1();

ui
.targets( {
  icon: icon,
  line: line,
  text: text
})
.states(require('./states'))
.transitions(require('./transitions'))
.parsers(require('f1-dom'))
.init('out')
.go('idle');

el.addEventListener('mouseenter', function() {

  ui.go('rollover');
});

el.addEventListener('mouseleave', function() {

  ui.go('idle');
});

el.addEventListener('mousedown', function() {

  ui.go('mousedown');
});

el.addEventListener('mouseup', function() {

  ui.go('rollover');
});<commit_msg>Added onState to dom-1<commit_after>var f1 = require('f1');
var css = require('dom-style');
var on = require('dom-event');

var el = document.createElement('div');
var icon = document.createElement('div');
var line = document.createElement('div');
var text = document.createElement('div');

css( el, {

  position: 'absolute',
  width: '100px',
  height: '100px',
  left: '100px',
  top: '100px'
});

css( icon, {

  position: 'absolute',
  background: '#CAFE00',
  width: '20px',
  height: '20px'
});

css( line, {

  position: 'absolute',
  background: '#000',
  width: '100px',
  height: '1px'
});

css( text, {

  position: 'absolute'
});

text.innerHTML = 'Something';

document.body.appendChild(el);
el.appendChild(icon);
el.appendChild(line);
el.appendChild(text);

var ui = f1({
  onState: function() {
    console.log('onState', arguments);
  }
});

ui
.targets( {
  icon: icon,
  line: line,
  text: text
})
.states(require('./states'))
.transitions(require('./transitions'))
.parsers(require('f1-dom'))
.init('out')
.go('idle');

el.addEventListener('mouseenter', function() {

  ui.go('rollover');
});

el.addEventListener('mouseleave', function() {

  ui.go('idle');
});

el.addEventListener('mousedown', function() {

  ui.go('mousedown');
});

el.addEventListener('mouseup', function() {

  ui.go('rollover');
});<|endoftext|>


<commit_before>class Person {
  constructor(first, last) {
    this.first = first;
    this.last = last;
  }

  toString() {
    return `${this.first} ${this.last}`;
  }
}

let brian = new Person('Miguel', 'Castillo');

export default brian;
<commit_msg>correct issue with exported variable name in babel example<commit_after>class Person {
  constructor(first, last) {
    this.first = first;
    this.last = last;
  }

  toString() {
    return `${this.first} ${this.last}`;
  }
}

let miguel = new Person('Miguel', 'Castillo');

export default miguel;
<|endoftext|>


<commit_before>process.stdout.write('\033c') //eslint-disableore-line
console.log('start!')
'use strict'
var Hub = require('../../lib')
// var _sc
var fs = require('fs')
  // var colors = require('colors-browserify')
var http = require('http')
var JSONStream = require('JSONStream')
var hub = new Hub({ //eslint-disable-line
  adapter: {
    inject: require('../../lib/protocol/websocket'),
    id: 'mtv',
    websocket: {
      // val: 'ws://youzi.local:3032'
    }
  },
  autoRemoveScopes: false,
  scope (scope, event, getScope) {
    //this, scope, event, getScope
    var init
    if (!this._scopes || !this._scopes[scope]) {
      init = true
    }
    var ret = getScope.apply(this, arguments)
    if( init) {
      console.log('init!', scope)
      ret.set({
        user: {
          name: scope
        }
      }, false)
    }
    return ret
  }
})

hub.set({
  shows: {
    977: {
      title: 'homie'
    },
    blurf: {
      title: 'gurk'
    }
  },
  discover: {
    carousel: {},
    lists: {
      free: {},
      popular: {},
      recommended: {},
      new: {}
    }
  },
  channels: {},
  levelready: true
}, false)

// hub.adapter.websocket.server.val = 3031

hub.levelready.is(true, function () {
  // var https = require('https')
  if (!hub.datafromjson || hub.datafromjson.val !== true) {
    setTimeout(function () {
      // console.log('start loading!')
      var count = 0
      http.request({
        host: '37.48.93.74',
        path: '/new.json',
        port: 51004,
        method: 'get',
        headers: {
          accepts: '*/*'
        }
      }, function (res) {
        // load channels
        res.pipe(JSONStream.parse('mtvData.NL.en.channels.*'))
          .on('data', function (data) {
            if (data.id) {
              // console.log('channel from json:', data.id, data)
              hub.channels.set({
                [data.id]: data
              })
              hub.channels[data.id].set({
                currentEpisode: hub.channels[data.id],
                epg: {
                  0: {
                    title: 'Dumb people unite',
                    subtitle: '20:00 - 21:00'
                  },
                  1: {
                    title: 'Friendly people unite',
                    subtitle: '21:00 - 22:00'
                  },
                  2: {
                    title: 'Shine flame',
                    subtitle: '21:00 - 22:00'
                  }
                }
              })
              if (!hub.channels.focus) {
                hub.channels.setKey('focus', hub.channels.firstChild())
              }
            } else {
              // console.log('channel from json --> no id:'.red, data)
            }
          })

        // load shows
        var showCount = 0
        res.pipe(JSONStream.parse('mtvData.NL.en.shows.*'))
          .on('data', function (data) {
            if (data.id) {
              console.log('show from json:', data.id, data.img)
                // event ofc
              data.index = showCount++
              hub.shows.set({
                [data.id]: data
              })

              hub.shows[data.id].set({
                currentEpisode: hub.shows[data.id].seasons[0].episodes[0],
                currentSeason: hub.shows[data.id].seasons[0]
              })
              hub.shows[data.id].seasons.each((season) => {
                season.episodes.each((episode) => {
                  episode.set({
                    time: Math.random(),
                    video: episode.mrss.val
                  })
                })

                season.episodes.setKey('focus', season.episodes.firstChild())
              })
              if (!hub.shows.focus) {
                hub.shows.setKey('focus', hub.shows.firstChild())
              }
            } else {
              console.log('show from json --> no id:', data)
            }
          })
          // load discover
        res.pipe(JSONStream.parse('mtvData.NL.en.discover_marquee_premium.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.carousel.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.carousel.focus) {
                hub.discover.carousel.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_marquee_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.free.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.free.focus) {
                hub.discover.lists.free.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row1_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.popular.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.popular.focus) {
                hub.discover.lists.popular.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row2_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.recommended.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.recommended.focus) {
                hub.discover.lists.recommended.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row3_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.new.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.new.focus) {
                hub.discover.lists.new.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })
        .on('end', function () {
          console.log('!!!!JSON READY!!!!')
          hub.set({ 'datafromjson': true })
          hub.adapter.websocket.server.val = 3031
        })
      }).end()
    }, 1000)
  } else {
    console.log('allready got data from the server')
    hub.adapter.websocket.server.val = 3031
  }

  var repl = require('repl')
  repl.start('> ').context.hub = hub

})<commit_msg>fixes<commit_after>process.stdout.write('\033c') //eslint-disableore-line
console.log('start!')
'use strict'
var Hub = require('../../lib')
var fs = require('fs')
var http = require('http')
var JSONStream = require('JSONStream')
var hub = new Hub({ //eslint-disable-line
  adapter: {
    inject: require('../../lib/protocol/websocket'),
    id: 'mtv',
    websocket: {}
  },
  autoRemoveScopes: false,
  scope (scope, event, getScope) {
    //this, scope, event, getScope
    var init
    if (!this._scopes || !this._scopes[scope]) {
      init = true
    }
    var ret = getScope.apply(this, arguments)
    if( init) {
      console.log('init!', scope)
      ret.set({
        user: {
          name: scope
        }
      }, false)
    }
    return ret
  }
})

hub.set({
  shows: {},
  discover: {
    carousel: {},
    lists: {
      free: {},
      popular: {},
      recommended: {},
      new: {}
    }
  },
  channels: {},
  levelready: true
}, false)

hub.levelready.is(true, function () {
  // var https = require('https')
  if (!hub.datafromjson || hub.datafromjson.val !== true) {
    setTimeout(function () {
      // console.log('start loading!')
      var count = 0
      http.request({
        host: '37.48.93.74',
        path: '/new.json',
        port: 51004,
        method: 'get',
        headers: {
          accepts: '*/*'
        }
      }, function (res) {
        // load channels
        res.pipe(JSONStream.parse('mtvData.NL.en.channels.*'))
          .on('data', function (data) {
            if (data.id) {
              // console.log('channel from json:', data.id, data)
              hub.channels.set({
                [data.id]: data
              })
              hub.channels[data.id].set({
                currentEpisode: hub.channels[data.id],
                epg: {
                  0: {
                    title: 'Dumb people unite',
                    subtitle: '20:00 - 21:00'
                  },
                  1: {
                    title: 'Friendly people unite',
                    subtitle: '21:00 - 22:00'
                  },
                  2: {
                    title: 'Shine flame',
                    subtitle: '21:00 - 22:00'
                  }
                }
              })
              if (!hub.channels.focus) {
                hub.channels.setKey('focus', hub.channels.firstChild())
              }
            } else {
              // console.log('channel from json --> no id:'.red, data)
            }
          })

        // load shows
        var showCount = 0
        res.pipe(JSONStream.parse('mtvData.NL.en.shows.*'))
          .on('data', function (data) {
            if (data.id) {
              console.log('show from json:', data.id, data.img)
                // event ofc
              data.index = showCount++
              hub.shows.set({
                [data.id]: data
              })

              hub.shows[data.id].set({
                currentEpisode: hub.shows[data.id].seasons[0].episodes[0],
                currentSeason: hub.shows[data.id].seasons[0]
              })
              hub.shows[data.id].seasons.each((season) => {
                season.episodes.each((episode) => {
                  episode.set({
                    time: Math.random(),
                    video: episode.mrss.val
                  })
                })

                season.episodes.setKey('focus', season.episodes.firstChild())
              })
              if (!hub.shows.focus) {
                hub.shows.setKey('focus', hub.shows.firstChild())
              }
            } else {
              console.log('show from json --> no id:', data)
            }
          })
          // load discover
        res.pipe(JSONStream.parse('mtvData.NL.en.discover_marquee_premium.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.carousel.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.carousel.focus) {
                hub.discover.carousel.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_marquee_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.free.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.free.focus) {
                hub.discover.lists.free.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row1_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.popular.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.popular.focus) {
                hub.discover.lists.popular.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row2_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.recommended.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.recommended.focus) {
                hub.discover.lists.recommended.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })

        res.pipe(JSONStream.parse('mtvData.NL.en.discover_row3_free.list.*'))
          .on('data', function (data) {
            // show or channel etc
            var link = data.link && data.link.split('.')
            if (link) {
              var length = link.length
              var id = link[length - 1]
              hub.discover.lists.new.set({
                [id]: hub.get(link.slice(3, length), {})
              })
              if (!hub.discover.lists.new.focus) {
                hub.discover.lists.new.setKey('focus', hub.get(link.slice(3, length), {}))
              }
            }
          })
        .on('end', function () {
          console.log('!!!!JSON READY!!!!')
          hub.set({ 'datafromjson': true })
          hub.adapter.websocket.server.val = 3031
        })
      }).end()
    }, 1000)
  } else {
    console.log('allready got data from the server')
    hub.adapter.websocket.server.val = 3031
  }

  var repl = require('repl')
  repl.start('> ').context.hub = hub

})<|endoftext|>


<commit_before>const http = require('http');
const [port] = process.argv.slice(2);

const minMoves = 1;
const moveFraction = 2;
const implodeRadiusFraction = 2;
const explodeImplodeRatio = 0.8;
const randomMovement = false;
const deterministic = false;

if (!port) {
  console.log('Pass port as command line argument...');
  process.exit(1);
}

const shuffle = (array) => {
  let arr = array.concat([]);
  if (deterministic) return arr;
  for (let i = arr.length - 1; i >= 0; i--) {
    var index = Math.floor(Math.random() * (i + 1));
    var item = arr[index];
    arr[index] = arr[i];
    arr[i] = item;
  }
  return arr;
}

const coordEq = (p, q) => p.x == q.x && p.y == q.y && p.z == q.z;

const helpers = (data) => {
  return {
    hasBomb: (p) => data.items.some(it => it.type === "BOMB" && coordEq(it, p)),
    hasPlayer: (p) => data.players.some(it => coordEq(it, p)),
    inBounds: (p) => [p.x, p.y, p.z].every(c => c >= 0 && c < data.gameInfo.edgeLength),
    me: data.players.find(p => p.name === data.currentPlayer.name)
  }
};

const explode = (tx, ty, tz, n, data) => {
  let queue = [{x: tx, y: ty, z: tz}]
  let done = [];
  let tasks = [];

  const {hasBomb, inBounds, me} = helpers(data);
  const isDone = (p) => done.some(it => coordEq(it, p));

  while(queue.length && tasks.length < n) {
    const pos = queue.shift();

    if (!hasBomb(pos)) {
      tasks.push({ task: 'BOMB', x: pos.x, y: pos.y, z: pos.z });
    }

    if (tasks.length < n) {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1}
      ].filter(p => inBounds(p) && !isDone(p) && !coordEq(p, me));
      queue = queue.concat(shuffle(neighbors));
    }

    done.push(pos);
  }

  return tasks;
};

const implode = (tx, ty, tz, n, data) => {
  let queue = [{x: tx, y: ty, z: tz, d: 0}]
  let done = [];

  const {hasBomb, inBounds, me} = helpers(data);
  const isDone = (p) => done.some(it => coordEq(it, p));
  const implodeRadius = Math.ceil(data.gameInfo.numOfTasksPerTick / implodeRadiusFraction)

  while(queue.length) {
    const pos = queue.shift();

    if (pos.d < implodeRadius) {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1, d: pos.d + 1}
      ].filter(p => inBounds(p) && !isDone(p) && !coordEq(p, me) && !hasBomb(p));
      queue = queue.concat(shuffle(neighbors));
    }

    done.push(pos);
  }

  const tasks = done.sort((a, b) => b.d - a.d).splice(0, n).map(pos => {
    return { task: 'BOMB', x: pos.x, y: pos.y, z: pos.z };
  });

  return tasks;
}

const pickTargets = (n, data) => {
  const others = data.players.filter(p => p.name != data.currentPlayer.name);
  const targets = shuffle(others)
    .splice(0, n)
    .map(t => Object.assign(t, {n: 1}));

  if (targets.length < n) {
    const left = n - targets.length;
    for (let i = 0; i < left; ++i) {
      targets[i % targets.length].n += 1;
    }
  }

  return targets;
}

const positionDesirability = (pos, data) => {
  const distSq = (a, b) => (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z)
  const bombProximityScore = data.items
    .filter(i => i.type === 'BOMB')
    .map(i => distSq(i, pos))
    .reduce((sum, x) => sum + x, 0)

  const playerProximityScore = data.players
    .filter(p => p.name != data.currentPlayer.name)
    .map(p => distSq(p, pos))
    .reduce((sum, x) => sum + x, 0)

  return bombProximityScore + playerProximityScore;
}

const moveDistance = (n, data) => {
  const {hasBomb, hasPlayer, inBounds, me} = helpers(data);

  let queue = [{x: me.x, y: me.y, z: me.z, moves: []}]
  let tasks = [];
  let done = [];
  const isDone = (p) => done.some(it => coordEq(it, p));

  while(queue.length) {
    const pos = queue.shift();

    if (pos.moves.length >= n) {
      // Desired distance reached
      return pos.moves.map(m => { return {task: 'MOVE', direction: m} }).splice(0, n);
    } else {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0, moves: pos.moves.concat(['+X'])},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0, moves: pos.moves.concat(['-X'])},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0, moves: pos.moves.concat(['+Y'])},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0, moves: pos.moves.concat(['-Y'])},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1, moves: pos.moves.concat(['+Z'])},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1, moves: pos.moves.concat(['-Z'])}
      ].filter(p => inBounds(p) && !isDone(p) && !hasBomb(p) && !hasPlayer(p));
      if (randomMovement) {
        queue = queue.concat(shuffle(neighbors));
      } else {
        const rankedNeighbors = neighbors
          .map(n => ({ x: n.x, y: n.y, z: n.z, moves: n.moves, score: positionDesirability(n, data) }))
          .sort((a, b) => b.score - a.score);
        queue = queue.concat(rankedNeighbors);
      }
    }
    done.push(pos);
  }

  // Find the longest path as fallback
  const best = done.reduce(
    (best, x) => best.moves.length < x.moves.length ? x : best,
    {moves: []})
  return best.moves.map(m => { return {task: 'MOVE', direction: m} })
}

const getDirections = (data) => {
  const numTasks = data.gameInfo.numOfTasksPerTick;
  const moves = moveDistance(Math.max(minMoves, numTasks / moveFraction), data);
  console.log("Moves:", JSON.stringify(moves))
  const targets = pickTargets(numTasks - moves.length, data);
  console.log("Targets:", JSON.stringify(targets))
  const flatMap = (xs, f) => xs.reduce((ts, x) => ts.concat(f(x)), [])
  const strategy = () => Math.random() < explodeImplodeRatio ? explode : implode;
  const tasks = moves.concat(flatMap(targets, t => strategy()(t.x, t.y, t.z, t.n, data)))
  console.log("Tasks:", JSON.stringify(tasks))
  return tasks;
};

http.createServer((req, res) => {
  if (req.method === 'POST') {
    let jsonString = '';

    req.on('data', (data) => {
      jsonString += data;
    });

    req.on('end', () => {
      const nextTickInfo = JSON.parse(jsonString);
      console.log('we got next tick info', nextTickInfo);
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(getDirections(nextTickInfo)));
    });

  }
}).listen(port);

// Console will print the message
console.log(`TeeBot running at http://127.0.0.1:${port}/`);
<commit_msg>Added teebot parametrization, non-random targeting and bomb spread<commit_after>const http = require('http');
const [port] = process.argv.slice(2);

const arg = (n, defaultValue) => n >= process.argv.length ? defaultValue : process.argv[n];
const parseBool = (x) => parseInt(x) ? true : false;

const minMoves = parseInt(arg(3, 1));
const moveFraction = parseInt(arg(4, 2));
const implodeRadiusFraction = parseInt(arg(5, 2));
const explodeImplodeRatio = parseFloat(arg(6, 0.8));
const randomMovement = parseBool(arg(7, 0));
const randomTargeting = parseBool(arg(8, 0));
const randomSpread = parseBool(arg(9, 0));
const deterministic = parseBool(arg(10, 0));
const verbose = parseBool(arg(11, 0));

if (!port) {
  console.log('Pass port as command line argument...');
  process.exit(1);
}

const shuffle = (array) => {
  let arr = array.concat([]);
  if (deterministic) return arr;
  for (let i = arr.length - 1; i >= 0; i--) {
    var index = Math.floor(Math.random() * (i + 1));
    var item = arr[index];
    arr[index] = arr[i];
    arr[i] = item;
  }
  return arr;
}

const coordEq = (p, q) => p.x == q.x && p.y == q.y && p.z == q.z;

const helpers = (data) => {
  return {
    hasBomb: (p) => data.items.some(it => it.type === "BOMB" && coordEq(it, p)),
    hasPlayer: (p) => data.players.some(it => coordEq(it, p)),
    inBounds: (p) => [p.x, p.y, p.z].every(c => c >= 0 && c < data.gameInfo.edgeLength),
    me: data.players.find(p => p.name === data.currentPlayer.name)
  }
};

const explode = (tx, ty, tz, n, data) => {
  let queue = [{x: tx, y: ty, z: tz}]
  let done = [];
  let tasks = [];

  const {hasBomb, inBounds, me} = helpers(data);
  const isDone = (p) => done.some(it => coordEq(it, p));

  const prioritize = (xs) => {
    if(randomSpread) {
      return shuffle(xs);
    } else {
      return xs
        .map(x => Object.assign({ score: positionDesirability(x, data.currentPlayer.name, data) }, x))
        .sort((a, b) => a.score - b.score);
    }
  };

  while(queue.length && tasks.length < n) {
    const pos = queue.shift();

    if (!hasBomb(pos)) {
      tasks.push({ task: 'BOMB', x: pos.x, y: pos.y, z: pos.z });
    }

    if (tasks.length < n) {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1}
      ].filter(p => inBounds(p) && !isDone(p) && !coordEq(p, me));
      queue = queue.concat(prioritize(neighbors));
    }

    done.push(pos);
  }

  return tasks;
};

const implode = (tx, ty, tz, n, data) => {
  let queue = [{x: tx, y: ty, z: tz, d: 0}]
  let done = [];

  const {hasBomb, inBounds, me} = helpers(data);
  const isDone = (p) => done.some(it => coordEq(it, p));
  const implodeRadius = Math.ceil(data.gameInfo.numOfTasksPerTick / implodeRadiusFraction)
  const prioritize = (xs) => {
    if(randomSpread) {
      return shuffle(xs);
    } else {
      return xs
        .map(x => Object.assign({ score: positionDesirability(x, data.currentPlayer.name, data) }, x))
        .sort((a, b) => a.score - b.score);
    }
  };

  while(queue.length) {
    const pos = queue.shift();

    if (pos.d < implodeRadius) {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1, d: pos.d + 1},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1, d: pos.d + 1}
      ].filter(p => inBounds(p) && !isDone(p) && !coordEq(p, me) && !hasBomb(p));
      queue = queue.concat(prioritize(neighbors));
    }

    done.push(pos);
  }

  const tasks = done.sort((a, b) => b.d - a.d).splice(0, n).map(pos => {
    return { task: 'BOMB', x: pos.x, y: pos.y, z: pos.z };
  });

  return tasks;
}

const pickTargets = (n, data) => {
  const others = data.players.filter(p => p.name != data.currentPlayer.name);
  const prioritize = (xs) => {
    if(randomTargeting) {
      return shuffle(xs);
    } else {
      return xs
        .map(x => Object.assign({ score: positionDesirability(x, x.name, data) }, x))
        .sort((a, b) => a.score - b.score);
    }
  };
  const targets = prioritize(others)
    .splice(0, n)
    .map(t => Object.assign(t, {n: 1}));

  if (targets.length < n) {
    const left = n - targets.length;
    for (let i = 0; i < left; ++i) {
      targets[i % targets.length].n += 1;
    }
  }

  return targets;
}

const positionDesirability = (pos, player, data) => {
  const distSq = (a, b) => (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z)
  const bombProximityScore = data.items
    .filter(i => i.type === 'BOMB')
    .map(i => distSq(i, pos))
    .reduce((sum, x) => sum + x, 0)

  const playerProximityScore = data.players
    .filter(p => p.name != player)
    .map(p => distSq(p, pos))
    .reduce((sum, x) => sum + x, 0)

  return bombProximityScore + playerProximityScore;
}

const moveDistance = (n, data) => {
  const {hasBomb, hasPlayer, inBounds, me} = helpers(data);

  let queue = [{x: me.x, y: me.y, z: me.z, moves: []}]
  let tasks = [];
  let done = [];
  const isDone = (p) => done.some(it => coordEq(it, p));

  while(queue.length) {
    const pos = queue.shift();

    if (pos.moves.length >= n) {
      // Desired distance reached
      return pos.moves.map(m => { return {task: 'MOVE', direction: m} }).splice(0, n);
    } else {
      const neighbors = [
        {x: pos.x + 1, y: pos.y + 0, z: pos.z + 0, moves: pos.moves.concat(['+X'])},
        {x: pos.x - 1, y: pos.y + 0, z: pos.z + 0, moves: pos.moves.concat(['-X'])},
        {x: pos.x + 0, y: pos.y + 1, z: pos.z + 0, moves: pos.moves.concat(['+Y'])},
        {x: pos.x + 0, y: pos.y - 1, z: pos.z + 0, moves: pos.moves.concat(['-Y'])},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z + 1, moves: pos.moves.concat(['+Z'])},
        {x: pos.x + 0, y: pos.y + 0, z: pos.z - 1, moves: pos.moves.concat(['-Z'])}
      ].filter(p => inBounds(p) && !isDone(p) && !hasBomb(p) && !hasPlayer(p));
      if (randomMovement) {
        queue = queue.concat(shuffle(neighbors));
      } else {
        const rankedNeighbors = neighbors
          .map(n => Object.assign({score: positionDesirability(n, data.currentPlayer.name, data)}, n))
          .sort((a, b) => b.score - a.score);
        queue = queue.concat(rankedNeighbors);
      }
    }
    done.push(pos);
  }

  // Find the longest path as fallback
  const best = done.reduce(
    (best, x) => best.moves.length < x.moves.length ? x : best,
    {moves: []})
  return best.moves.map(m => { return {task: 'MOVE', direction: m} })
}

const getDirections = (data) => {
  const numTasks = data.gameInfo.numOfTasksPerTick;
  const moves = moveDistance(Math.max(minMoves, numTasks / moveFraction), data);
  if(verbose) console.log("Moves:", JSON.stringify(moves))
  const targets = pickTargets(numTasks - moves.length, data);
  if(verbose) console.log("Targets:", JSON.stringify(targets))
  const flatMap = (xs, f) => xs.reduce((ts, x) => ts.concat(f(x)), [])
  const strategy = () => Math.random() < explodeImplodeRatio ? explode : implode;
  const tasks = moves.concat(flatMap(targets, t => strategy()(t.x, t.y, t.z, t.n, data)))
  if(verbose) console.log("Tasks:", JSON.stringify(tasks))
  return tasks;
};

http.createServer((req, res) => {
  if (req.method === 'POST') {
    let jsonString = '';

    req.on('data', (data) => {
      jsonString += data;
    });

    req.on('end', () => {
      const nextTickInfo = JSON.parse(jsonString);
      if(verbose) console.log('we got next tick info', nextTickInfo);
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(getDirections(nextTickInfo)));
    });

  }
}).listen(port);

// Console will print the message
console.log(`TeeBot running at http://127.0.0.1:${port}/`);
console.log(`
  minMoves: ${minMoves}
  moveFraction: ${moveFraction}
  implodeRadiusFraction: ${implodeRadiusFraction}
  explodeImplodeRatio: ${explodeImplodeRatio}
  randomMovement: ${randomMovement}
  randomTargeting: ${randomTargeting}
  randomSpread: ${randomSpread}
  deterministic: ${deterministic}
`)
<|endoftext|>


<commit_before>var elf = require("../index"), sys = require("sys"), _;

var Calculator = elf.Language.clone(function () {
  this.number   ( /\d+/        )
  this.name     ( /[a-zA-Z]+/  )
  this.operator ( /\||\}|\)/)

  this.prefix   ( "+", "-"     )

  this.infixr   ( "=", 10      )

  this.infix    ( "+", "-", 10 )
  this.infix    ( "*", "/", 20 )

  this.prefix   ("{", function (node) {
    node.value  = "function";
    node.first  = this.parseUntil("|", { step: ",", meta: { type: "parameter" }, optional: true });
    node.second = this.parseUntil("}");

    return node;
  })

  this.infix  ("(", 80, function (node, first) {
    node.value  = "call";
    node.first  = first;
    node.second = this.parseUntil(")", { step: "," })

    return node;
  });

  this.stmt ("print")

  this.skip ( /\s+/ )
  this.eol  ( /\;/  )
});

Evaluator = elf.Walker.clone(function () {

  // Match unary -
  this.match ("-", [ _ ], function (env, node, left) {
    return -this.walk(left, env);
  })

  // Match binary -
  this.match ("-", [ _ , _ ], function (env, node, left, right) {
    return this.walk(left, env) - this.walk(right, env);
  })

  // Match unary +
  this.match ("+", [ _ ], function (env, node, left) {
    return +this.walk(left, env);
  })

  // Match binary +
  this.match ("+", [ _ , _ ], function (env, node, left, right) {
    return this.walk(left, env) + this.walk(right, env);
  })

  // Match binary *
  this.match ("*", function (env, node, left, right) {
    return this.walk(left, env) * this.walk(right, env);
  });

  // Match and "optimize" binary * when the right node is 2 by turning it into a left shift
  this.match ("*", [ _ , 2 ], function (env, node, left) {
    return this.walk(left, env) << 1;
  });

  // Match binary =
  this.match ("=", [ "name", _ ], function (env, node, left, right) {
    return env[left.value] = this.walk(right, env);
  });

  // Match binary /
  this.match ("/", function (env, node, left, right) {
    return this.walk(left, env) / this.walk(right, env);
  })

  // Match print statements
  this.match ("print", function (env, node, right) {
    return sys.puts(this.walk(right, env));
  })

  // Match function statements
  this.match("function", function (env, node, params, body) {
    var self = this;
    return function () {
      var args = arguments;
      env = env.clone();
      params.forEach(function (param, idx) { env[self.walk(param, env)] = args[idx]; }, self);
      return self.walk(body, env).pop();
    };
  });

  // Match function calls
  this.match ("call", function (env, node, left, right) {
    var res = this.walk(left, env).apply(this, this.walk(right, env));
    return res;
  });

  // Match identifiers
  this.match ("name", function (env, node) {
    return env[node.value];
  });

  // Match anything else and return it's value
  this.match (_, function (env, node) {
    return node.value;
  })
});

var REPL = elf.REPL.clone({
  eval: function (cmd, env) {
    var ast    = Calculator.parse(cmd);
    var errors = elf.ErrorWalker.report(ast, cmd);
    if (errors) console.log(errors);
    var res    = Evaluator.walk(ast, env);
    return res.pop()
  }
});

REPL.start();

// var source = require("fs").readFileSync(__dirname + "/test.calc", 'utf8');
// var ast    = Calculator.parse(source);

// Evaluator.walk(ast);

// console.log("\n\nAST:\n")
// console.log('  ' + ast.toSexp().replace(/\n/g, '\n  '));

// console.log("\n\nErrors:")
// console.log(elf.ErrorWalker.report(ast, source) || '-');
<commit_msg>print the s-expression of the executed command<commit_after>var elf = require("../index"), sys = require("sys"), _;

var Calculator = elf.Language.clone(function () {
  this.number   ( /\d+/        )
  this.name     ( /[a-zA-Z]+/  )
  this.operator ( /\||\}|\)/)

  this.prefix   ( "+", "-"     )

  this.infixr   ( "=", 10      )

  this.infix    ( "+", "-", 10 )
  this.infix    ( "*", "/", 20 )

  this.prefix   ("{", function (node) {
    node.value  = "function";
    node.first  = this.parseUntil("|", { step: ",", meta: { type: "parameter" }, optional: true });
    node.second = this.parseUntil("}");

    return node;
  })

  this.infix  ("(", 80, function (node, first) {
    node.value  = "call";
    node.first  = first;
    node.second = this.parseUntil(")", { step: "," })

    return node;
  });

  this.stmt ("print")

  this.skip ( /\s+/ )
  this.eol  ( /\;/  )
});

Evaluator = elf.Walker.clone(function () {

  // Match unary -
  this.match ("-", [ _ ], function (env, node, left) {
    return -this.walk(left, env);
  })

  // Match binary -
  this.match ("-", [ _ , _ ], function (env, node, left, right) {
    return this.walk(left, env) - this.walk(right, env);
  })

  // Match unary +
  this.match ("+", [ _ ], function (env, node, left) {
    return +this.walk(left, env);
  })

  // Match binary +
  this.match ("+", [ _ , _ ], function (env, node, left, right) {
    return this.walk(left, env) + this.walk(right, env);
  })

  // Match binary *
  this.match ("*", function (env, node, left, right) {
    return this.walk(left, env) * this.walk(right, env);
  });

  // Match and "optimize" binary * when the right node is 2 by turning it into a left shift
  this.match ("*", [ _ , 2 ], function (env, node, left) {
    return this.walk(left, env) << 1;
  });

  // Match binary =
  this.match ("=", [ "name", _ ], function (env, node, left, right) {
    return env[left.value] = this.walk(right, env);
  });

  // Match binary /
  this.match ("/", function (env, node, left, right) {
    return this.walk(left, env) / this.walk(right, env);
  })

  // Match print statements
  this.match ("print", function (env, node, right) {
    return sys.puts(this.walk(right, env));
  })

  // Match function statements
  this.match("function", function (env, node, params, body) {
    var self = this;
    return function () {
      var args = arguments;
      env = env.clone();
      params.forEach(function (param, idx) { env[self.walk(param, env)] = args[idx]; }, self);
      return self.walk(body, env).pop();
    };
  });

  // Match function calls
  this.match ("call", function (env, node, left, right) {
    var res = this.walk(left, env).apply(this, this.walk(right, env));
    return res;
  });

  // Match identifiers
  this.match ("name", function (env, node) {
    return env[node.value];
  });

  // Match anything else and return it's value
  this.match (_, function (env, node) {
    return node.value;
  })
});

var REPL = elf.REPL.clone({
  eval: function (cmd, env) {
    var ast    = Calculator.parse(cmd);
    console.log("sexp:", ast.toSexp())
    var errors = elf.ErrorWalker.report(ast, cmd);
    if (errors) console.log(errors);
    var res    = Evaluator.walk(ast, env);
    return res.pop()
  }
});

REPL.start();

// var source = require("fs").readFileSync(__dirname + "/test.calc", 'utf8');
// var ast    = Calculator.parse(source);

// Evaluator.walk(ast);

// console.log("\n\nAST:\n")
// console.log('  ' + ast.toSexp().replace(/\n/g, '\n  '));

// console.log("\n\nErrors:")
// console.log(elf.ErrorWalker.report(ast, source) || '-');
<|endoftext|>