<commit_before>import Color from '../../util/Color'
import ColorPicker from '../../colorpicker/index';

const colorpicker_class = 'codemirror-colorview';
const colorpicker_background_class = 'codemirror-colorview-background';
// Excluded tokens do not show color views..
let excluded_token = ['comment'];

function onChange(cm, evt) {
    if (evt.origin == 'setValue') {  // if content is changed by setValue method, it initialize markers
        cm.state.colorpicker.close_color_picker();
        cm.state.colorpicker.init_color_update();
        cm.state.colorpicker.style_color_update();
    } else {
        cm.state.colorpicker.style_color_update(cm.getCursor().line);
    }

}

function onUpdate(cm, evt) {
    if (!cm.state.colorpicker.isUpdate) {
        cm.state.colorpicker.isUpdate = true;
        cm.state.colorpicker.close_color_picker();
        cm.state.colorpicker.init_color_update();
        cm.state.colorpicker.style_color_update();
    }
}

function onRefresh(cm, evt) {
    onChange(cm, { origin : 'setValue'});
}

function onKeyup(cm, evt) {
    cm.state.colorpicker.keyup(evt);
}

function onMousedown(cm, evt) {
    if (cm.state.colorpicker.is_edit_mode())
    {
        cm.state.colorpicker.check_mousedown(evt);
    }
}

function onPaste (cm, evt) {
    onChange(cm, { origin : 'setValue'});
}

function onScroll (cm) {
    cm.state.colorpicker.close_color_picker();
}

function onBlur (cm) {
    cm.state.colorpicker.hide_delay_color_picker(cm.state.colorpicker.opt.hideDelay || 1000);
}

function debounce (callback, delay) {

    var t = undefined;

    return function (cm, e) {
        if (t) {
            clearTimeout(t);
        }

        t = setTimeout(function () {
            callback(cm, e);
        }, delay || 300);
    }
}

function has_class(el, cls) {
    if (!el || !el.className) {
        return false;
    } else {
        var newClass = ' ' + el.className + ' ';
        return newClass.indexOf(' ' + cls + ' ') > -1;
    }
}

export default class ColorView {
    constructor (cm, opt) {
        var self = this;

        if (typeof opt == 'boolean')
        {
            opt = { mode : 'edit' };
        } else {
            opt = Object.assign({ mode: 'edit' }, opt || {});
        }

        this.opt = opt;
        this.cm = cm;
        this.markers = {};

        // set excluded token
        this.excluded_token = this.opt.excluded_token || excluded_token;

        if (this.opt.colorpicker) {
            this.colorpicker = this.opt.colorpicker(this.opt);
        } else {
            this.colorpicker = ColorPicker.create(this.opt);
        }

        this.init_event();

    }

    init_event() {

        this.cm.on('mousedown', onMousedown);
        this.cm.on('keyup', onKeyup);
        this.cm.on('change', onChange);
        this.cm.on('update', onUpdate);
        this.cm.on('refresh', onRefresh);
        this.cm.on('blur', onBlur);

        // create paste callback
        this.onPasteCallback = (function (cm, callback) {
            return  function (evt) {
                callback.call(this, cm, evt);
            }
        })(this.cm, onPaste);

        this.onScrollEvent = debounce(onScroll, 50)

        this.cm.getWrapperElement().addEventListener('paste', this.onPasteCallback);

        if (this.is_edit_mode())
        {
            this.cm.on('scroll', this.onScrollEvent);
        }

    }

    is_edit_mode() {
        return this.opt.mode == 'edit';
    }

    is_view_mode() {
        return this.opt.mode == 'view';
    }

    destroy() {
        this.cm.off('mousedown', onMousedown);
        this.cm.off('keyup', onKeyup);
        this.cm.off('change', onChange)
        this.cm.off('blur', onBlur);

        this.cm.getWrapperElement().removeEventListener('paste', this.onPasteCallback);

        if (this.is_edit_mode())
        {
            this.cm.off('scroll', this.onScrollEvent);
        }
    }

    hasClass(el, className) {
        if (!el.className)
        {
            return false;
        } else {
            var newClass = ' ' + el.className + ' ';
            return newClass.indexOf(' ' + className + ' ') > -1;
        }
    }

    check_mousedown(evt) {
        if (this.hasClass(evt.target, colorpicker_background_class) )
        {
            this.open_color_picker(evt.target.parentNode);
        } else {
            this.close_color_picker();
        }
    }

    popup_color_picker(defalutColor) {
        var cursor = this.cm.getCursor();
        var self = this;
        var colorMarker = {
            lineNo : cursor.line,
            ch : cursor.ch,
            color: defalutColor || '#FFFFFF',
            isShortCut : true
        };

        Object.keys(this.markers).forEach(function(key) {
            var searchKey = "#" + key;
            if (searchKey.indexOf( "#" + colorMarker.lineNo + ":") > -1) {
                var marker = self.markers[key];

                if (marker.ch <= colorMarker.ch && colorMarker.ch <= marker.ch + marker.color.length) {
                    // when cursor has marker
                    colorMarker.ch = marker.ch;
                    colorMarker.color = marker.color;
                    colorMarker.nameColor = marker.nameColor;
                }

            }
        });

        this.open_color_picker(colorMarker);
    }

    open_color_picker(el) {
        var lineNo = el.lineNo;
        var ch = el.ch;
        var nameColor = el.nameColor;
        var color = el.color;

        if (this.colorpicker) {
            var self = this;
            var prevColor = color;
            var pos = this.cm.charCoords({line : lineNo, ch : ch });
            this.colorpicker.show({
                left : pos.left,
                top : pos.bottom,
                isShortCut : el.isShortCut || false,
                hideDelay : self.opt.hideDelay || 2000
            }, nameColor || color, function (newColor) {
                self.cm.replaceRange(newColor, { line : lineNo, ch : ch } , { line : lineNo, ch : ch + prevColor.length }, '*colorpicker');
                prevColor = newColor;
            });

        }

    }

    close_color_picker() {
        if (this.colorpicker)
        {
            this.colorpicker.hide();
        }
    }

    hide_delay_color_picker() {
        if (this.colorpicker)
        {
            this.colorpicker.runHideDelay();
        }
    }

    key(lineNo, ch) {
        return [lineNo, ch].join(":");
    }

    keyup(evt) {

        if (this.colorpicker ) {
            if (evt.key == 'Escape') {
                this.colorpicker.hide();
            } else if (this.colorpicker.isShortCut == false) {
                this.colorpicker.hide();
            }
        }
    }

    init_color_update() {
        this.markers = {};  // initialize marker list
    }

    style_color_update(lineHandle) {
        if (lineHandle) {
            this.match(lineHandle);
        } else {
            var max = this.cm.lineCount();

            for(var lineNo = 0; lineNo < max; lineNo++) {
                this.match(lineNo);
            }
        }

    }

    empty_marker(lineNo, lineHandle) {
        var list = lineHandle.markedSpans || [];

        for(var i = 0, len = list.length; i < len; i++) {
            var key = this.key(lineNo, list[i].from);

            if (key && has_class(list[i].marker.replacedWith, colorpicker_class)) {
                delete this.markers[key];
                list[i].marker.clear();
            }

        }
    }

    match_result(lineHandle) {
        return Color.matches(lineHandle.text);
    }

    submatch(lineNo, lineHandle) {

        this.empty_marker(lineNo, lineHandle);

        const result = this.match_result(lineHandle);
        let obj = { next : 0 };

        result.forEach(item => {
            this.render(obj, lineNo, lineHandle, item.color, item.nameColor);
        });
    }

    match(lineNo) {
        var lineHandle = this.cm.getLineHandle(lineNo);
        var self = this;
        this.cm.operation(function () {
            self.submatch(lineNo, lineHandle);
        })
    }

    make_element() {
        var el = document.createElement('div');

        el.className = colorpicker_class;

        if (this.is_edit_mode())
        {
            el.title ="open color picker";
        } else {
            el.title ="";
        }

        el.back_element = this.make_background_element();
        el.appendChild(el.back_element);

        return el;
    }

    make_background_element() {
        var el = document.createElement('div');

        el.className = colorpicker_background_class;

        return el;
    }

    set_state(lineNo, start, color, nameColor) {
        var marker = this.create_marker(lineNo, start);

        marker.lineNo = lineNo;
        marker.ch = start;
        marker.color = color;
        marker.nameColor = nameColor;

        return marker;
    }

    create_marker(lineNo, start) {

        if (!this.has_marker(lineNo, start)) {
            this.init_marker(lineNo, start);
        }

        return this.get_marker(lineNo, start);

    }

    init_marker (lineNo, start) {
        this.markers[this.key(lineNo, start)] = this.make_element();
    }

    has_marker(lineNo, start) {
        return !!this.get_marker(lineNo, start);
    }

    get_marker(lineNo, start) {
        var key = this.key(lineNo,start);
        return this.markers[key]
    }

    update_element(el, color) {
        el.back_element.style.backgroundColor = color;
    }

    set_mark(line, ch, el) {
        this.cm.setBookmark({ line : line, ch : ch}, { widget : el, handleMouseEvents : true} );
    }

    is_excluded_token(line, ch) {
        var type = this.cm.getTokenTypeAt({line : line, ch : ch});
        var count = 0;
        for(var i = 0, len = this.excluded_token.length; i < len; i++) {
            if (type === this.excluded_token[i]) {
                count++;
                break;
            }
        }

        return count > 0;   // true is that it has a excluded token
    }

    render(cursor, lineNo, lineHandle, color, nameColor) {
        var start = lineHandle.text.indexOf(color, cursor.next);

        if (this.is_excluded_token(lineNo, start) === true) {
            // excluded token do not show.
            return;
        }

        cursor.next = start + color.length;

        if (this.has_marker(lineNo, start))
        {
            this.update_element(this.create_marker(lineNo, start), nameColor || color);
            this.set_state(lineNo, start, color, nameColor);
            return;
        }

        var el  = this.create_marker(lineNo, start);

        this.update_element(el, nameColor || color);

        this.set_state(lineNo, start, color, nameColor || color);
        this.set_mark(lineNo, start, el);

    }

}

<commit_msg>Focus the codemirror after color change<commit_after>import Color from '../../util/Color'
import ColorPicker from '../../colorpicker/index';

const colorpicker_class = 'codemirror-colorview';
const colorpicker_background_class = 'codemirror-colorview-background';
// Excluded tokens do not show color views..
let excluded_token = ['comment'];

function onChange(cm, evt) {
    if (evt.origin == 'setValue') {  // if content is changed by setValue method, it initialize markers
        cm.state.colorpicker.close_color_picker();
        cm.state.colorpicker.init_color_update();
        cm.state.colorpicker.style_color_update();
    } else {
        cm.state.colorpicker.style_color_update(cm.getCursor().line);
    }

}

function onUpdate(cm, evt) {
    if (!cm.state.colorpicker.isUpdate) {
        cm.state.colorpicker.isUpdate = true;
        cm.state.colorpicker.close_color_picker();
        cm.state.colorpicker.init_color_update();
        cm.state.colorpicker.style_color_update();
    }
}

function onRefresh(cm, evt) {
    onChange(cm, { origin : 'setValue'});
}

function onKeyup(cm, evt) {
    cm.state.colorpicker.keyup(evt);
}

function onMousedown(cm, evt) {
    if (cm.state.colorpicker.is_edit_mode())
    {
        cm.state.colorpicker.check_mousedown(evt);
    }
}

function onPaste (cm, evt) {
    onChange(cm, { origin : 'setValue'});
}

function onScroll (cm) {
    cm.state.colorpicker.close_color_picker();
}

function onBlur (cm) {
    cm.state.colorpicker.hide_delay_color_picker(cm.state.colorpicker.opt.hideDelay || 1000);
}

function debounce (callback, delay) {

    var t = undefined;

    return function (cm, e) {
        if (t) {
            clearTimeout(t);
        }

        t = setTimeout(function () {
            callback(cm, e);
        }, delay || 300);
    }
}

function has_class(el, cls) {
    if (!el || !el.className) {
        return false;
    } else {
        var newClass = ' ' + el.className + ' ';
        return newClass.indexOf(' ' + cls + ' ') > -1;
    }
}

export default class ColorView {
    constructor (cm, opt) {
        var self = this;

        if (typeof opt == 'boolean')
        {
            opt = { mode : 'edit' };
        } else {
            opt = Object.assign({ mode: 'edit' }, opt || {});
        }

        this.opt = opt;
        this.cm = cm;
        this.markers = {};

        // set excluded token
        this.excluded_token = this.opt.excluded_token || excluded_token;

        if (this.opt.colorpicker) {
            this.colorpicker = this.opt.colorpicker(this.opt);
        } else {
            this.colorpicker = ColorPicker.create(this.opt);
        }

        this.init_event();

    }

    init_event() {

        this.cm.on('mousedown', onMousedown);
        this.cm.on('keyup', onKeyup);
        this.cm.on('change', onChange);
        this.cm.on('update', onUpdate);
        this.cm.on('refresh', onRefresh);
        this.cm.on('blur', onBlur);

        // create paste callback
        this.onPasteCallback = (function (cm, callback) {
            return  function (evt) {
                callback.call(this, cm, evt);
            }
        })(this.cm, onPaste);

        this.onScrollEvent = debounce(onScroll, 50)

        this.cm.getWrapperElement().addEventListener('paste', this.onPasteCallback);

        if (this.is_edit_mode())
        {
            this.cm.on('scroll', this.onScrollEvent);
        }

    }

    is_edit_mode() {
        return this.opt.mode == 'edit';
    }

    is_view_mode() {
        return this.opt.mode == 'view';
    }

    destroy() {
        this.cm.off('mousedown', onMousedown);
        this.cm.off('keyup', onKeyup);
        this.cm.off('change', onChange)
        this.cm.off('blur', onBlur);

        this.cm.getWrapperElement().removeEventListener('paste', this.onPasteCallback);

        if (this.is_edit_mode())
        {
            this.cm.off('scroll', this.onScrollEvent);
        }
    }

    hasClass(el, className) {
        if (!el.className)
        {
            return false;
        } else {
            var newClass = ' ' + el.className + ' ';
            return newClass.indexOf(' ' + className + ' ') > -1;
        }
    }

    check_mousedown(evt) {
        if (this.hasClass(evt.target, colorpicker_background_class) )
        {
            this.open_color_picker(evt.target.parentNode);
        } else {
            this.close_color_picker();
        }
    }

    popup_color_picker(defalutColor) {
        var cursor = this.cm.getCursor();
        var self = this;
        var colorMarker = {
            lineNo : cursor.line,
            ch : cursor.ch,
            color: defalutColor || '#FFFFFF',
            isShortCut : true
        };

        Object.keys(this.markers).forEach(function(key) {
            var searchKey = "#" + key;
            if (searchKey.indexOf( "#" + colorMarker.lineNo + ":") > -1) {
                var marker = self.markers[key];

                if (marker.ch <= colorMarker.ch && colorMarker.ch <= marker.ch + marker.color.length) {
                    // when cursor has marker
                    colorMarker.ch = marker.ch;
                    colorMarker.color = marker.color;
                    colorMarker.nameColor = marker.nameColor;
                }

            }
        });

        this.open_color_picker(colorMarker);
    }

    open_color_picker(el) {
        var lineNo = el.lineNo;
        var ch = el.ch;
        var nameColor = el.nameColor;
        var color = el.color;

        if (this.colorpicker) {
            var prevColor = color;
            var pos = this.cm.charCoords({line : lineNo, ch : ch });
            this.colorpicker.show({
                left : pos.left,
                top : pos.bottom,
                isShortCut : el.isShortCut || false,
                hideDelay : this.opt.hideDelay || 2000
            }, nameColor || color, (newColor) => {
                this.cm.replaceRange(newColor, { line : lineNo, ch : ch } , { line : lineNo, ch : ch + prevColor.length }, '*colorpicker');
                this.cm.focus();
                prevColor = newColor;
            });

        }

    }

    close_color_picker() {
        if (this.colorpicker)
        {
            this.colorpicker.hide();
        }
    }

    hide_delay_color_picker() {
        if (this.colorpicker)
        {
            this.colorpicker.runHideDelay();
        }
    }

    key(lineNo, ch) {
        return [lineNo, ch].join(":");
    }

    keyup(evt) {

        if (this.colorpicker ) {
            if (evt.key == 'Escape') {
                this.colorpicker.hide();
            } else if (this.colorpicker.isShortCut == false) {
                this.colorpicker.hide();
            }
        }
    }

    init_color_update() {
        this.markers = {};  // initialize marker list
    }

    style_color_update(lineHandle) {
        if (lineHandle) {
            this.match(lineHandle);
        } else {
            var max = this.cm.lineCount();

            for(var lineNo = 0; lineNo < max; lineNo++) {
                this.match(lineNo);
            }
        }

    }

    empty_marker(lineNo, lineHandle) {
        var list = lineHandle.markedSpans || [];

        for(var i = 0, len = list.length; i < len; i++) {
            var key = this.key(lineNo, list[i].from);

            if (key && has_class(list[i].marker.replacedWith, colorpicker_class)) {
                delete this.markers[key];
                list[i].marker.clear();
            }

        }
    }

    match_result(lineHandle) {
        return Color.matches(lineHandle.text);
    }

    submatch(lineNo, lineHandle) {

        this.empty_marker(lineNo, lineHandle);

        const result = this.match_result(lineHandle);
        let obj = { next : 0 };

        result.forEach(item => {
            this.render(obj, lineNo, lineHandle, item.color, item.nameColor);
        });
    }

    match(lineNo) {
        var lineHandle = this.cm.getLineHandle(lineNo);
        var self = this;
        this.cm.operation(function () {
            self.submatch(lineNo, lineHandle);
        })
    }

    make_element() {
        var el = document.createElement('div');

        el.className = colorpicker_class;

        if (this.is_edit_mode())
        {
            el.title ="open color picker";
        } else {
            el.title ="";
        }

        el.back_element = this.make_background_element();
        el.appendChild(el.back_element);

        return el;
    }

    make_background_element() {
        var el = document.createElement('div');

        el.className = colorpicker_background_class;

        return el;
    }

    set_state(lineNo, start, color, nameColor) {
        var marker = this.create_marker(lineNo, start);

        marker.lineNo = lineNo;
        marker.ch = start;
        marker.color = color;
        marker.nameColor = nameColor;

        return marker;
    }

    create_marker(lineNo, start) {

        if (!this.has_marker(lineNo, start)) {
            this.init_marker(lineNo, start);
        }

        return this.get_marker(lineNo, start);

    }

    init_marker (lineNo, start) {
        this.markers[this.key(lineNo, start)] = this.make_element();
    }

    has_marker(lineNo, start) {
        return !!this.get_marker(lineNo, start);
    }

    get_marker(lineNo, start) {
        var key = this.key(lineNo,start);
        return this.markers[key]
    }

    update_element(el, color) {
        el.back_element.style.backgroundColor = color;
    }

    set_mark(line, ch, el) {
        this.cm.setBookmark({ line : line, ch : ch}, { widget : el, handleMouseEvents : true} );
    }

    is_excluded_token(line, ch) {
        var type = this.cm.getTokenTypeAt({line : line, ch : ch});
        var count = 0;
        for(var i = 0, len = this.excluded_token.length; i < len; i++) {
            if (type === this.excluded_token[i]) {
                count++;
                break;
            }
        }

        return count > 0;   // true is that it has a excluded token
    }

    render(cursor, lineNo, lineHandle, color, nameColor) {
        var start = lineHandle.text.indexOf(color, cursor.next);

        if (this.is_excluded_token(lineNo, start) === true) {
            // excluded token do not show.
            return;
        }

        cursor.next = start + color.length;

        if (this.has_marker(lineNo, start))
        {
            this.update_element(this.create_marker(lineNo, start), nameColor || color);
            this.set_state(lineNo, start, color, nameColor);
            return;
        }

        var el  = this.create_marker(lineNo, start);

        this.update_element(el, nameColor || color);

        this.set_state(lineNo, start, color, nameColor || color);
        this.set_mark(lineNo, start, el);

    }

}

<|endoftext|>


<commit_before>const
    R = require('ramda'),
    Rx = require('rx'),
    Box = x => ({
        map: f => Box(f(x))
    }),
    store = state => {
        return {
            reduce: (reducer, input) => { state = reducer(state, input); return state },
            state: () => state
        }
    },
    pauseMode = require('./pauseMode.js'),
    startMode = require('./startMode.js'),
    flyingMode = require('./flyingMode.js'),
    restartMode = require('./restartMode.js'),
    render = require('./render.js'),
    tap = require('./tap.js'),
    boolMatch = require('./boolMatch'),
    startingGameState = require('./startingGameState.js'),
    context = document.getElementById("gameScreen").getContext("2d"),
    screenShrinkFactor = .6

context.canvas.width = window.innerWidth * screenShrinkFactor * 1.5
context.canvas.height = window.innerWidth * screenShrinkFactor * (480 / 640)

const
    includeInput = R.curry((input, gameState) => ({
        ...gameState,
        input
    })),
    gameModes = (gameState, input) => {
        switch(gameState.mode) {
            case 'start':
                return startMode(gameState, input)
            case 'pause':
                return pauseMode(gameState, input)
            case 'flying':
                return flyingMode(gameState, input)
            case 'restart':
                return restartMode(gameState, input)
            default:
                return gameState
        }
    },
    modesIncludingInput = (gameState, input) => R.pipe(gameModes, includeInput(input))(gameState, input),
    random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min,
    effects = gameState =>
        R.pipe(
            R.prop('commands'),
            R.map(command => {
                switch(command.type) {
                    case 'random_numbers':
                        return {
                            type: command.returnType,
                            numbers:
                                R.pipe(
                                    R.prop('numbers'),
                                    R.toPairs,
                                    R.map(pair => [pair[0], random(pair[1][0], pair[1][1])]),
                                    R.fromPairs)
                                        (command)
                        }
                }
            }),
            R.filter(x => x),
            R.reduce((gameState, effect) => modesIncludingInput(gameState, effect), gameState),
            gameState => ({
                ...gameState,
                commands: []
            }))
                (gameState),
    game = R.pipe(modesIncludingInput, effects),
    gameStore = store(startingGameState(context.canvas.width, context.canvas.height)),
    clock = Rx.Observable.interval(1000/60).map(() => 'tick'), // 60 fps
    escKey = Rx.Observable.fromEvent(document, 'keydown')
        .map(R.prop('key'))
        .filter(R.equals('Escape'))

Rx.Observable.fromEvent(document, 'keydown')
    .merge(Rx.Observable.fromEvent(document, 'keyup'))
    .map(input => input.key + input.type)
    .filter(boolMatch(/^(ArrowUp|ArrowDown).*$/))
    .distinctUntilChanged()
    .merge(Rx.Observable.fromEvent(document, 'keypress').map(() => 'anykey'))
    .merge(clock)
    .merge(escKey)
    .map(input => ({type: input}))
    .subscribe(
        input => Box(gameStore.reduce(game, input)).map(
            newGameState => { if(newGameState.input.type === 'tick') render(context, newGameState) }))
<commit_msg>added TODO comment<commit_after>//TODO make effects use gameStore.reduce call with it's own reducer
const
    R = require('ramda'),
    Rx = require('rx'),
    Box = x => ({
        map: f => Box(f(x))
    }),
    store = state => {
        return {
            reduce: (reducer, input) => { state = reducer(state, input); return state },
            state: () => state
        }
    },
    pauseMode = require('./pauseMode.js'),
    startMode = require('./startMode.js'),
    flyingMode = require('./flyingMode.js'),
    restartMode = require('./restartMode.js'),
    render = require('./render.js'),
    tap = require('./tap.js'),
    boolMatch = require('./boolMatch'),
    startingGameState = require('./startingGameState.js'),
    context = document.getElementById("gameScreen").getContext("2d"),
    screenShrinkFactor = .6

context.canvas.width = window.innerWidth * screenShrinkFactor * 1.5
context.canvas.height = window.innerWidth * screenShrinkFactor * (480 / 640)

const
    includeInput = R.curry((input, gameState) => ({
        ...gameState,
        input
    })),
    gameModes = (gameState, input) => {
        switch(gameState.mode) {
            case 'start':
                return startMode(gameState, input)
            case 'pause':
                return pauseMode(gameState, input)
            case 'flying':
                return flyingMode(gameState, input)
            case 'restart':
                return restartMode(gameState, input)
            default:
                return gameState
        }
    },
    modesIncludingInput = (gameState, input) => R.pipe(gameModes, includeInput(input))(gameState, input),
    random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min,
    effects = gameState =>
        R.pipe(
            R.prop('commands'),
            R.map(command => {
                switch(command.type) {
                    case 'random_numbers':
                        return {
                            type: command.returnType,
                            numbers:
                                R.pipe(
                                    R.prop('numbers'),
                                    R.toPairs,
                                    R.map(pair => [pair[0], random(pair[1][0], pair[1][1])]),
                                    R.fromPairs)
                                        (command)
                        }
                }
            }),
            R.filter(x => x),
            R.reduce((gameState, effect) => modesIncludingInput(gameState, effect), gameState),
            gameState => ({
                ...gameState,
                commands: []
            }))
                (gameState),
    game = R.pipe(modesIncludingInput, effects),
    gameStore = store(startingGameState(context.canvas.width, context.canvas.height)),
    clock = Rx.Observable.interval(1000/60).map(() => 'tick'), // 60 fps
    escKey = Rx.Observable.fromEvent(document, 'keydown')
        .map(R.prop('key'))
        .filter(R.equals('Escape'))

Rx.Observable.fromEvent(document, 'keydown')
    .merge(Rx.Observable.fromEvent(document, 'keyup'))
    .map(input => input.key + input.type)
    .filter(boolMatch(/^(ArrowUp|ArrowDown).*$/))
    .distinctUntilChanged()
    .merge(Rx.Observable.fromEvent(document, 'keypress').map(() => 'anykey'))
    .merge(clock)
    .merge(escKey)
    .map(input => ({type: input}))
    .subscribe(
        input => Box(gameStore.reduce(game, input)).map(
            newGameState => { if(newGameState.input.type === 'tick') render(context, newGameState) }))
<|endoftext|>


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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, JSLINT, Mustache, brackets */

/**
 * Allows JSLint to run on the current document and report results in a UI panel.
 */
define(function (require, exports, module) {
    "use strict";

    // Load dependent non-module scripts
    require("thirdparty/jslint/jslint");

    // Load dependent modules
    var Commands                = brackets.getModule("command/Commands"),
        PanelManager            = brackets.getModule("view/PanelManager"),
        CommandManager          = brackets.getModule("command/CommandManager"),
        Menus                   = brackets.getModule("command/Menus"),
        DocumentManager         = brackets.getModule("document/DocumentManager"),
        EditorManager           = brackets.getModule("editor/EditorManager"),
        LanguageManager         = brackets.getModule("language/LanguageManager"),
        PreferencesManager      = brackets.getModule("preferences/PreferencesManager"),
        PerfUtils               = brackets.getModule("utils/PerfUtils"),
        Strings                 = brackets.getModule("strings"),
        StringUtils             = brackets.getModule("utils/StringUtils"),
        AppInit                 = brackets.getModule("utils/AppInit"),
        Resizer                 = brackets.getModule("utils/Resizer"),
        ExtensionUtils          = brackets.getModule("utils/ExtensionUtils"),
        StatusBar               = brackets.getModule("widgets/StatusBar"),
        JSLintTemplate          = require("text!htmlContent/bottom-panel.html"),
        ResultsTemplate         = require("text!htmlContent/results-table.html");

    var KeyboardPrefs = JSON.parse(require("text!keyboard.json")),
        JSLintOptions = JSON.parse(require("text!config.json"));

    var INDICATOR_ID = "jslint-status",
        defaultPrefs = {
            enabled: JSLintOptions.enabled_by_default,
            collapsed: false
        };

    /** @const {string} JSLint commands ID */
    var TOGGLE_ENABLED   = "jslint.toggleEnabled";
    var GOTO_FIRST_ERROR = "jslint.gotoFirstError";

    /**
     * @private
     * @type {PreferenceStorage}
     */
    var _prefs = null;

    /**
     * @private
     * @type {boolean}
     */
    var _enabled = true;

    /**
     * @private
     * @type {boolean}
     */
    var _collapsed = false;

    /**
     * @private
     * @type {$.Element}
     */
    var $lintResults;

    /**
     * @private
     * @type {boolean}
     */
    var _gotoEnabled = false;

    /**
     * Enable or disable the "Go to First JSLint Error" command
     * @param {boolean} gotoEnabled Whether it is enabled.
     */
    function setGotoEnabled(gotoEnabled) {
        CommandManager.get(GOTO_FIRST_ERROR).setEnabled(gotoEnabled);
        _gotoEnabled = gotoEnabled;
    }

    /**
     * Run JSLint on the current document. Reports results to the main UI. Displays
     * a gold star when no errors are found.
     */
    function run() {
        var currentDoc = DocumentManager.getCurrentDocument();

        var perfTimerDOM,
            perfTimerLint;

        var language = currentDoc ? LanguageManager.getLanguageForPath(currentDoc.file.fullPath) : "";

        if (_enabled && language && language.getId() === "javascript") {
            perfTimerLint = PerfUtils.markStart("JSLint linting:\t" + (!currentDoc || currentDoc.file.fullPath));
            var text = currentDoc.getText();

            // If a line contains only whitespace, remove the whitespace
            // This should be doable with a regexp: text.replace(/\r[\x20|\t]+\r/g, "\r\r");,
            // but that doesn't work.
            var i, arr = text.split("\n");
            for (i = 0; i < arr.length; i++) {
                if (!arr[i].match(/\S/)) {
                    arr[i] = "";
                }
            }
            text = arr.join("\n");

            var result = JSLINT(text, null);

            PerfUtils.addMeasurement(perfTimerLint);
            perfTimerDOM = PerfUtils.markStart("JSLint DOM:\t" + (!currentDoc || currentDoc.file.fullPath));

            if (!result) {
                // Remove the null errors for the template
                var errors = JSLINT.errors.filter(function (err) { return err !== null; });
                var html   = Mustache.render(ResultsTemplate, {reportList: errors});
                var $selectedRow;

                $lintResults.find(".table-container")
                    .empty()
                    .append(html)
                    .scrollTop(0)  // otherwise scroll pos from previous contents is remembered
                    .on("click", function (e) {
                        if ($selectedRow) {
                            $selectedRow.removeClass("selected");
                        }

                        $selectedRow  = $(e.target).closest("tr");
                        $selectedRow.addClass("selected");
                        var lineTd    = $selectedRow.find("td.line");
                        var line      = lineTd.text();
                        var character = lineTd.data("character");

                        var editor = EditorManager.getCurrentFullEditor();
                        editor.setCursorPos(line - 1, character - 1, true);
                        EditorManager.focusEditor();
                    });

                if (!_collapsed) {
                    Resizer.show($lintResults);
                }
                if (JSLINT.errors.length === 1) {
                    StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-errors", Strings.JSLINT_ERROR_INFORMATION);
                } else {
                    // Return the number of non-null errors
                    var numberOfErrors = errors.length;
                    // If there was a null value it means there was a stop notice and an indeterminate
                    // upper bound on the number of JSLint errors, which we'll represent by appending a '+'
                    if (numberOfErrors !== JSLINT.errors.length) {
                        // First discard the stop notice
                        numberOfErrors -= 1;
                        numberOfErrors += "+";
                    }
                    StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-errors",
                        StringUtils.format(Strings.JSLINT_ERRORS_INFORMATION, numberOfErrors));
                }
                setGotoEnabled(true);

            } else {
                Resizer.hide($lintResults);
                StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-valid", Strings.JSLINT_NO_ERRORS);
                setGotoEnabled(false);
            }

            PerfUtils.addMeasurement(perfTimerDOM);

        } else {
            // JSLint is disabled or does not apply to the current file, hide the results
            Resizer.hide($lintResults);
            StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-disabled", Strings.JSLINT_DISABLED);
            setGotoEnabled(false);
        }
    }

    /**
     * Update DocumentManager listeners.
     */
    function updateListeners() {
        if (_enabled) {
            // register our event listeners
            $(DocumentManager)
                .on("currentDocumentChange.jslint", function () {
                    run();
                })
                .on("documentSaved.jslint documentRefreshed.jslint", function (event, document) {
                    if (document === DocumentManager.getCurrentDocument()) {
                        run();
                    }
                });
        } else {
            $(DocumentManager).off(".jslint");
        }
    }

    /**
     * Enable or disable JSLint.
     * @param {boolean} enabled Enabled state.
     */
    function setEnabled(enabled) {
        _enabled = enabled;

        CommandManager.get(TOGGLE_ENABLED).setChecked(_enabled);
        updateListeners();
        _prefs.setValue("enabled", _enabled);

        // run immediately
        run();
    }

    /**
     * Toggle the collapsed state for the panel
     * @param {?boolean} collapsed Collapsed state. If omitted, the state is toggled.
     */
    function toggleCollapsed(collapsed) {
        if (collapsed === undefined) {
            collapsed = !_collapsed;
        }

        _collapsed = collapsed;
        _prefs.setValue("collapsed", _collapsed);

        if (_collapsed) {
            Resizer.hide($lintResults);
        } else {
            if (JSLINT.errors && JSLINT.errors.length) {
                Resizer.show($lintResults);
            }
        }
    }

    /** Command to toggle enablement */
    function handleToggleEnabled() {
        setEnabled(!_enabled);
    }

    /** Command to go to the first JSLint Error */
    function handleGotoFirstError() {
        run();
        if (_gotoEnabled) {
            $lintResults.find("tr:first-child").trigger("click");
        }
    }

    // Register command handlers
    CommandManager.register(Strings.CMD_JSLINT,             TOGGLE_ENABLED,   handleToggleEnabled);
    CommandManager.register(Strings.CMD_JSLINT_FIRST_ERROR, GOTO_FIRST_ERROR, handleGotoFirstError);

    // Add the menu items
    var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
    menu.addMenuItem(TOGGLE_ENABLED, "", Menus.AFTER, Commands.TOGGLE_WORD_WRAP);
    menu.addMenuDivider(Menus.AFTER, Commands.TOGGLE_WORD_WRAP);

    menu = Menus.getMenu(Menus.AppMenuBar.NAVIGATE_MENU);
    menu.addMenuItem(GOTO_FIRST_ERROR, KeyboardPrefs.gotoFirstError, Menus.AFTER, Commands.NAVIGATE_GOTO_DEFINITION);

    // Init PreferenceStorage
    _prefs = PreferencesManager.getPreferenceStorage(module, defaultPrefs);

    // Initialize items dependent on HTML DOM
    AppInit.htmlReady(function () {
        ExtensionUtils.loadStyleSheet(module, "jslint.css");

        var jsLintHtml = Mustache.render(JSLintTemplate, Strings);
        var resultsPanel = PanelManager.createBottomPanel("jslint.results", $(jsLintHtml), 100);
        $lintResults = $("#jslint-results");

        var lintStatusHtml = Mustache.render("

", Strings);
        $(lintStatusHtml).insertBefore("#status-language");
        StatusBar.addIndicator(INDICATOR_ID, $("#lint-status"));
        $("#jslint-results .close").click(function () {
            toggleCollapsed(true);
        });

        $("#jslint-status").click(function () {
            toggleCollapsed();
        });

        // Called on HTML ready to trigger the initial UI state
        setEnabled(_prefs.getValue("enabled"));

        toggleCollapsed(_prefs.getValue("collapsed"));

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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, JSLINT, Mustache, brackets */

/**
 * Allows JSLint to run on the current document and report results in a UI panel.
 */
define(function (require, exports, module) {
    "use strict";

    // Load dependent non-module scripts
    require("thirdparty/jslint/jslint");

    // Load dependent modules
    var Commands                = brackets.getModule("command/Commands"),
        PanelManager            = brackets.getModule("view/PanelManager"),
        CommandManager          = brackets.getModule("command/CommandManager"),
        Menus                   = brackets.getModule("command/Menus"),
        DocumentManager         = brackets.getModule("document/DocumentManager"),
        EditorManager           = brackets.getModule("editor/EditorManager"),
        LanguageManager         = brackets.getModule("language/LanguageManager"),
        NativeFileSystem        = brackets.getModule("file/NativeFileSystem").NativeFileSystem,
        PreferencesManager      = brackets.getModule("preferences/PreferencesManager"),
        PerfUtils               = brackets.getModule("utils/PerfUtils"),
        ProjectManager          = brackets.getModule("project/ProjectManager"),
        Strings                 = brackets.getModule("strings"),
        StringUtils             = brackets.getModule("utils/StringUtils"),
        AppInit                 = brackets.getModule("utils/AppInit"),
        Resizer                 = brackets.getModule("utils/Resizer"),
        ExtensionUtils          = brackets.getModule("utils/ExtensionUtils"),
        StatusBar               = brackets.getModule("widgets/StatusBar"),
        JSLintTemplate          = require("text!htmlContent/bottom-panel.html"),
        ResultsTemplate         = require("text!htmlContent/results-table.html");

    var KeyboardPrefs = JSON.parse(require("text!keyboard.json")),
        JSLintOptions = JSON.parse(require("text!config.json"));

    var INDICATOR_ID = "jslint-status",
        defaultPrefs = {
            enabled: JSLintOptions.enabled_by_default,
            collapsed: false
        };

    /** @const {string} JSLint commands ID */
    var TOGGLE_ENABLED   = "jslint.toggleEnabled";
    var GOTO_FIRST_ERROR = "jslint.gotoFirstError";

    /**
     * @private
     * @type {PreferenceStorage}
     */
    var _prefs = null;

    /**
     * @private
     * @type {boolean}
     */
    var _enabled = true;

    /**
     * @private
     * @type {boolean}
     */
    var _collapsed = false;

    /**
     * @private
     * @type {$.Element}
     */
    var $lintResults;

    /**
     * @private
     * @type {boolean}
     */
    var _gotoEnabled = false;

    /**
     * @private
     * @type {string}
     */
    var _configFileName = ".jslint.json";

    /**
     * @private
     * @type {object}
     */
    var _jsLintConfig = null;

    /**
     * Enable or disable the "Go to First JSLint Error" command
     * @param {boolean} gotoEnabled Whether it is enabled.
     */
    function setGotoEnabled(gotoEnabled) {
        CommandManager.get(GOTO_FIRST_ERROR).setEnabled(gotoEnabled);
        _gotoEnabled = gotoEnabled;
    }

    /**
     * Load project-wide JSLint configuration.
     *
     * Brackets JSLint configuration should be in JSON format, with all the
     * JSLint options specified according to JSLint documentation.
     *
     * JSLint project file should be located at <Project Root>/.jslint.json . It
     * is loaded each time project is changed or the configuration file is
     * modified.
     *
     * @return Promise to return JSLint configuration object.
     *
     * @see JSLint option
     * reference.
     */
    function _loadProjectConfig() {

        var projectRootEntry = ProjectManager.getProjectRoot(),
            result = new $.Deferred(),
            config;

        projectRootEntry.getFile(_configFileName,
                { create: false },
                function (configFileEntry) {
                var reader = new NativeFileSystem.FileReader();
                configFileEntry.file(function (file) {
                    reader.onload = function (event) {
                        try {
                            config = JSON.parse(event.target.result);
                            result.resolve(config);
                        } catch (e) {
                            result.reject(e);
                        }
                    };
                    reader.onerror = function (event) {
                        result.reject(event.target.error);
                    };
                    reader.readAsText(file);
                });
            },
            function (err) {
                result.reject(err);
            });

        return result.promise();

    }

    /**
     * Run JSLint on the current document. Reports results to the main UI. Displays
     * a gold star when no errors are found.
     */
    function run() {
        var currentDoc = DocumentManager.getCurrentDocument();

        var perfTimerDOM,
            perfTimerLint;

        var language = currentDoc ? LanguageManager.getLanguageForPath(currentDoc.file.fullPath) : "";

        if (_enabled && language && language.getId() === "javascript") {
            perfTimerLint = PerfUtils.markStart("JSLint linting:\t" + (!currentDoc || currentDoc.file.fullPath));
            var text = currentDoc.getText();

            // If a line contains only whitespace, remove the whitespace
            // This should be doable with a regexp: text.replace(/\r[\x20|\t]+\r/g, "\r\r");,
            // but that doesn't work.
            var i, arr = text.split("\n");
            for (i = 0; i < arr.length; i++) {
                if (!arr[i].match(/\S/)) {
                    arr[i] = "";
                }
            }
            text = arr.join("\n");

            var result = JSLINT(text, _jsLintConfig);

            PerfUtils.addMeasurement(perfTimerLint);
            perfTimerDOM = PerfUtils.markStart("JSLint DOM:\t" + (!currentDoc || currentDoc.file.fullPath));

            if (!result) {
                // Remove the null errors for the template
                var errors = JSLINT.errors.filter(function (err) { return err !== null; });
                var html   = Mustache.render(ResultsTemplate, {reportList: errors});
                var $selectedRow;

                $lintResults.find(".table-container")
                    .empty()
                    .append(html)
                    .scrollTop(0)  // otherwise scroll pos from previous contents is remembered
                    .on("click", function (e) {
                        if ($selectedRow) {
                            $selectedRow.removeClass("selected");
                        }

                        $selectedRow  = $(e.target).closest("tr");
                        $selectedRow.addClass("selected");
                        var lineTd    = $selectedRow.find("td.line");
                        var line      = lineTd.text();
                        var character = lineTd.data("character");

                        var editor = EditorManager.getCurrentFullEditor();
                        editor.setCursorPos(line - 1, character - 1, true);
                        EditorManager.focusEditor();
                    });

                if (!_collapsed) {
                    Resizer.show($lintResults);
                }
                if (JSLINT.errors.length === 1) {
                    StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-errors", Strings.JSLINT_ERROR_INFORMATION);
                } else {
                    // Return the number of non-null errors
                    var numberOfErrors = errors.length;
                    // If there was a null value it means there was a stop notice and an indeterminate
                    // upper bound on the number of JSLint errors, which we'll represent by appending a '+'
                    if (numberOfErrors !== JSLINT.errors.length) {
                        // First discard the stop notice
                        numberOfErrors -= 1;
                        numberOfErrors += "+";
                    }
                    StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-errors",
                        StringUtils.format(Strings.JSLINT_ERRORS_INFORMATION, numberOfErrors));
                }
                setGotoEnabled(true);

            } else {
                Resizer.hide($lintResults);
                StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-valid", Strings.JSLINT_NO_ERRORS);
                setGotoEnabled(false);
            }

            PerfUtils.addMeasurement(perfTimerDOM);

        } else {
            // JSLint is disabled or does not apply to the current file, hide the results
            Resizer.hide($lintResults);
            StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-disabled", Strings.JSLINT_DISABLED);
            setGotoEnabled(false);
        }
    }

    /**
     * Update DocumentManager and ProjectManager listeners.
     */
    function updateListeners() {
        if (_enabled) {
            // register our event listeners
            $(DocumentManager)
                .on("currentDocumentChange.jslint", function () {
                    run();
                })
                .on("documentSaved.jslint documentRefreshed.jslint", function (event, document) {
                    // if this project's JSLint config has been updated, reload
                    if (document.file.fullPath ===
                                ProjectManager.getProjectRoot().fullPath + _configFileName) {
                        _loadProjectConfig()
                            .done(function (config) {
                                _jsLintConfig = config;
                            })
                            .fail(function () {
                                _jsLintConfig = null;
                            });
                    }
                    if (document === DocumentManager.getCurrentDocument()) {
                        run();
                    }
                });
            $(ProjectManager)
                .on("projectOpen.jslint", function () {
                    _loadProjectConfig()
                        .done(function (config) {
                            _jsLintConfig = config;
                        })
                        .fail(function () {
                            _jsLintConfig = null;
                        });
                });
        } else {
            $(DocumentManager).off(".jslint");
            $(ProjectManager).off(".jslint");
        }
    }

    /**
     * Enable or disable JSLint.
     * @param {boolean} enabled Enabled state.
     */
    function setEnabled(enabled) {
        _enabled = enabled;

        CommandManager.get(TOGGLE_ENABLED).setChecked(_enabled);
        updateListeners();
        _prefs.setValue("enabled", _enabled);

        // run immediately
        run();
    }

    /**
     * Toggle the collapsed state for the panel
     * @param {?boolean} collapsed Collapsed state. If omitted, the state is toggled.
     */
    function toggleCollapsed(collapsed) {
        if (collapsed === undefined) {
            collapsed = !_collapsed;
        }

        _collapsed = collapsed;
        _prefs.setValue("collapsed", _collapsed);

        if (_collapsed) {
            Resizer.hide($lintResults);
        } else {
            if (JSLINT.errors && JSLINT.errors.length) {
                Resizer.show($lintResults);
            }
        }
    }

    /** Command to toggle enablement */
    function handleToggleEnabled() {
        setEnabled(!_enabled);
    }

    /** Command to go to the first JSLint Error */
    function handleGotoFirstError() {
        run();
        if (_gotoEnabled) {
            $lintResults.find("tr:first-child").trigger("click");
        }
    }

    // Register command handlers
    CommandManager.register(Strings.CMD_JSLINT,             TOGGLE_ENABLED,   handleToggleEnabled);
    CommandManager.register(Strings.CMD_JSLINT_FIRST_ERROR, GOTO_FIRST_ERROR, handleGotoFirstError);

    // Add the menu items
    var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
    menu.addMenuItem(TOGGLE_ENABLED, "", Menus.AFTER, Commands.TOGGLE_WORD_WRAP);
    menu.addMenuDivider(Menus.AFTER, Commands.TOGGLE_WORD_WRAP);

    menu = Menus.getMenu(Menus.AppMenuBar.NAVIGATE_MENU);
    menu.addMenuItem(GOTO_FIRST_ERROR, KeyboardPrefs.gotoFirstError, Menus.AFTER, Commands.NAVIGATE_GOTO_DEFINITION);

    // Init PreferenceStorage
    _prefs = PreferencesManager.getPreferenceStorage(module, defaultPrefs);

    // Initialize items dependent on HTML DOM
    AppInit.htmlReady(function () {
        ExtensionUtils.loadStyleSheet(module, "jslint.css");

        var jsLintHtml = Mustache.render(JSLintTemplate, Strings);
        var resultsPanel = PanelManager.createBottomPanel("jslint.results", $(jsLintHtml), 100);
        $lintResults = $("#jslint-results");

        var lintStatusHtml = Mustache.render("

", Strings);
        $(lintStatusHtml).insertBefore("#status-language");
        StatusBar.addIndicator(INDICATOR_ID, $("#lint-status"));
        $("#jslint-results .close").click(function () {
            toggleCollapsed(true);
        });

        $("#jslint-status").click(function () {
            toggleCollapsed();
        });

        // Called on HTML ready to trigger the initial UI state
        setEnabled(_prefs.getValue("enabled"));

        toggleCollapsed(_prefs.getValue("collapsed"));

    });
});
<|endoftext|>


<commit_before>/* eslint-disable max-len */
export default {
  header: '',
  item: `<label class="{{cssClasses.label}}">
  <input type="radio" class="{{cssClasses.checkbox}}" name="{{attributeName}}" {{#isRefined}}checked{{/isRefined}} />{{name}}
</label>`,
  footer: ''
};
<commit_msg>fix(numericRefinementList): classes on radio buttons (#1358) (#1432)<commit_after>/* eslint-disable max-len */
export default {
  header: '',
  item: `<label class="{{cssClasses.label}}">
  <input type="radio" class="{{cssClasses.radio}}" name="{{attributeName}}" {{#isRefined}}checked{{/isRefined}} />{{name}}
</label>`,
  footer: ''
};
<|endoftext|>


<commit_before>define(function(require) {

  var $ = require('jquery');
  var Backbone = require('backbone');
  var AppView = require('views/app');
  var docs = require('collections/docs');
  var cache = require('utils/cache');
  var settings = require('models/settings');
  var router = require('utils/router');
  var remoteStorageDocuments = require('remotestorage-documents');

  function litewrite() {

    var origHash = document.location.hash;

    remoteStorage.onWidget('ready', fetch);

    remoteStorage.onWidget('disconnect', function() {
      docs.reset().addNew();
    });

    remoteStorage.claimAccess('documents', 'rw').then(function() {
      remoteStorage.displayWidget('remotestorage-connect');

      remoteStorageDocuments.onChange('notes', fetch);

      setTimeout(function() {
        var md = origHash.match(/access_token=([^&]+)/);
        if(md && (! remoteStorage.getBearerToken())) {
          // backbone stole our access token
          remoteStorage.setBearerToken(md[1]);
        }
      }, 0);

    });

    settings
      .on('change:openDocId', setOpenDoc)
      .on('change:openDocId', setWindowTitle)
      .on('change:openDocId', router.setUrl, router)
      .on('change:openDocId', docs.deleteEmpty, docs);

    docs
      .on('change:title', router.setUrl, router)
      .on('change:title', setWindowTitle)
      .on('add', updateOpenDocId);

    fetch();

    $.when(settings.deferred, docs.deferred)
      .done(loadCache);

    cache.loading.done(setWindowTitle, startHistory);

    //Load on DOM-ready
    $(function() {
      new AppView();
    });

  }

  function loadCache() {
    ensureOpenDocId();
    setOpenDoc();
    cache.loading.resolve();
  }

  function ensureOpenDocId() {
    if ( _.isUndefined(settings.get('openDocId')) ) {
      settings.save('openDocId', docs.first().id);
    }
  }

  function setOpenDoc() {
    cache.openDoc = docs.get( settings.get('openDocId') );
  }

  function setWindowTitle() {
    document.title = (
      cache.openDoc ? cache.openDoc.get('title') : null
    ) || 'Litewrite';
  }

  function updateOpenDocId(doc) {
    settings.save('openDocId', doc.id);
  }

  function startHistory() {
    Backbone.history.start();
  }

  function fetch() {
    docs.fetch({
      success: function() {
        docs.trigger('fetch');
        setOpenDoc();
        if (docs.isEmpty()) docs.addNew();
        docs.deferred.resolve();
      }
    });
  }

  return litewrite;
});
<commit_msg>only handle 'change' events coming from remote<commit_after>define(function(require) {

  var $ = require('jquery');
  var Backbone = require('backbone');
  var AppView = require('views/app');
  var docs = require('collections/docs');
  var cache = require('utils/cache');
  var settings = require('models/settings');
  var router = require('utils/router');
  var remoteStorageDocuments = require('remotestorage-documents');

  function litewrite() {

    var origHash = document.location.hash;

    remoteStorage.onWidget('ready', fetch);

    remoteStorage.onWidget('disconnect', function() {
      docs.reset().addNew();
    });

    remoteStorage.claimAccess('documents', 'rw').then(function() {
      remoteStorage.displayWidget('remotestorage-connect');

      remoteStorageDocuments.onChange('notes', function(event) {
        if(event.origin === 'remote') {
          fetch();
        }
      });

      setTimeout(function() {
        var md = origHash.match(/access_token=([^&]+)/);
        if(md && (! remoteStorage.getBearerToken())) {
          // backbone stole our access token
          remoteStorage.setBearerToken(md[1]);
        }
      }, 0);

    });

    settings
      .on('change:openDocId', setOpenDoc)
      .on('change:openDocId', setWindowTitle)
      .on('change:openDocId', router.setUrl, router)
      .on('change:openDocId', docs.deleteEmpty, docs);

    docs
      .on('change:title', router.setUrl, router)
      .on('change:title', setWindowTitle)
      .on('add', updateOpenDocId);

    fetch();

    $.when(settings.deferred, docs.deferred)
      .done(loadCache);

    cache.loading.done(setWindowTitle, startHistory);

    //Load on DOM-ready
    $(function() {
      new AppView();
    });

  }

  function loadCache() {
    ensureOpenDocId();
    setOpenDoc();
    cache.loading.resolve();
  }

  function ensureOpenDocId() {
    if ( _.isUndefined(settings.get('openDocId')) ) {
      settings.save('openDocId', docs.first().id);
    }
  }

  function setOpenDoc() {
    cache.openDoc = docs.get( settings.get('openDocId') );
  }

  function setWindowTitle() {
    document.title = (
      cache.openDoc ? cache.openDoc.get('title') : null
    ) || 'Litewrite';
  }

  function updateOpenDocId(doc) {
    settings.save('openDocId', doc.id);
  }

  function startHistory() {
    Backbone.history.start();
  }

  function fetch() {
    docs.fetch({
      success: function() {
        docs.trigger('fetch');
        setOpenDoc();
        if (docs.isEmpty()) docs.addNew();
        docs.deferred.resolve();
      }
    });
  }

  return litewrite;
});
<|endoftext|>


<commit_before>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
    avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
    animate: false, // whether to transition the node positions
    animationDuration: 500, // duration of animation in ms if enabled
    ready: undefined, // callback on layoutready
    stop: undefined // callback on layoutstop
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var eles = options.eles;
    var nodes = eles.nodes().not(':parent');
    var graph = eles;

    var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
      x1: 0, y1: 0, w: cy.width(), h: cy.height()
    } );

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var components = [];
        var unhandledNodes = nodes;

        while( unhandledNodes.length > 0 ){
          var currComp = cy.collection();

          eles.bfs({
            roots: unhandledNodes[0],
            visit: function(i, depth, node, edge, pNode){
              currComp = currComp.add( node );
            },
            directed: false
          });

          unhandledNodes = unhandledNodes.not( currComp );
          components.push( currComp );
        }

        roots = cy.collection();
        for( var i = 0; i < components.length; i++ ){
          var comp = components[i];
          var maxDegree = comp.maxDegree( false );
          var compRoots = comp.filter(function(){
            return this.degree(false) === maxDegree;
          });

          roots = roots.add( compRoots );
        }

      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};
    var prevNode = {};
    var prevEdge = {};
    var successors = {};

    // find the depths of the nodes
    graph.bfs({
      roots: roots,
      directed: options.directed,
      visit: function(i, depth, node, edge, pNode){
        var ele = this[0];
        var id = ele.id();

        if( !depths[depth] ){
          depths[depth] = [];
        }

        depths[depth].push( ele );
        foundByBfs[ id ] = true;
        id2depth[ id ] = depth;
        prevNode[ id ] = pNode;
        prevEdge[ id ] = edge;

        if( pNode ){
          var prevId = pNode.id();
          var succ = successors[ prevId ] = successors[ prevId ] || [];

          succ.push( node );
        }
      }
    });

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.breadthfirst = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges(function(){
        return this.data('target') === node.id();
      });
      var thisInfo = node._private.scratch.breadthfirst;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.breadthfirst;

        if( thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.breadthfirst;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.breadthfirst;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.breadthfirst;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    if( options.avoidOverlap ){
      for( var i = 0; i < nodes.length; i++ ){
        var w = nodes[i].outerWidth();
        var h = nodes[i].outerHeight();

        minDistance = Math.max(minDistance, w, h);
      }
      minDistance *= options.spacingFactor; // just to have some nice spacing
    }

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.breadthfirst.depth;
      var neighbors = ele.neighborhood().nodes();
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var index = neighbor._private.scratch.breadthfirst.index;
        var depth = neighbor._private.scratch.breadthfirst.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity

    var sortFn = function(a, b){
      var apct = getWeightedPercent( a );
      var bpct = getWeightedPercent( b );

      return apct - bpct;
    };

    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        depths[i] = depths[i].sort( sortFn );
      }
      assignDepthsToEles(); // and update

    }

    var biggestDepthSize = 0;
    for( var i = 0; i < depths.length; i++ ){
      biggestDepthSize = Math.max( depths[i].length, biggestDepthSize );
    }

    var center = {
      x: bb.x1 + bb.w/2,
      y: bb.x1 + bb.h/2
    };

    var getPosition = function( ele, isBottomDepth ){
      var info = ele._private.scratch.breadthfirst;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( bb.w / (depthSize + 1), minDistance );
      var distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( !options.circle ){

        var epos = {
          x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
          y: (depth + 1) * distanceY
        };

        if( isBottomDepth ){
          return epos;
        }

        var succs = successors[ ele.id() ];
        if( succs ){
          epos.x = 0;

          for( var i = 0 ; i < succs.length; i++ ){
            var spos = pos[ succs[i].id() ];

            epos.x += spos.x;
          }

          epos.x /= succs.length;
        } else {
          //debugger;
        }

        return epos;

      } else {
        if( options.circle ){
          var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
          var theta = 2 * Math.PI / depths[depth].length * index;

          if( depth === 0 && depths[0].length === 1 ){
            radius = 1;
          }

          return {
            x: center.x + radius * Math.cos(theta),
            y: center.y + radius * Math.sin(theta)
          };

        } else {
          return {
            x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
            y: (depth + 1) * distanceY
          };
        }
      }

    };

    // get positions in reverse depth order
    var pos = {};
    for( var i = depths.length - 1; i >=0; i-- ){
      var depth = depths[i];

      for( var j = 0; j < depth.length; j++ ){
        var node = depth[j];

        pos[ node.id() ] = getPosition( node, i === depths.length - 1 );
      }
    }

    nodes.layoutPositions(this, options, function(){
      return pos[ this.id() ];
    });

    return this; // chaining
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<commit_msg> BFS layout overlap #915<commit_after>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
    avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
    animate: false, // whether to transition the node positions
    animationDuration: 500, // duration of animation in ms if enabled
    ready: undefined, // callback on layoutready
    stop: undefined // callback on layoutstop
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var eles = options.eles;
    var nodes = eles.nodes().not(':parent');
    var graph = eles;

    var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
      x1: 0, y1: 0, w: cy.width(), h: cy.height()
    } );

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var components = [];
        var unhandledNodes = nodes;

        while( unhandledNodes.length > 0 ){
          var currComp = cy.collection();

          eles.bfs({
            roots: unhandledNodes[0],
            visit: function(i, depth, node, edge, pNode){
              currComp = currComp.add( node );
            },
            directed: false
          });

          unhandledNodes = unhandledNodes.not( currComp );
          components.push( currComp );
        }

        roots = cy.collection();
        for( var i = 0; i < components.length; i++ ){
          var comp = components[i];
          var maxDegree = comp.maxDegree( false );
          var compRoots = comp.filter(function(){
            return this.degree(false) === maxDegree;
          });

          roots = roots.add( compRoots );
        }

      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};
    var prevNode = {};
    var prevEdge = {};
    var successors = {};

    // find the depths of the nodes
    graph.bfs({
      roots: roots,
      directed: options.directed,
      visit: function(i, depth, node, edge, pNode){
        var ele = this[0];
        var id = ele.id();

        if( !depths[depth] ){
          depths[depth] = [];
        }

        depths[depth].push( ele );
        foundByBfs[ id ] = true;
        id2depth[ id ] = depth;
        prevNode[ id ] = pNode;
        prevEdge[ id ] = edge;

        if( pNode ){
          var prevId = pNode.id();
          var succ = successors[ prevId ] = successors[ prevId ] || [];

          succ.push( node );
        }
      }
    });

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.breadthfirst = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges(function(){
        return this.data('target') === node.id();
      });
      var thisInfo = node._private.scratch.breadthfirst;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.breadthfirst;

        if( thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.breadthfirst;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.breadthfirst;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.breadthfirst;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    if( options.avoidOverlap ){
      for( var i = 0; i < nodes.length; i++ ){
        var w = nodes[i].outerWidth();
        var h = nodes[i].outerHeight();

        minDistance = Math.max(minDistance, w, h);
      }
      minDistance *= options.spacingFactor; // just to have some nice spacing
    }

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.breadthfirst.depth;
      var neighbors = ele.neighborhood().nodes();
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var index = neighbor._private.scratch.breadthfirst.index;
        var depth = neighbor._private.scratch.breadthfirst.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity

    var sortFn = function(a, b){
      var apct = getWeightedPercent( a );
      var bpct = getWeightedPercent( b );

      return apct - bpct;
    };

    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        depths[i] = depths[i].sort( sortFn );
      }
      assignDepthsToEles(); // and update

    }

    var biggestDepthSize = 0;
    for( var i = 0; i < depths.length; i++ ){
      biggestDepthSize = Math.max( depths[i].length, biggestDepthSize );
    }

    var center = {
      x: bb.x1 + bb.w/2,
      y: bb.x1 + bb.h/2
    };

    var getPosition = function( ele, isBottomDepth ){
      var info = ele._private.scratch.breadthfirst;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( bb.w / (depthSize + 1), minDistance );
      var distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( !options.circle ){

        var epos = {
          x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
          y: (depth + 1) * distanceY
        };

        if( isBottomDepth ){
          return epos;
        }

        // var succs = successors[ ele.id() ];
        // if( succs ){
        //   epos.x = 0;
        //
        //   for( var i = 0 ; i < succs.length; i++ ){
        //     var spos = pos[ succs[i].id() ];
        //
        //     epos.x += spos.x;
        //   }
        //
        //   epos.x /= succs.length;
        // } else {
        //   //debugger;
        // }

        return epos;

      } else {
        if( options.circle ){
          var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
          var theta = 2 * Math.PI / depths[depth].length * index;

          if( depth === 0 && depths[0].length === 1 ){
            radius = 1;
          }

          return {
            x: center.x + radius * Math.cos(theta),
            y: center.y + radius * Math.sin(theta)
          };

        } else {
          return {
            x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
            y: (depth + 1) * distanceY
          };
        }
      }

    };

    // get positions in reverse depth order
    var pos = {};
    for( var i = depths.length - 1; i >=0; i-- ){
      var depth = depths[i];

      for( var j = 0; j < depth.length; j++ ){
        var node = depth[j];

        pos[ node.id() ] = getPosition( node, i === depths.length - 1 );
      }
    }

    nodes.layoutPositions(this, options, function(){
      return pos[ this.id() ];
    });

    return this; // chaining
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<|endoftext|>


<commit_before>var locations = [
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'brad montgomery', origin: 'lepanto, ar', latitude: 35.61046, longitude: -90.33114, slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' }
];
<commit_msg>add self<commit_after>var locations = [
  { name: 'Tim Brownawell', origin: 'Fulton, MO', latitude: 38.86517, longitude: -91.98643, slack_handle: "tbrownaw" },
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'brad montgomery', origin: 'lepanto, ar', latitude: 35.61046, longitude: -90.33114, slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' }
];
<|endoftext|>


<commit_before>'use strict';

var opennms = require('../../util/opennms')(casper),
	utils = require('utils');

var x = require('casper').selectXPath;
var nextButton = 'div#next > span.v-button-wrap > span.v-icon';
var previousButton = 'div#previous > span.v-button-wrap > span.v-icon';

casper.test.begin('JMX Configuration Generator', {
	setUp: function() {
		opennms.initialize();
		opennms.login();
		casper.thenOpen(opennms.root() + '/admin/jmxConfigGenerator.jsp');
		casper.then(function() {
			this.page.switchToChildFrame(0);
		});
	},

	test: function(test) {
		/*
		 * In Vaadin 7 a Navigator was introduced to navigate within Vaadin applications
		 * Somehow normal links cause a vaadin exception. This verifies that no exception
		 * is thrown when clicking the Header links
		 */
		casper.waitForText('1. Service Configuration');
		casper.then(function() {
			casper.clickLabel('1. Service Configuration');
		});
		casper.then(function() {
			// sometimes empty v-errormessage divs are present, so we can't rely on just counting them
			var errorText = casper.fetchText('div.v-errormessage');
			test.assertTruthy(!errorText || errorText.trim().length === 0, 'v-errormessage elements should be empty');
		});

		/*
		 * Verify that navigation works.
		 */
		casper.then(function() {
			casper.sendKeys('input#port', '18980', {reset:true});
			var info = casper.getElementInfo('span#authenticate input[type="checkbox"]');
			test.assertTruthy(!info.attributes.hasOwnProperty('checked'), 'Authentication checkbox should be checked');
			casper.click('span#authenticate label');
		});
		casper.wait(200);
		casper.then(function() {
			var info = casper.getElementInfo('span#authenticate input[type="checkbox"]');
			test.assertTruthy(info.attributes.hasOwnProperty('checked'), 'Authentication checkbox should be checked');
			casper.sendKeys('input#authenticateUser', opennms.options().username, {reset:true});
			casper.sendKeys('input#authenticatePassword', opennms.options().password, {reset:true});
		});
		casper.then(function() {
			casper.click(nextButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			test.assertTextExists('com.mchange.v2.c3p0', 'After navigating to next page, "com.mchange.v2.c3p0" should be in the tree view');
			casper.click(nextButton);
		});
		casper.waitForText('collectd-configuration.xml');
		casper.then(function() {
			test.assertTextExists('collectd-configuration.xml', 'After navigating to the last page, "collectd-configuration.xml" should be visible');
			casper.click(previousButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			test.assertTextExists('com.mchange.v2.c3p0', 'After navigating to the previous page, "com.mchange.v2.c3p0" should be in the tree view');
			casper.click(previousButton);
		});
		casper.waitForText('Skip JVM MBeans');
		casper.then(function() {
			test.assertTextExists('Skip JVM MBeans', 'After navigating to the previous page, "Skip JVM beans" should be visible');
		});

		/*
		 * Verify that selected CompMembers do show up in the generated jmx-datacollection-config.xml snippet.
		 */
		casper.then(function() {
			var info = casper.getElementInfo('span#skipDefaultVM input[type="checkbox"]');
			test.assertTruthy(info.attributes.hasOwnProperty('checked'), 'Skip JVM MBeans should be checked');
			casper.click('span#skipDefaultVM input');
		});
		casper.wait(200);
		casper.then(function() {
			var info = casper.getElementInfo('span#skipDefaultVM input[type="checkbox"]');
			test.assertTruthy(!info.attributes.hasOwnProperty('checked'), 'Skip JVM MBeans should not be checked');
			casper.click(nextButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			opennms.scrollToElementWithText('span', 'PS MarkSweep');
		});
		casper.then(function() {
			this.mouse.rightclick(x('//span[text()=\'PS MarkSweep\']'));
		});
		casper.wait(100);
		casper.then(function() {
			casper.click(x('//td[@role="menuitem"]/div[text()=\'select\']'));
		});
		casper.wait(100);
		opennms.scrollToElementWithText('span', 'PS MarkSweep');
		casper.then(function() {
			casper.click(nextButton);
		});
		casper.waitForText('collectd-configuration.xml');
		casper.then(function() {
			test.assertTextExists('collectd-configuration.xml', 'collectd-configuration.xml tab should exist');
			test.assertTextExists('jmx-datacollection-config.xml', 'jmx-datacollection-config.xml tab should exist');
			casper.clickLabel('jmx-datacollection-config.xml');
		});
		casper.waitForText('JMXMP protocol');
		casper.then(function() {
			var info = casper.fetchText('textarea');
			test.assertEquals(info.match(/\<comp-attrib/g).length, 1, 'There should be 1 <comp-attrib/> tag in jmx-datacollection-config.xml');
			test.assertEquals(info.match(/\<comp-member/g).length, 7, 'There should be 7 <comp-member/> tags in jmx-datacollection-config.xml');
		});

		opennms.finished(test);
	}
});
<commit_msg>check for a different JVM attribute that is more likely to be there<commit_after>'use strict';

var opennms = require('../../util/opennms')(casper),
	utils = require('utils');

var x = require('casper').selectXPath;
var nextButton = 'div#next > span.v-button-wrap > span.v-icon';
var previousButton = 'div#previous > span.v-button-wrap > span.v-icon';

casper.test.begin('JMX Configuration Generator', {
	setUp: function() {
		opennms.initialize();
		opennms.login();
		casper.thenOpen(opennms.root() + '/admin/jmxConfigGenerator.jsp');
		casper.then(function() {
			this.page.switchToChildFrame(0);
		});
	},

	test: function(test) {
		/*
		 * In Vaadin 7 a Navigator was introduced to navigate within Vaadin applications
		 * Somehow normal links cause a vaadin exception. This verifies that no exception
		 * is thrown when clicking the Header links
		 */
		casper.waitForText('1. Service Configuration');
		casper.then(function() {
			casper.clickLabel('1. Service Configuration');
		});
		casper.then(function() {
			// sometimes empty v-errormessage divs are present, so we can't rely on just counting them
			var errorText = casper.fetchText('div.v-errormessage');
			test.assertTruthy(!errorText || errorText.trim().length === 0, 'v-errormessage elements should be empty');
		});

		/*
		 * Verify that navigation works.
		 */
		casper.then(function() {
			casper.sendKeys('input#port', '18980', {reset:true});
			var info = casper.getElementInfo('span#authenticate input[type="checkbox"]');
			test.assertTruthy(!info.attributes.hasOwnProperty('checked'), 'Authentication checkbox should be checked');
			casper.click('span#authenticate label');
		});
		casper.wait(200);
		casper.then(function() {
			var info = casper.getElementInfo('span#authenticate input[type="checkbox"]');
			test.assertTruthy(info.attributes.hasOwnProperty('checked'), 'Authentication checkbox should be checked');
			casper.sendKeys('input#authenticateUser', opennms.options().username, {reset:true});
			casper.sendKeys('input#authenticatePassword', opennms.options().password, {reset:true});
		});
		casper.then(function() {
			casper.click(nextButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			test.assertTextExists('com.mchange.v2.c3p0', 'After navigating to next page, "com.mchange.v2.c3p0" should be in the tree view');
			casper.click(nextButton);
		});
		casper.waitForText('collectd-configuration.xml');
		casper.then(function() {
			test.assertTextExists('collectd-configuration.xml', 'After navigating to the last page, "collectd-configuration.xml" should be visible');
			casper.click(previousButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			test.assertTextExists('com.mchange.v2.c3p0', 'After navigating to the previous page, "com.mchange.v2.c3p0" should be in the tree view');
			casper.click(previousButton);
		});
		casper.waitForText('Skip JVM MBeans');
		casper.then(function() {
			test.assertTextExists('Skip JVM MBeans', 'After navigating to the previous page, "Skip JVM beans" should be visible');
		});

		/*
		 * Verify that selected CompMembers do show up in the generated jmx-datacollection-config.xml snippet.
		 */
		casper.then(function() {
			var info = casper.getElementInfo('span#skipDefaultVM input[type="checkbox"]');
			test.assertTruthy(info.attributes.hasOwnProperty('checked'), 'Skip JVM MBeans should be checked');
			casper.click('span#skipDefaultVM input');
		});
		casper.wait(200);
		casper.then(function() {
			var info = casper.getElementInfo('span#skipDefaultVM input[type="checkbox"]');
			test.assertTruthy(!info.attributes.hasOwnProperty('checked'), 'Skip JVM MBeans should not be checked');
			casper.click(nextButton);
		});
		casper.waitForText('com.mchange.v2.c3p0');
		casper.then(function() {
			opennms.scrollToElementWithText('span', 'Code Cache');
		});
		casper.then(function() {
			this.mouse.rightclick(x('//span[text()=\'Code Cache\']'));
		});
		casper.wait(100);
		casper.then(function() {
			casper.click(x('//td[@role="menuitem"]/div[text()=\'select\']'));
		});
		casper.wait(100);
		opennms.scrollToElementWithText('span', 'Code Cache');
		casper.then(function() {
			casper.click(nextButton);
		});
		casper.waitForText('collectd-configuration.xml');
		casper.then(function() {
			test.assertTextExists('collectd-configuration.xml', 'collectd-configuration.xml tab should exist');
			test.assertTextExists('jmx-datacollection-config.xml', 'jmx-datacollection-config.xml tab should exist');
			casper.clickLabel('jmx-datacollection-config.xml');
		});
		casper.waitForText('JMXMP protocol');
		casper.then(function() {
			var info = casper.fetchText('textarea');
			test.assertEquals(info.match(/\<comp-attrib/g).length, 2, 'There should be 2 <comp-attrib/> tags in jmx-datacollection-config.xml');
			test.assertEquals(info.match(/\<comp-member/g).length, 8, 'There should be 8 <comp-member/> tags in jmx-datacollection-config.xml');
		});

		opennms.finished(test);
	}
});
<|endoftext|>