<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

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

var dom = require("../lib/dom");
var event = require("../lib/event");
var useragent = require("../lib/useragent");

// Safari accepts either image or element (but it must present in the DOM)
var proxy = dom.createElement('img');
// Safari crashes without image data
proxy.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";

function DragdropHandler(mouseHandler) {

    var editor = mouseHandler.editor;

    if (useragent.isOpera) {
        proxy.style.cssText = 'width:1px;height:1px;position:fixed;top:0;z-index:-1';
        editor.container.appendChild(proxy);
    }

    var exports = ["dragWait", "dragWaitEnd", "startDrag", "dragReadyEnd"];

     exports.forEach(function(x) {
         mouseHandler[x] = this[x];
    }, this);

    var mouseTarget = editor.renderer.getMouseEventTarget();
    editor.addEventListener("mousedown", this.onMouseDown.bind(mouseHandler));

    var dragSelectionMarker, x, y;
    var timerId, range;
    var dragCursor, counter = 0;
    var dragOperation;

    this.onDragStart = function(e) {
        // webkit workaround, see this.onMouseDown
        if (this.cancelDrag || !mouseTarget.draggable) {
            var self = this;
            setTimeout(function(){
                self.startSelect();
                self.captureMouse(e);
            }, 0);
            return e.preventDefault();
        }
        range = editor.getSelectionRange();

        var dataTransfer = e.dataTransfer;
        dataTransfer.effectAllowed = editor.getReadOnly() ? "copy" : "copyMove";
        dataTransfer.setDragImage && dataTransfer.setDragImage(proxy, 0, 0);
        dataTransfer.setData("Text", editor.session.getTextRange());

        this.setState("drag");
    };

    this.onDragEnd = function(e) {
        mouseTarget.draggable = false;
        this.setState(null);
        if (!editor.getReadOnly()) {
            var dropEffect = e.dataTransfer.dropEffect;
            if (!dragOperation && dropEffect == "move")
                // text was dragged outside the editor
                editor.session.remove(editor.getSelectionRange());
            editor.renderer.$cursorLayer.setBlinking(true);
        }
    };

    this.onDragEnter = function(e) {
        if (editor.getReadOnly() || !canAccept(e.dataTransfer))
            return;
        if (!dragSelectionMarker)
            addDragMarker();
        counter++;
        // dataTransfer object does not save dropEffect across events on IE, so we store it in dragOperation
        e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
        return event.preventDefault(e);
    };

    this.onDragOver = function(e) {
        if (editor.getReadOnly() || !canAccept(e.dataTransfer))
            return;
        // Opera doesn't trigger dragenter event on drag start
        if (!dragSelectionMarker) {
            addDragMarker();
            counter++;
        }
        if (onMouseMoveTimer !== null)
            onMouseMoveTimer = null;
        x = e.clientX;
        y = e.clientY;

        e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
        return event.preventDefault(e);
    };

    this.onDragLeave = function(e) {
        counter--;
        if (counter <= 0 && dragSelectionMarker) {
            clearDragMarker();
            dragOperation = null;
            return event.preventDefault(e);
        }
    };

    this.onDrop = function(e) {
        if (!dragSelectionMarker)
            return;
        var dataTransfer = e.dataTransfer;
        var isInternal = this.state == "drag";
        if (isInternal) {
            switch (dragOperation) {
                case "move":
                    if (range.contains(dragCursor.row, dragCursor.column)) {
                        // clear selection
                        range = {
                            start: dragCursor,
                            end: dragCursor
                        };
                    } else {
                        // move text
                        range = editor.moveText(range, dragCursor);
                    }
                    break;
                case "copy":
                    // copy text
                    range = editor.moveText(range, dragCursor, true);
                    break;
            }
        } else {
            var dropData = dataTransfer.getData('Text');
            range = {
                start: dragCursor,
                end: editor.session.insert(dragCursor, dropData)
            };
            editor.focus();
            dragOperation = null;
        }
        clearDragMarker();
        return event.preventDefault(e);
    };

    event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler));
    event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler));
    event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler));
    event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler));
    event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler));
    event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler));

    function onDragInterval() {
        dragCursor = editor.renderer.screenToTextCoordinates(x, y);
        var lineHeight = editor.renderer.layerConfig.lineHeight;
        var characterWidth = editor.renderer.layerConfig.characterWidth;
        var editorRect = editor.renderer.scroller.getBoundingClientRect();
        var offsets = {
           x: {
               left: x - editorRect.left,
               right: editorRect.right - x
           },
           y: {
               top: y - editorRect.top,
               bottom: editorRect.bottom - y
           }
        };
        var nearestXOffset = Math.min(offsets.x.left, offsets.x.right);
        var nearestYOffset = Math.min(offsets.y.top, offsets.y.bottom);
        var scrollCursor = {row: dragCursor.row, column: dragCursor.column};
        if (nearestXOffset / characterWidth <= 2) {
            scrollCursor.column += (offsets.x.left < offsets.x.right ? -3 : +2);
        }
        if (nearestYOffset / lineHeight <= 1) {
            scrollCursor.row += (offsets.y.top < offsets.y.bottom ? -1 : +1);
        }
        editor.moveCursorToPosition(dragCursor);
        editor.renderer.scrollCursorIntoView(scrollCursor);
    }

    function addDragMarker() {
        range = editor.selection.toOrientedRange();
        dragSelectionMarker = editor.session.addMarker(range, "ace_selection", editor.getSelectionStyle());
        editor.clearSelection();
        clearInterval(timerId);
        timerId = setInterval(onDragInterval, 20);
        counter = 0;
        event.addListener(document, "mousemove", onMouseMove);
        editor.setStyle("ace_dragging");
    }

    function clearDragMarker() {
        clearInterval(timerId);
        editor.session.removeMarker(dragSelectionMarker);
        dragSelectionMarker = null;
        editor.$blockScrolling += 1;
        editor.selection.fromOrientedRange(range);
        editor.$blockScrolling -= 1;
        range = null;
        counter = 0;
        event.removeListener(document, "mousemove", onMouseMove);
        editor.unsetStyle("ace_dragging");
    }

    // sometimes other code on the page can stop dragleave event leaving editor stuck in the drag state
    var onMouseMoveTimer = null;
    function onMouseMove() {
        if (onMouseMoveTimer == null) {
            onMouseMoveTimer = setTimeout(function() {
                if (onMouseMoveTimer != null && dragSelectionMarker)
                    clearDragMarker();
            }, 20);
        }
    }

    function canAccept(dataTransfer) {
        var types = dataTransfer.types;
        return !types || Array.prototype.some.call(types, function(type) {
            return type == 'text/plain' || type == 'Text';
        });
    }

    function getDropEffect(e) {
        var copyAllowed = ['copy', 'copymove', 'all', 'uninitialized'];
        var moveAllowed = ['move', 'copymove', 'linkmove', 'all', 'uninitialized'];

        var copyModifierState = useragent.isMac ? e.altKey : e.ctrlKey;

        // IE throws error while dragging from another app
        var effectAllowed = "uninitialized";
        try {
            effectAllowed = e.dataTransfer.effectAllowed.toLowerCase();
        } catch (e) {}
        var dropEffect = "none";

        if (copyModifierState && copyAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "copy";
        else if (moveAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "move";
        else if (copyAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "copy";

        return dropEffect;
    }
}

(function() {

    this.dragWait = function() {
        var editor = this.editor;
        var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
        var interval = (new Date()).getTime() - this.mousedownEvent.time;

        if (distance > 0)
            this.startSelect(this.mousedownEvent.getDocumentPosition());
        else if (interval > editor.getDragDelay())
            this.startDrag();
    };

    this.dragWaitEnd = function() {
        this.startSelect(this.mousedownEvent.getDocumentPosition(), true);
        this.selectEnd();
    };

    this.startDrag = function(){
        var target = this.editor.renderer.getMouseEventTarget();
        this.setState("dragReady");
        this.editor.renderer.$cursorLayer.setBlinking(false);
        target.draggable = true;
        if (useragent.isIE) {
            // IE does not handle [draggable] attribute set after mousedown
            event.addListener(target, "mousemove", forceDragIE);
        }
    };

    this.dragReadyEnd = function(e) {
        var target = this.editor.renderer.getMouseEventTarget();
        target.draggable = false;
        if (useragent.isIE) {
            event.removeListener(target, "mousemove", forceDragIE);
        }
        this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly());
        this.startSelect(this.mousedownEvent.getDocumentPosition(), true);
        this.selectEnd();
    };

    this.onMouseDown = function(e) {
        if (!this.$dragEnabled)
            return;
        var inSelection = e.inSelection();
        var editor = this.editor;
        this.mousedownEvent = e;

        var button = e.getButton();
        if (button === 0 && inSelection) {
            this.mousedownEvent.time = (new Date()).getTime();
            if (editor.getDragDelay()) {
                // https://code.google.com/p/chromium/issues/detail?id=286700
                if (useragent.isWebKit) {
                    var self = this;
                    self.cancelDrag = true;
                    var mouseTarget = editor.renderer.getMouseEventTarget();
                    mouseTarget.draggable = true;
                    setTimeout(function(){
                        self.cancelDrag = false;
                        mouseTarget.draggable = false;
                    }, 8);
                }
                this.captureMouse(e, "dragWait");
            } else {
                this.startDrag();
                this.captureMouse(e);
            }

            if (useragent.isOpera) {
                var cancelSelection = function(e){
                    document.getSelection().removeAllRanges();
                    editor.container.removeEventListener("mousemove", cancelSelection);
                };
                editor.container.addEventListener("mousemove", cancelSelection);
            }
            // TODO: a better way to prevent default handler without preventing browser default action
            e.defaultPrevented = true;
        }
    };

    function forceDragIE() {
        event.removeListener(this, "mousemove", forceDragIE);
        this.dragDrop();
    }

    function calcDistance(ax, ay, bx, by) {
        return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
    }
}).call(DragdropHandler.prototype);

exports.DragdropHandler = DragdropHandler;

});<commit_msg>Fix Opera drag image issue.<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

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

var dom = require("../lib/dom");
var event = require("../lib/event");
var useragent = require("../lib/useragent");

function DragdropHandler(mouseHandler) {

    var editor = mouseHandler.editor;

    // Safari accepts either image or element (but it must present in the DOM)
    var proxy = dom.createElement("img");
    // Safari crashes without image data
    proxy.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";

    if (useragent.isOpera) {
        proxy.style.cssText = "width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;visibility:hidden";
        editor.container.appendChild(proxy);
    }

    var exports = ["dragWait", "dragWaitEnd", "startDrag", "dragReadyEnd"];

     exports.forEach(function(x) {
         mouseHandler[x] = this[x];
    }, this);

    var mouseTarget = editor.renderer.getMouseEventTarget();
    editor.addEventListener("mousedown", this.onMouseDown.bind(mouseHandler));

    var dragSelectionMarker, x, y;
    var timerId, range;
    var dragCursor, counter = 0;
    var dragOperation;

    this.onDragStart = function(e) {
        // webkit workaround, see this.onMouseDown
        if (this.cancelDrag || !mouseTarget.draggable) {
            var self = this;
            setTimeout(function(){
                self.startSelect();
                self.captureMouse(e);
            }, 0);
            return e.preventDefault();
        }
        if (useragent.isOpera) {
            proxy.style.visibility = "visible";
            setTimeout(function(){
                proxy.style.visibility = "hidden";
            }, 0);
        }
        range = editor.getSelectionRange();

        var dataTransfer = e.dataTransfer;
        dataTransfer.effectAllowed = editor.getReadOnly() ? "copy" : "copyMove";
        dataTransfer.setDragImage && dataTransfer.setDragImage(proxy, 0, 0);
        dataTransfer.setData("Text", editor.session.getTextRange());

        this.setState("drag");
    };

    this.onDragEnd = function(e) {
        mouseTarget.draggable = false;
        this.setState(null);
        if (!editor.getReadOnly()) {
            var dropEffect = e.dataTransfer.dropEffect;
            if (!dragOperation && dropEffect == "move")
                // text was dragged outside the editor
                editor.session.remove(editor.getSelectionRange());
            editor.renderer.$cursorLayer.setBlinking(true);
        }
    };

    this.onDragEnter = function(e) {
        if (editor.getReadOnly() || !canAccept(e.dataTransfer))
            return;
        if (!dragSelectionMarker)
            addDragMarker();
        counter++;
        // dataTransfer object does not save dropEffect across events on IE, so we store it in dragOperation
        e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
        return event.preventDefault(e);
    };

    this.onDragOver = function(e) {
        if (editor.getReadOnly() || !canAccept(e.dataTransfer))
            return;
        // Opera doesn't trigger dragenter event on drag start
        if (!dragSelectionMarker) {
            addDragMarker();
            counter++;
        }
        if (onMouseMoveTimer !== null)
            onMouseMoveTimer = null;
        x = e.clientX;
        y = e.clientY;

        e.dataTransfer.dropEffect = dragOperation = getDropEffect(e);
        return event.preventDefault(e);
    };

    this.onDragLeave = function(e) {
        counter--;
        if (counter <= 0 && dragSelectionMarker) {
            clearDragMarker();
            dragOperation = null;
            return event.preventDefault(e);
        }
    };

    this.onDrop = function(e) {
        if (!dragSelectionMarker)
            return;
        var dataTransfer = e.dataTransfer;
        var isInternal = this.state == "drag";
        if (isInternal) {
            switch (dragOperation) {
                case "move":
                    if (range.contains(dragCursor.row, dragCursor.column)) {
                        // clear selection
                        range = {
                            start: dragCursor,
                            end: dragCursor
                        };
                    } else {
                        // move text
                        range = editor.moveText(range, dragCursor);
                    }
                    break;
                case "copy":
                    // copy text
                    range = editor.moveText(range, dragCursor, true);
                    break;
            }
        } else {
            var dropData = dataTransfer.getData('Text');
            range = {
                start: dragCursor,
                end: editor.session.insert(dragCursor, dropData)
            };
            editor.focus();
            dragOperation = null;
        }
        clearDragMarker();
        return event.preventDefault(e);
    };

    event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler));
    event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler));
    event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler));
    event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler));
    event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler));
    event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler));

    function onDragInterval() {
        dragCursor = editor.renderer.screenToTextCoordinates(x, y);
        var lineHeight = editor.renderer.layerConfig.lineHeight;
        var characterWidth = editor.renderer.layerConfig.characterWidth;
        var editorRect = editor.renderer.scroller.getBoundingClientRect();
        var offsets = {
           x: {
               left: x - editorRect.left,
               right: editorRect.right - x
           },
           y: {
               top: y - editorRect.top,
               bottom: editorRect.bottom - y
           }
        };
        var nearestXOffset = Math.min(offsets.x.left, offsets.x.right);
        var nearestYOffset = Math.min(offsets.y.top, offsets.y.bottom);
        var scrollCursor = {row: dragCursor.row, column: dragCursor.column};
        if (nearestXOffset / characterWidth <= 2) {
            scrollCursor.column += (offsets.x.left < offsets.x.right ? -3 : +2);
        }
        if (nearestYOffset / lineHeight <= 1) {
            scrollCursor.row += (offsets.y.top < offsets.y.bottom ? -1 : +1);
        }
        editor.moveCursorToPosition(dragCursor);
        editor.renderer.scrollCursorIntoView(scrollCursor);
    }

    function addDragMarker() {
        range = editor.selection.toOrientedRange();
        dragSelectionMarker = editor.session.addMarker(range, "ace_selection", editor.getSelectionStyle());
        editor.clearSelection();
        clearInterval(timerId);
        timerId = setInterval(onDragInterval, 20);
        counter = 0;
        event.addListener(document, "mousemove", onMouseMove);
        editor.setStyle("ace_dragging");
    }

    function clearDragMarker() {
        clearInterval(timerId);
        editor.session.removeMarker(dragSelectionMarker);
        dragSelectionMarker = null;
        editor.$blockScrolling += 1;
        editor.selection.fromOrientedRange(range);
        editor.$blockScrolling -= 1;
        range = null;
        counter = 0;
        event.removeListener(document, "mousemove", onMouseMove);
        editor.unsetStyle("ace_dragging");
    }

    // sometimes other code on the page can stop dragleave event leaving editor stuck in the drag state
    var onMouseMoveTimer = null;
    function onMouseMove() {
        if (onMouseMoveTimer == null) {
            onMouseMoveTimer = setTimeout(function() {
                if (onMouseMoveTimer != null && dragSelectionMarker)
                    clearDragMarker();
            }, 20);
        }
    }

    function canAccept(dataTransfer) {
        var types = dataTransfer.types;
        return !types || Array.prototype.some.call(types, function(type) {
            return type == 'text/plain' || type == 'Text';
        });
    }

    function getDropEffect(e) {
        var copyAllowed = ['copy', 'copymove', 'all', 'uninitialized'];
        var moveAllowed = ['move', 'copymove', 'linkmove', 'all', 'uninitialized'];

        var copyModifierState = useragent.isMac ? e.altKey : e.ctrlKey;

        // IE throws error while dragging from another app
        var effectAllowed = "uninitialized";
        try {
            effectAllowed = e.dataTransfer.effectAllowed.toLowerCase();
        } catch (e) {}
        var dropEffect = "none";

        if (copyModifierState && copyAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "copy";
        else if (moveAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "move";
        else if (copyAllowed.indexOf(effectAllowed) >= 0)
            dropEffect = "copy";

        return dropEffect;
    }
}

(function() {

    this.dragWait = function() {
        var editor = this.editor;
        var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
        var interval = (new Date()).getTime() - this.mousedownEvent.time;

        if (distance > 0)
            this.startSelect(this.mousedownEvent.getDocumentPosition());
        else if (interval > editor.getDragDelay())
            this.startDrag();
    };

    this.dragWaitEnd = function() {
        this.startSelect(this.mousedownEvent.getDocumentPosition(), true);
        this.selectEnd();
    };

    this.startDrag = function(){
        var target = this.editor.renderer.getMouseEventTarget();
        this.setState("dragReady");
        this.editor.renderer.$cursorLayer.setBlinking(false);
        target.draggable = true;
        if (useragent.isIE) {
            // IE does not handle [draggable] attribute set after mousedown
            event.addListener(target, "mousemove", forceDragIE);
        }
    };

    this.dragReadyEnd = function(e) {
        var target = this.editor.renderer.getMouseEventTarget();
        target.draggable = false;
        if (useragent.isIE) {
            event.removeListener(target, "mousemove", forceDragIE);
        }
        this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly());
        this.startSelect(this.mousedownEvent.getDocumentPosition(), true);
        this.selectEnd();
    };

    this.onMouseDown = function(e) {
        if (!this.$dragEnabled)
            return;
        var inSelection = e.inSelection();
        var editor = this.editor;
        this.mousedownEvent = e;

        var button = e.getButton();
        if (button === 0 && inSelection) {
            this.mousedownEvent.time = (new Date()).getTime();
            if (editor.getDragDelay()) {
                // https://code.google.com/p/chromium/issues/detail?id=286700
                if (useragent.isWebKit) {
                    var self = this;
                    self.cancelDrag = true;
                    var mouseTarget = editor.renderer.getMouseEventTarget();
                    mouseTarget.draggable = true;
                    setTimeout(function(){
                        self.cancelDrag = false;
                        mouseTarget.draggable = false;
                    }, 8);
                }
                this.captureMouse(e, "dragWait");
            } else {
                this.startDrag();
                this.captureMouse(e);
            }

            if (useragent.isOpera) {
                var cancelSelection = function(e){
                    document.getSelection().removeAllRanges();
                    editor.container.removeEventListener("mousemove", cancelSelection);
                };
                editor.container.addEventListener("mousemove", cancelSelection);
            }
            // TODO: a better way to prevent default handler without preventing browser default action
            e.defaultPrevented = true;
        }
    };

    function forceDragIE() {
        event.removeListener(this, "mousemove", forceDragIE);
        this.dragDrop();
    }

    function calcDistance(ax, ay, bx, by) {
        return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
    }
}).call(DragdropHandler.prototype);

exports.DragdropHandler = DragdropHandler;

});<|endoftext|>


<commit_before>'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name bind2vind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/bind2vind}
*/
setReadOnly( ns, 'bind2vind', require( '@stdlib/types/ndarray/base/bind2vind' ) );

/**
* @name ind2sub
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/ind2sub}
*/
setReadOnly( ns, 'ind2sub', require( '@stdlib/types/ndarray/base/ind2sub' ) );

/**
* @name isColumnMajor
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/is-column-major}
*/
setReadOnly( ns, 'isColumnMajor', require( '@stdlib/types/ndarray/base/is-column-major' ) );

/**
* @name isRowMajor
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/is-row-major}
*/
setReadOnly( ns, 'isRowMajor', require( '@stdlib/types/ndarray/base/is-row-major' ) );

/**
* @name iterationOrder
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/iteration-order}
*/
setReadOnly( ns, 'iterationOrder', require( '@stdlib/types/ndarray/base/iteration-order' ) );

/**
* @name maxViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/max-view-buffer-index}
*/
setReadOnly( ns, 'maxViewBufferIndex', require( '@stdlib/types/ndarray/base/max-view-buffer-index' ) );

/**
* @name minViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/min-view-buffer-index}
*/
setReadOnly( ns, 'minViewBufferIndex', require( '@stdlib/types/ndarray/base/min-view-buffer-index' ) );

/**
* @name minmaxViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/minmax-view-buffer-index}
*/
setReadOnly( ns, 'minmaxViewBufferIndex', require( '@stdlib/types/ndarray/base/minmax-view-buffer-index' ) );

/**
* @name numel
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/numel}
*/
setReadOnly( ns, 'numel', require( '@stdlib/types/ndarray/base/numel' ) );

/**
* @name shape2strides
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/shape2strides}
*/
setReadOnly( ns, 'shape2strides', require( '@stdlib/types/ndarray/base/shape2strides' ) );

/**
* @name strides2offset
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/strides2offset}
*/
setReadOnly( ns, 'strides2offset', require( '@stdlib/types/ndarray/base/strides2offset' ) );

/**
* @name sub2ind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/sub2ind}
*/
setReadOnly( ns, 'sub2ind', require( '@stdlib/types/ndarray/base/sub2ind' ) );

/**
* @name ndarray2array
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/to-array}
*/
setReadOnly( ns, 'ndarray2array', require( '@stdlib/types/ndarray/base/ndarray2array' ) );

/**
* @name vind2bind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/vind2bind}
*/
setReadOnly( ns, 'vind2bind', require( '@stdlib/types/ndarray/base/vind2bind' ) );

// EXPORTS //

module.exports = ns;
<commit_msg>Update namespace<commit_after>'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace ns
*/
var ns = {};

/**
* @name bind2vind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/bind2vind}
*/
setReadOnly( ns, 'bind2vind', require( '@stdlib/types/ndarray/base/bind2vind' ) );

/**
* @name ind2sub
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/ind2sub}
*/
setReadOnly( ns, 'ind2sub', require( '@stdlib/types/ndarray/base/ind2sub' ) );

/**
* @name isColumnMajor
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/is-column-major}
*/
setReadOnly( ns, 'isColumnMajor', require( '@stdlib/types/ndarray/base/is-column-major' ) );

/**
* @name isRowMajor
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/is-row-major}
*/
setReadOnly( ns, 'isRowMajor', require( '@stdlib/types/ndarray/base/is-row-major' ) );

/**
* @name isSingleSegmentCompatible
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/is-single-segment-compatible}
*/
setReadOnly( ns, 'isSingleSegmentCompatible', require( '@stdlib/types/ndarray/base/is-single-segment-compatible' ) );

/**
* @name iterationOrder
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/iteration-order}
*/
setReadOnly( ns, 'iterationOrder', require( '@stdlib/types/ndarray/base/iteration-order' ) );

/**
* @name maxViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/max-view-buffer-index}
*/
setReadOnly( ns, 'maxViewBufferIndex', require( '@stdlib/types/ndarray/base/max-view-buffer-index' ) );

/**
* @name minViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/min-view-buffer-index}
*/
setReadOnly( ns, 'minViewBufferIndex', require( '@stdlib/types/ndarray/base/min-view-buffer-index' ) );

/**
* @name minmaxViewBufferIndex
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/minmax-view-buffer-index}
*/
setReadOnly( ns, 'minmaxViewBufferIndex', require( '@stdlib/types/ndarray/base/minmax-view-buffer-index' ) );

/**
* @name numel
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/numel}
*/
setReadOnly( ns, 'numel', require( '@stdlib/types/ndarray/base/numel' ) );

/**
* @name shape2strides
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/shape2strides}
*/
setReadOnly( ns, 'shape2strides', require( '@stdlib/types/ndarray/base/shape2strides' ) );

/**
* @name strides2offset
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/strides2offset}
*/
setReadOnly( ns, 'strides2offset', require( '@stdlib/types/ndarray/base/strides2offset' ) );

/**
* @name sub2ind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/sub2ind}
*/
setReadOnly( ns, 'sub2ind', require( '@stdlib/types/ndarray/base/sub2ind' ) );

/**
* @name ndarray2array
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/to-array}
*/
setReadOnly( ns, 'ndarray2array', require( '@stdlib/types/ndarray/base/ndarray2array' ) );

/**
* @name vind2bind
* @memberof ns
* @readonly
* @type {Function}
* @see {@link module:@stdlib/types/ndarray/base/vind2bind}
*/
setReadOnly( ns, 'vind2bind', require( '@stdlib/types/ndarray/base/vind2bind' ) );

// EXPORTS //

module.exports = ns;
<|endoftext|>


<commit_before>import _ from 'lodash';
import path from 'path';
import fse from 'fs-extra';
import pkg from '../package.json';
import gutil from 'gulp-util';

const build = './build/';
const dist = './dist/';
const bundleDependencies = {
    'vendor': [
        //'i18next',
        'react',
        'react-dom',
        'react-addons-update',
        'lodash'
    ]
};

export default {
    clean: {
        styles: [
            'web/components/**/*.css',
            'web/styles/**/*.css'
        ],
        scripts: [
        ],
        templates: [
        ],
        vendor: [
            'web/vendor/**'
        ]
    },
    autoprefixer: {
        options: {
            browsers: [
                'last 2 versions',
                'safari 5',
                'ie 8',
                'ie 9',
                'opera 12.1',
                'ios 6',
                'android 4'
            ],
            cascade: true
        }
    },
    uglify: {
        options: {
        }
    },
    browserify: {
        'vendor': {
            dest: dist + 'assets/',
            options: {
                debug: true // Sourcemapping
            },
            require: bundleDependencies['vendor']
        },
        'app': {
            src: [
                './web/main.js'
            ],
            dest: dist + 'assets/',
            options: {
                paths: [],
                extensions: ['.jsx'], // default: .js and .json
                debug: true, // Sourcemapping

                // watchify requires these options
                cache: {},
                packageCache: {},
                fullPaths: true
            },
            external: _.union(
                bundleDependencies['vendor']
            ),
            transform: {
                'babelify': {
                    presets: ['es2015', 'stage-0', 'react']
                },
                'browserify-css': {
                    autoInject: true,
                    autoInjectOptions: {
                        'verbose': true
                    },
                    rootDir: 'web/',
                    minify: true,
                    // Example:
                    //   source={webroot}/../node_modules/bootstrap/**/*
                    //   target={webroot}/vendor/bootstrap/**/*
                    processRelativeUrl: (relativeUrl) => {
                        const stripQueryStringAndHashFromPath = (url) => {
                            return url.split('?')[0].split('#')[0];
                        };
                        let rootDir = path.resolve(process.cwd(), 'web');
                        let relativePath = stripQueryStringAndHashFromPath(relativeUrl);
                        let queryStringAndHash = relativeUrl.substring(relativePath.length);

                        let prefix = '../node_modules/';
                        if (_.startsWith(relativePath, prefix)) {
                            let vendorPath = 'vendor/' + relativePath.substring(prefix.length);
                            let source = path.join(rootDir, relativePath);
                            let target = path.join(rootDir, vendorPath);

                            gutil.log('Copying file from ' + JSON.stringify(source) + ' to ' + JSON.stringify(target));
                            fse.copySync(source, target);

                            // Returns a new path string with original query string and hash fragments
                            return vendorPath + queryStringAndHash;
                        }

                        return relativeUrl;

                    }
                }
            }
        }
    },
    csslint: {
        src: [
            'web/components/**/*.css',
            'web/styles/**/*.css'
            // exclusion
        ],
        options: require('../config/csslint')
    },
    handlebars: {
        common: {
            src: 'web/components/common/**/*.hbs',
            dest: 'web/components/common/'
        },
        portal: {
            src: 'web/components/portal/**/*.hbs',
            dest: 'web/components/portal/'
        }
    },
    jscs: {
        src: [
            'gulp/**/*.js',
            '*.js',
            '*.jsx',
            '{app,web,test}/**/*.js',

            // exclusion
            '!web/**/handlebars-templates.js', // exclude handlebars-templates.js:w!
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/jscs')
    },
    eslint: {
        src: [
            'gulp/**/*.js',
            '*.js',
            '*.jsx',
            '{app,web}/**/*.js',
            '{app,web}/**/*.jsx',

            // exclusion
            '!web/**/handlebars-templates.js', // exclude handlebars-templates.js:w!
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/eslint')
    },
    jshint: {
        src: [
            '*.json',
            '{app,web,test}/**/*.json',

            // exclusion
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/jshint')
    },
    mainBowerFiles: {
        base: 'bower_components/',
        dest: 'web/vendor/',
        options: {
            checkExistence: true,
            debugging: true,
            paths: {
                bowerDirectory: 'bower_components',
                bowerrc: '.bowerrc',
                bowerJson: 'bower.json'
            }
        }
    },
    stylus: {
        src: ['web/**/*.styl'],
        dest: 'web/',
        options: {
            compress: true
        }
    },
    i18next: {
        src: [
            'web/**/*.html',
            'web/**/*.hbs',
            'web/**/*.js',
            'web/**/*.jsx',
            // Use ! to filter out files or directories
            '!web/{vendor,test,i18n}/**'
        ],
        dest: './',
        options: {
            debug: true,
            sort: true,
            lngs: ['en'],
            defaultValue: '__L10N__', // to indicate that a default value has not been defined for the key
            resGetPath: 'web/i18n/{{lng}}/{{ns}}.json',
            resSetPath: 'web/i18n/{{lng}}/{{ns}}.json', // or 'web/i18n/${lng}/${ns}.saveAll.json'
            nsseparator: ':', // namespace separator
            keyseparator: '.', // key separator
            interpolationPrefix: '{{',
            interpolationSuffix: '}}',
            ns: {
                namespaces: [
                    'locale', // locale: language, timezone, ...
                    'resource' // default
                ],
                defaultNs: 'resource'
            }
        }
    }
};
<commit_msg>Creates vendor bundles<commit_after>import _ from 'lodash';
import path from 'path';
import fse from 'fs-extra';
import pkg from '../package.json';
import gutil from 'gulp-util';

const build = './build/';
const dist = './dist/';
const bundleDependencies = {
    'vendor': [
        'async',
        'classnames',
        'fbjs/lib/joinClasses',
        'fixed-data-table',
        'i18next',
        'jsuri',
        'lodash',
        'moment',
        'pubsub-js',
        'react',
        'react-dom',
        'react-addons-update',
        'react-bootstrap',
        'react-datagrid',
        'react-dom',
        'react-infinite',
        'react-router',
        'react-select',
        'redux',
        'sha1',
        'socketio-file-upload',
        'three',

        // Bower Components
        'Sortable',
        'stacktrace'
    ]
};

export default {
    clean: {
        styles: [
            'web/components/**/*.css',
            'web/styles/**/*.css'
        ],
        scripts: [
        ],
        templates: [
        ],
        vendor: [
            'web/vendor/**'
        ]
    },
    autoprefixer: {
        options: {
            browsers: [
                'last 2 versions',
                'safari 5',
                'ie 8',
                'ie 9',
                'opera 12.1',
                'ios 6',
                'android 4'
            ],
            cascade: true
        }
    },
    uglify: {
        options: {
        }
    },
    browserify: {
        'vendor': {
            dest: dist + 'assets/',
            options: {
                debug: true // Sourcemapping
            },
            require: bundleDependencies['vendor']
        },
        'app': {
            src: [
                './web/main.js'
            ],
            dest: dist + 'assets/',
            options: {
                paths: [],
                extensions: ['.jsx'], // default: .js and .json
                debug: true, // Sourcemapping

                // watchify requires these options
                cache: {},
                packageCache: {},
                fullPaths: true
            },
            external: _.union(
                bundleDependencies['vendor']
            ),
            transform: {
                'babelify': {
                    presets: ['es2015', 'stage-0', 'react']
                },
                'browserify-css': {
                    autoInject: true,
                    autoInjectOptions: {
                        'verbose': true
                    },
                    rootDir: 'web/',
                    minify: true,
                    // Example:
                    //   source={webroot}/../node_modules/bootstrap/**/*
                    //   target={webroot}/vendor/bootstrap/**/*
                    processRelativeUrl: (relativeUrl) => {
                        const stripQueryStringAndHashFromPath = (url) => {
                            return url.split('?')[0].split('#')[0];
                        };
                        let rootDir = path.resolve(process.cwd(), 'web');
                        let relativePath = stripQueryStringAndHashFromPath(relativeUrl);
                        let queryStringAndHash = relativeUrl.substring(relativePath.length);

                        let prefix = '../node_modules/';
                        if (_.startsWith(relativePath, prefix)) {
                            let vendorPath = 'vendor/' + relativePath.substring(prefix.length);
                            let source = path.join(rootDir, relativePath);
                            let target = path.join(rootDir, vendorPath);

                            gutil.log('Copying file from ' + JSON.stringify(source) + ' to ' + JSON.stringify(target));
                            fse.copySync(source, target);

                            // Returns a new path string with original query string and hash fragments
                            return vendorPath + queryStringAndHash;
                        }

                        return relativeUrl;

                    }
                }
            }
        }
    },
    csslint: {
        src: [
            'web/components/**/*.css',
            'web/styles/**/*.css'
            // exclusion
        ],
        options: require('../config/csslint')
    },
    handlebars: {
        common: {
            src: 'web/components/common/**/*.hbs',
            dest: 'web/components/common/'
        },
        portal: {
            src: 'web/components/portal/**/*.hbs',
            dest: 'web/components/portal/'
        }
    },
    jscs: {
        src: [
            'gulp/**/*.js',
            '*.js',
            '*.jsx',
            '{app,web,test}/**/*.js',

            // exclusion
            '!web/**/handlebars-templates.js', // exclude handlebars-templates.js:w!
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/jscs')
    },
    eslint: {
        src: [
            'gulp/**/*.js',
            '*.js',
            '*.jsx',
            '{app,web}/**/*.js',
            '{app,web}/**/*.jsx',

            // exclusion
            '!web/**/handlebars-templates.js', // exclude handlebars-templates.js:w!
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/eslint')
    },
    jshint: {
        src: [
            '*.json',
            '{app,web,test}/**/*.json',

            // exclusion
            '!web/{vendor,test}/**',
            '!**/node_modules/**'
        ],
        options: require('../config/jshint')
    },
    mainBowerFiles: {
        base: 'bower_components/',
        dest: 'web/vendor/',
        options: {
            checkExistence: true,
            debugging: true,
            paths: {
                bowerDirectory: 'bower_components',
                bowerrc: '.bowerrc',
                bowerJson: 'bower.json'
            }
        }
    },
    stylus: {
        src: ['web/**/*.styl'],
        dest: 'web/',
        options: {
            compress: true
        }
    },
    i18next: {
        src: [
            'web/**/*.html',
            'web/**/*.hbs',
            'web/**/*.js',
            'web/**/*.jsx',
            // Use ! to filter out files or directories
            '!web/{vendor,test,i18n}/**'
        ],
        dest: './',
        options: {
            debug: true,
            sort: true,
            lngs: ['en'],
            defaultValue: '__L10N__', // to indicate that a default value has not been defined for the key
            resGetPath: 'web/i18n/{{lng}}/{{ns}}.json',
            resSetPath: 'web/i18n/{{lng}}/{{ns}}.json', // or 'web/i18n/${lng}/${ns}.saveAll.json'
            nsseparator: ':', // namespace separator
            keyseparator: '.', // key separator
            interpolationPrefix: '{{',
            interpolationSuffix: '}}',
            ns: {
                namespaces: [
                    'locale', // locale: language, timezone, ...
                    'resource' // default
                ],
                defaultNs: 'resource'
            }
        }
    }
};
<|endoftext|>


<commit_before>"use strict";

var env = require('./env');
var Spec = require('./Spec');
var Syncable = require('./Syncable');
var Pipe = require('./Pipe');
var SecondPreciseClock = require('./SecondPreciseClock');

/**
 * Host is (normally) a singleton object registering/coordinating
 * all the local Swarm objects, connecting them to appropriate
 * external uplinks, maintaining clocks, etc.
 * Host itself is not fully synchronized like a Model but still
 * does some event gossiping with peer Hosts.
 * @constructor
 */
function Host(id, ms, storage) {
    this.objects = {};
    this.sources = {};
    this.storage = storage;
    this._host = this; // :)
    this._lstn = [','];
    this._id = id;
    this._server = /^swarm~.*/.test(id);
    var clock_fn = env.clockType || SecondPreciseClock;
    this.clock = new clock_fn(this._id, ms||0);

    if (this.storage) {
        this.sources[this._id] = this.storage;
        this.storage._host = this;
    }
    delete this.objects[this.spec()];

    if (!env.multihost) {
        if (env.localhost) {
            throw new Error('use multihost mode');
        }
        env.localhost = this;
    }
}

Host.MAX_INT = 9007199254740992;
Host.MAX_SYNC_TIME = 60 * 60000; // 1 hour (milliseconds)
Host.HASH_POINTS = 3;

Host.hashDistance = function hashDistance(peer, obj) {
    if ((obj).constructor !== Number) {
        if (obj._id) {
            obj = obj._id;
        }
        obj = env.hashfn(obj);
    }
    if (peer._id) {
        peer = peer._id;
    }
    var dist = 4294967295;
    for (var i = 0; i < Host.HASH_POINTS; i++) {
        var hash = env.hashfn(peer._id + ':' + i);
        dist = Math.min(dist, hash ^ obj);
    }
    return dist;
};

module.exports = Syncable.extend(Host, {

    deliver: function (spec, val, repl) {
        if (spec.type() !== 'Host') {
            var typeid = spec.filter('/#');
            var obj = this.get(typeid);
            if (obj) {
                // TODO seeTimestamp()
                obj.deliver(spec, val, repl);
            }
        } else {
            this._super.deliver.apply(this, arguments);
        }
    },

    init: function (spec, val, repl) {

    },

    get: function (spec, callback) {
        if (spec && spec.constructor === Function && spec.prototype._type) {
            spec = '/' + spec.prototype._type;
        }
        spec = new Spec(spec);
        var typeid = spec.filter('/#');
        if (!typeid.has('/')) {
            throw new Error('invalid spec');
        }
        var o = typeid.has('#') && this.objects[typeid];
        if (!o) {
            var t = Syncable.types[spec.type()];
            if (!t) {
                throw new Error('type unknown: ' + spec);
            }
            o = new t(typeid, undefined, this);
            if (typeof(callback) === 'function') {
                o.on('.init', callback);
            }
        }
        return o;
    },

    addSource: function hostAddPeer(spec, peer) {
        //FIXME when their time is off so tell them so
        // if (false) { this.clockOffset; }
        var old = this.sources[peer._id];
        if (old) {
            old.deliver(this.newEventSpec('off'), '', this);
        }

        this.sources[peer._id] = peer;
        if (spec.op() === 'on') {
            peer.deliver(this.newEventSpec('reon'), this.clock.ms(), this);
        }
        for (var sp in this.objects) {
            this.objects[sp].checkUplink();
        }
    },

    neutrals: {
        /**
         * Host forwards on() calls to local objects to support some
         * shortcut notations, like
         *          host.on('/Mouse',callback)
         *          host.on('/Mouse.init',callback)
         *          host.on('/Mouse#Mickey',callback)
         *          host.on('/Mouse#Mickey.init',callback)
         *          host.on('/Mouse#Mickey!baseVersion',repl)
         *          host.on('/Mouse#Mickey!base.x',trackfn)
         * The target object may not exist beforehand.
         * Note that the specifier is actually the second 3sig parameter
         * (value). The 1st (spec) reflects this /Host.on invocation only.
         */
        on: function hostOn(spec, filter, lstn) {
            if (!filter) {
                // the subscriber needs "all the events"
                return this.addSource(spec, lstn);
            }

            if (filter.constructor === Function && filter.id) {
                filter = new Spec(filter.id, '/');
            } else if (filter.constructor === String) {
                filter = new Spec(filter, '.');
            }
            // either suscribe to this Host or to some other object
            if (!filter.has('/') || filter.type() === 'Host') {
                this._super._neutrals.on.call(this, spec, filter, lstn);
            } else {
                var objSpec = new Spec(filter);
                if (!objSpec.has('#')) {
                    throw new Error('no id to listen');
                }
                objSpec = objSpec.set('.on').set(spec.version(), '!');
                this.deliver(objSpec, filter, lstn);
            }
        },

        reon: function hostReOn(spec, ms, host) {
            if (spec.type() !== 'Host') {
                throw new Error('Host.reon(/NotHost.reon)');
            }
            this.clock.adjustTime(ms);
            this.addSource(spec, host);
        },

        off: function (spec, nothing, peer) {
            peer.deliver(peer.spec().add(this.time(), '!').add('.reoff'), '', this);
            this.removeSource(spec, peer);
        },

        reoff: function hostReOff(spec, nothing, peer) {
            this.removeSource(spec, peer);
        }

    }, // neutrals

    removeSource: function (spec, peer) {
        if (spec.type() !== 'Host') {
            throw new Error('Host.removeSource(/NoHost)');
        }

        if (this.sources[peer._id] !== peer) {
            console.error('peer unknown', peer._id); //throw new Error
            return;
        }
        delete this.sources[peer._id];
        for (var sp in this.objects) {
            var obj = this.objects[sp];
            if (obj.getListenerIndex(peer, true) > -1) {
                obj.off(sp, '', peer);
                obj.checkUplink(sp);
            }
        }
    },

    /**
     * Returns an unique Lamport timestamp on every invocation.
     * Swarm employs 30bit integer Unix-like timestamps starting epoch at
     * 1 Jan 2010. Timestamps are encoded as 5-char base64 tokens; in case
     * several events are generated by the same process at the same second
     * then sequence number is added so a timestamp may be more than 5
     * chars. The id of the Host (+user~session) is appended to the ts.
     */
    time: function () {
        var ts = this.clock.issueTimestamp();
        this._version = ts;
        return ts;
    },

    /**
     * Returns an array of sources (caches,storages,uplinks,peers)
     * a given replica should be subscribed to. This default
     * implementation uses a simple consistent hashing scheme.
     * Note that a client may be connected to many servers
     * (peers), so the uplink selection logic is shared.
     * @param {Spec} spec some object specifier
     * @returns {Array} array of currently available uplinks for specified object
     */
    getSources: function (spec) {
        var self = this,
            uplinks = [],
            mindist = 4294967295,
            rePeer = /^swarm~/, // peers, not clients
            target = env.hashfn(spec),
            closestPeer = null;

        if (rePeer.test(this._id)) {
            mindist = Host.hashDistance(this._id, target);
            closestPeer = this.storage;
        } else {
            uplinks.push(self.storage); // client-side cache
        }

        for (var id in this.sources) {
            if (!rePeer.test(id)) {
                continue;
            }
            var dist = Host.hashDistance(id, target);
            if (dist < mindist) {
                closestPeer = this.sources[id];
                mindist = dist;
            }
        }
        if (closestPeer) {
            uplinks.push(closestPeer);
        }
        return uplinks;
    },

    isUplinked: function () {
        for (var id in this.sources) {
            if (/^swarm~.*/.test(id)) {
                return true;
            }
        }
        return false;
    },

    isServer: function () {
        return this._server;
    },

    register: function (obj) {
        var spec = obj.spec();
        if (spec in this.objects) {
            return this.objects[spec];
        }
        this.objects[spec] = obj;
        return obj;
    },

    unregister: function (obj) {
        var spec = obj.spec();
        // TODO unsubscribe from the uplink - swarm-scale gc
        if (spec in this.objects) {
            delete this.objects[spec];
        }
    },

    // waits for handshake from stream
    accept: function (stream_or_url, pipe_env) {
        new Pipe(this, stream_or_url, pipe_env);
    },

    // initiate handshake with peer
    connect: function (stream_or_url, pipe_env) {
        var pipe = new Pipe(this, stream_or_url, pipe_env);
        pipe.deliver(new Spec('/Host#'+this._id+'!0.on'), '', this); //this.newEventSpec
        return pipe;
    },

    disconnect: function (id) {
        for (var peer_id in this.sources) {
            if (id && peer_id != id) {
                continue;
            }
            if (peer_id === this._id) {
                // storage
                continue;
            }
            var peer = this.sources[peer_id];
            // normally, .off is sent by a downlink
            peer.deliver(peer.spec().add(this.time(), '!').add('.off'));
        }
    },

    close: function (cb) {
        for(var id in this.sources) {
            if (id===this._id) {continue;}
            this.disconnect(id);
        }
        this.storage.close(cb);
    },

    checkUplink: function (spec) {
        //  TBD Host event relay + PEX
    }

});
<commit_msg>fix Host.close(): check storage is defined before closing it<commit_after>"use strict";

var env = require('./env');
var Spec = require('./Spec');
var Syncable = require('./Syncable');
var Pipe = require('./Pipe');
var SecondPreciseClock = require('./SecondPreciseClock');

/**
 * Host is (normally) a singleton object registering/coordinating
 * all the local Swarm objects, connecting them to appropriate
 * external uplinks, maintaining clocks, etc.
 * Host itself is not fully synchronized like a Model but still
 * does some event gossiping with peer Hosts.
 * @constructor
 */
function Host(id, ms, storage) {
    this.objects = {};
    this.sources = {};
    this.storage = storage;
    this._host = this; // :)
    this._lstn = [','];
    this._id = id;
    this._server = /^swarm~.*/.test(id);
    var clock_fn = env.clockType || SecondPreciseClock;
    this.clock = new clock_fn(this._id, ms||0);

    if (this.storage) {
        this.sources[this._id] = this.storage;
        this.storage._host = this;
    }
    delete this.objects[this.spec()];

    if (!env.multihost) {
        if (env.localhost) {
            throw new Error('use multihost mode');
        }
        env.localhost = this;
    }
}

Host.MAX_INT = 9007199254740992;
Host.MAX_SYNC_TIME = 60 * 60000; // 1 hour (milliseconds)
Host.HASH_POINTS = 3;

Host.hashDistance = function hashDistance(peer, obj) {
    if ((obj).constructor !== Number) {
        if (obj._id) {
            obj = obj._id;
        }
        obj = env.hashfn(obj);
    }
    if (peer._id) {
        peer = peer._id;
    }
    var dist = 4294967295;
    for (var i = 0; i < Host.HASH_POINTS; i++) {
        var hash = env.hashfn(peer._id + ':' + i);
        dist = Math.min(dist, hash ^ obj);
    }
    return dist;
};

module.exports = Syncable.extend(Host, {

    deliver: function (spec, val, repl) {
        if (spec.type() !== 'Host') {
            var typeid = spec.filter('/#');
            var obj = this.get(typeid);
            if (obj) {
                // TODO seeTimestamp()
                obj.deliver(spec, val, repl);
            }
        } else {
            this._super.deliver.apply(this, arguments);
        }
    },

    init: function (spec, val, repl) {

    },

    get: function (spec, callback) {
        if (spec && spec.constructor === Function && spec.prototype._type) {
            spec = '/' + spec.prototype._type;
        }
        spec = new Spec(spec);
        var typeid = spec.filter('/#');
        if (!typeid.has('/')) {
            throw new Error('invalid spec');
        }
        var o = typeid.has('#') && this.objects[typeid];
        if (!o) {
            var t = Syncable.types[spec.type()];
            if (!t) {
                throw new Error('type unknown: ' + spec);
            }
            o = new t(typeid, undefined, this);
            if (typeof(callback) === 'function') {
                o.on('.init', callback);
            }
        }
        return o;
    },

    addSource: function hostAddPeer(spec, peer) {
        //FIXME when their time is off so tell them so
        // if (false) { this.clockOffset; }
        var old = this.sources[peer._id];
        if (old) {
            old.deliver(this.newEventSpec('off'), '', this);
        }

        this.sources[peer._id] = peer;
        if (spec.op() === 'on') {
            peer.deliver(this.newEventSpec('reon'), this.clock.ms(), this);
        }
        for (var sp in this.objects) {
            this.objects[sp].checkUplink();
        }
    },

    neutrals: {
        /**
         * Host forwards on() calls to local objects to support some
         * shortcut notations, like
         *          host.on('/Mouse',callback)
         *          host.on('/Mouse.init',callback)
         *          host.on('/Mouse#Mickey',callback)
         *          host.on('/Mouse#Mickey.init',callback)
         *          host.on('/Mouse#Mickey!baseVersion',repl)
         *          host.on('/Mouse#Mickey!base.x',trackfn)
         * The target object may not exist beforehand.
         * Note that the specifier is actually the second 3sig parameter
         * (value). The 1st (spec) reflects this /Host.on invocation only.
         */
        on: function hostOn(spec, filter, lstn) {
            if (!filter) {
                // the subscriber needs "all the events"
                return this.addSource(spec, lstn);
            }

            if (filter.constructor === Function && filter.id) {
                filter = new Spec(filter.id, '/');
            } else if (filter.constructor === String) {
                filter = new Spec(filter, '.');
            }
            // either suscribe to this Host or to some other object
            if (!filter.has('/') || filter.type() === 'Host') {
                this._super._neutrals.on.call(this, spec, filter, lstn);
            } else {
                var objSpec = new Spec(filter);
                if (!objSpec.has('#')) {
                    throw new Error('no id to listen');
                }
                objSpec = objSpec.set('.on').set(spec.version(), '!');
                this.deliver(objSpec, filter, lstn);
            }
        },

        reon: function hostReOn(spec, ms, host) {
            if (spec.type() !== 'Host') {
                throw new Error('Host.reon(/NotHost.reon)');
            }
            this.clock.adjustTime(ms);
            this.addSource(spec, host);
        },

        off: function (spec, nothing, peer) {
            peer.deliver(peer.spec().add(this.time(), '!').add('.reoff'), '', this);
            this.removeSource(spec, peer);
        },

        reoff: function hostReOff(spec, nothing, peer) {
            this.removeSource(spec, peer);
        }

    }, // neutrals

    removeSource: function (spec, peer) {
        if (spec.type() !== 'Host') {
            throw new Error('Host.removeSource(/NoHost)');
        }

        if (this.sources[peer._id] !== peer) {
            console.error('peer unknown', peer._id); //throw new Error
            return;
        }
        delete this.sources[peer._id];
        for (var sp in this.objects) {
            var obj = this.objects[sp];
            if (obj.getListenerIndex(peer, true) > -1) {
                obj.off(sp, '', peer);
                obj.checkUplink(sp);
            }
        }
    },

    /**
     * Returns an unique Lamport timestamp on every invocation.
     * Swarm employs 30bit integer Unix-like timestamps starting epoch at
     * 1 Jan 2010. Timestamps are encoded as 5-char base64 tokens; in case
     * several events are generated by the same process at the same second
     * then sequence number is added so a timestamp may be more than 5
     * chars. The id of the Host (+user~session) is appended to the ts.
     */
    time: function () {
        var ts = this.clock.issueTimestamp();
        this._version = ts;
        return ts;
    },

    /**
     * Returns an array of sources (caches,storages,uplinks,peers)
     * a given replica should be subscribed to. This default
     * implementation uses a simple consistent hashing scheme.
     * Note that a client may be connected to many servers
     * (peers), so the uplink selection logic is shared.
     * @param {Spec} spec some object specifier
     * @returns {Array} array of currently available uplinks for specified object
     */
    getSources: function (spec) {
        var self = this,
            uplinks = [],
            mindist = 4294967295,
            rePeer = /^swarm~/, // peers, not clients
            target = env.hashfn(spec),
            closestPeer = null;

        if (rePeer.test(this._id)) {
            mindist = Host.hashDistance(this._id, target);
            closestPeer = this.storage;
        } else {
            uplinks.push(self.storage); // client-side cache
        }

        for (var id in this.sources) {
            if (!rePeer.test(id)) {
                continue;
            }
            var dist = Host.hashDistance(id, target);
            if (dist < mindist) {
                closestPeer = this.sources[id];
                mindist = dist;
            }
        }
        if (closestPeer) {
            uplinks.push(closestPeer);
        }
        return uplinks;
    },

    isUplinked: function () {
        for (var id in this.sources) {
            if (/^swarm~.*/.test(id)) {
                return true;
            }
        }
        return false;
    },

    isServer: function () {
        return this._server;
    },

    register: function (obj) {
        var spec = obj.spec();
        if (spec in this.objects) {
            return this.objects[spec];
        }
        this.objects[spec] = obj;
        return obj;
    },

    unregister: function (obj) {
        var spec = obj.spec();
        // TODO unsubscribe from the uplink - swarm-scale gc
        if (spec in this.objects) {
            delete this.objects[spec];
        }
    },

    // waits for handshake from stream
    accept: function (stream_or_url, pipe_env) {
        new Pipe(this, stream_or_url, pipe_env);
    },

    // initiate handshake with peer
    connect: function (stream_or_url, pipe_env) {
        var pipe = new Pipe(this, stream_or_url, pipe_env);
        pipe.deliver(new Spec('/Host#'+this._id+'!0.on'), '', this); //this.newEventSpec
        return pipe;
    },

    disconnect: function (id) {
        for (var peer_id in this.sources) {
            if (id && peer_id != id) {
                continue;
            }
            if (peer_id === this._id) {
                // storage
                continue;
            }
            var peer = this.sources[peer_id];
            // normally, .off is sent by a downlink
            peer.deliver(peer.spec().add(this.time(), '!').add('.off'));
        }
    },

    close: function (cb) {
        for(var id in this.sources) {
            if (id===this._id) {continue;}
            this.disconnect(id);
        }
        if (this.storage) {
            this.storage.close(cb);
        } else if (cb) {
            cb();
        }
    },

    checkUplink: function (spec) {
        //  TBD Host event relay + PEX
    }

});
<|endoftext|>


<commit_before>const Groa = require('../../');

const app = new Groa();

app.addProto(__dirname + '/proto/example.proto');

app.use(async (ctx, next) => {

	console.log('middleware');
	await next();
});

app.use(async (ctx, next) => {

	if (ctx.path === 'example.foo.Example1.ping') {
		ctx.body = ctx.req.body;
	}
});

app.listen(50051, () => {
	console.log('Listening on port 50051');
});
<commit_msg>using new pattern to represent service and methods<commit_after>const Groa = require('../../');

const app = new Groa();

app.addProto(__dirname + '/proto/example.proto');

app.use(async (ctx, next) => {

	console.log('middleware');
	await next();
});

app.use(async (ctx, next) => {

	if (ctx.path === '/example.foo.Example1/Ping') {
		ctx.body = ctx.req.body;
	}
});

app.listen(50051, () => {
	console.log('Listening on port 50051');
});
<|endoftext|>


<commit_before>/**
 * Set up Selenium WebDriver for UI tests.
 */
'use strict';

var webdriver;

var pageLoadTimeoutms = 60 * 1000;
var implicitlyWaitTimeoutms = 1 * 1000;

/*
 * Convert a string to camel case.
 * @param  String string The string to modify.
 * @return String        The modified string.
 */
function toCamelCase(string) {
  return string.replace(/^([A-Z])|\s(\w)/g, function(match, p1, p2) {
    if (p2) {
      return p2.toUpperCase();
    }
    return p1.toLowerCase();
  });
}

function getCustomCapabilitiesFromEnvironment(webdriver) {
  var saucelabsProperties = {};

  var browserKey = webdriver.Capability.BROWSER_NAME;
  var platformKey = webdriver.Capability.PLATFORM_NAME;

  var browserValue = process.env.SELENIUM_BROWSER || webdriver.Browser.FIREFOX;

  // Object.values() will be in ES7, but until then...
  let validBrowser = false;
  for (let key in webdriver.Browser) {
    validBrowser = webdriver.Browser[key] === browserValue;
    if (validBrowser) {
      break;
    }
  }

  if (validBrowser) {
    saucelabsProperties[browserKey] = browserValue;
  } else {
    /* eslint-disable no-console */
    console.warn('Unsupported browser requested, ignoring: ', browserValue);
    /* eslint-enable no-console */
  }

  if(process.env.SELENIUM_PLATFORM) {
    saucelabsProperties[platformKey] = process.env.SELENIUM_PLATFORM;
  }

  // Parse any prefixed general environment variables,
  // e.g. SAUCELABS_BUILD on teamcity.
  Object.keys(process.env).forEach(function(key) {
    if(/^SAUCELABS_.*/.test(key)) {
      var sanitisedKey = key
        .replace(/^SAUCELABS_/, '')
        .split(/_/)
        .map(function (item) { return item.toLowerCase(); })
        .join(' ');
      sanitisedKey = toCamelCase(sanitisedKey);
      saucelabsProperties[sanitisedKey] = process.env[key];
    }
  });

  return saucelabsProperties;
}

module.exports = function seleniumHooks() {
  // Lets give browser a minute to start up
  this.Before({ tags: ['@ui-automation'], timeout: 60 * 1000}, function(scenario, callback) {
    var world = this;
    var timeoutManager;

    // Lazy require WebDriver so it isn't pulled in for non-selenium tests.
    webdriver = require('selenium-webdriver');

    var capabilities = getCustomCapabilitiesFromEnvironment(webdriver);

    // Set the meta data for possbile use by SauceLabs.
    capabilities.name = scenario.getName() || undefined;
    capabilities.tags = scenario.getTags().map((t) => t.getName()) || undefined;

    // this is defaults, can be overriden through environment variables
    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_builder_class_Builder.html
    try {
      var driver = world.browser = new webdriver.Builder()
        .withCapabilities(capabilities)
        .build();

      driver.getSession()
          .then(function () {
            // Manage timeouts.
            timeoutManager = driver.manage().timeouts();
            timeoutManager.pageLoadTimeout(pageLoadTimeoutms);
            timeoutManager.implicitlyWait(implicitlyWaitTimeoutms);

            callback();
          });
    } catch (error) {
      callback(error);
    }
  });

  // Tidy up.
  this.After('@ui-automation', function(scenario, callback) {
    var browser = this.browser;

    var status = scenario.isSuccessful() ? 'passed' : 'failed';

    browser.getSession()
      .then(function () {
        return browser.executeScript('sauce:job-result=' + status);
      })
      .catch(function () {
      })
      .then(function () {
        return browser.quit();
      })
      .then(function () {
        callback();
      });
  });
};
<commit_msg>Adding browser maximise<commit_after>/**
 * Set up Selenium WebDriver for UI tests.
 */
'use strict';

var webdriver;

var pageLoadTimeoutms = 60 * 1000;
var implicitlyWaitTimeoutms = 1 * 1000;

/*
 * Convert a string to camel case.
 * @param  String string The string to modify.
 * @return String        The modified string.
 */
function toCamelCase(string) {
  return string.replace(/^([A-Z])|\s(\w)/g, function(match, p1, p2) {
    if (p2) {
      return p2.toUpperCase();
    }
    return p1.toLowerCase();
  });
}

function getCustomCapabilitiesFromEnvironment(webdriver) {
  var saucelabsProperties = {};

  var browserKey = webdriver.Capability.BROWSER_NAME;
  var platformKey = webdriver.Capability.PLATFORM_NAME;

  var browserValue = process.env.SELENIUM_BROWSER || webdriver.Browser.FIREFOX;

  // Object.values() will be in ES7, but until then...
  let validBrowser = false;
  for (let key in webdriver.Browser) {
    validBrowser = webdriver.Browser[key] === browserValue;
    if (validBrowser) {
      break;
    }
  }

  if (validBrowser) {
    saucelabsProperties[browserKey] = browserValue;
  } else {
    /* eslint-disable no-console */
    console.warn('Unsupported browser requested, ignoring: ', browserValue);
    /* eslint-enable no-console */
  }

  if(process.env.SELENIUM_PLATFORM) {
    saucelabsProperties[platformKey] = process.env.SELENIUM_PLATFORM;
  }

  // Parse any prefixed general environment variables,
  // e.g. SAUCELABS_BUILD on teamcity.
  Object.keys(process.env).forEach(function(key) {
    if(/^SAUCELABS_.*/.test(key)) {
      var sanitisedKey = key
        .replace(/^SAUCELABS_/, '')
        .split(/_/)
        .map(function (item) { return item.toLowerCase(); })
        .join(' ');
      sanitisedKey = toCamelCase(sanitisedKey);
      saucelabsProperties[sanitisedKey] = process.env[key];
    }
  });

  return saucelabsProperties;
}

module.exports = function seleniumHooks() {
  // Lets give browser a minute to start up
  this.Before({ tags: ['@ui-automation'], timeout: 60 * 1000}, function(scenario, callback) {
    var world = this;
    var timeoutManager;

    // Lazy require WebDriver so it isn't pulled in for non-selenium tests.
    webdriver = require('selenium-webdriver');

    var capabilities = getCustomCapabilitiesFromEnvironment(webdriver);

    // Set the meta data for possbile use by SauceLabs.
    capabilities.name = scenario.getName() || undefined;
    capabilities.tags = scenario.getTags().map((t) => t.getName()) || undefined;

    // this is defaults, can be overriden through environment variables
    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_builder_class_Builder.html
    try {
      var driver = world.browser = new webdriver.Builder()
        .withCapabilities(capabilities)
        .build();

      driver.getSession()
          .then(function () {
            // Manage timeouts.
            timeoutManager = driver.manage().timeouts();
            timeoutManager.pageLoadTimeout(pageLoadTimeoutms);
            timeoutManager.implicitlyWait(implicitlyWaitTimeoutms);

            driver.manage().window().maximize()
                .then(function () {
                  callback();
                });

          });
    } catch (error) {
      callback(error);
    }
  });

  // Tidy up.
  this.After('@ui-automation', function(scenario, callback) {
    var browser = this.browser;

    var status = scenario.isSuccessful() ? 'passed' : 'failed';

    browser.getSession()
      .then(function () {
        return browser.executeScript('sauce:job-result=' + status);
      })
      .catch(function () {
      })
      .then(function () {
        return browser.quit();
      })
      .then(function () {
        callback();
      });
  });
};
<|endoftext|>


<commit_before>require('babel-register')

const config = require('../config')
const server = require('../server/app')
const debug = require('debug')('app:bin:server')

const host = config.server_host
const port = config.server_port

server.listen(port, host, function () {
  debug('Server is now running at ' + host + ':' + port + '.')
})
<commit_msg>Remove host<commit_after>require('babel-register')

const config = require('../config')
const server = require('../server/app')
const debug = require('debug')('app:bin:server')

const host = config.server_host
const port = config.server_port

server.listen(port, function () {
  debug('Server is now running at port ' + port + '.')
})
<|endoftext|>


<commit_before>// Save a reference to the global object (`window` in the browser, `global`
// on the server).
var root = this;

// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
var App, server = false;
if (typeof exports !== 'undefined') {
    App = exports;
    server = true;
} else {
    App = root.App = {};
}

// Require Underscore, Backbone & BackboneIO, if we're on the server, and it's not already present.
var _ = root._;
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');

var BackboneIO = root.BackboneIO;
if ((typeof require !== 'undefined')) Backbone = require('backbone');

App.Model = Backbone.Model.extend({
    urlRoot: 'app',
    backend: 'appbackend',
    idAttribute: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new App.Model');

        return Backbone.Model.prototype.initialize.call (this);
    },
});

App.Status = Backbone.Model.extend ({
    backend: 'statusbackend',
    urlRoot: 'status',
    idAttribute: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('STATUS got from backend:', method, model);
            });
        }
        console.log ('creating new STATUS');

        return Backbone.Model.prototype.initialize.call (this);
    },
    defaults: {
        _id: 2,
        piece: {
            previous: {name: ''},
            current:  {name: '', progress: '0%'},
            next:     {name: ''},
        },
        show: {
            previous: {name: ''},
            current:  {name: '', progress: '0%'},
            next:     {name: ''},
        },
        source: null,
        on_air: false,
    },
});

App.ProgressStatus = Backbone.Model.extend({
    urlRoot: 'status-progress',
    backend: 'statusbackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new App.Model');

        return Backbone.Model.prototype.initialize.call (this);
    },
    defaults: {
        currentFrame: 0,
        totalFrames: 0,
    },
});

if(server) module.exports = App;
else root.App = App;
<commit_msg>add default ID to make sure always the same object is returned<commit_after>// Save a reference to the global object (`window` in the browser, `global`
// on the server).
var root = this;

// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
var App, server = false;
if (typeof exports !== 'undefined') {
    App = exports;
    server = true;
} else {
    App = root.App = {};
}

// Require Underscore, Backbone & BackboneIO, if we're on the server, and it's not already present.
var _ = root._;
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');

var BackboneIO = root.BackboneIO;
if ((typeof require !== 'undefined')) Backbone = require('backbone');

App.Model = Backbone.Model.extend({
    urlRoot: 'app',
    backend: 'appbackend',
    idAttribute: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new App.Model');

        return Backbone.Model.prototype.initialize.call (this);
    },
});

App.Status = Backbone.Model.extend ({
    backend: 'statusbackend',
    urlRoot: 'status',
    idAttribute: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('STATUS got from backend:', method, model);
            });
        }
        console.log ('creating new STATUS');

        return Backbone.Model.prototype.initialize.call (this);
    },
    defaults: {
        _id: 2,
        piece: {
            previous: {name: ''},
            current:  {name: '', progress: '0%'},
            next:     {name: ''},
        },
        show: {
            previous: {name: ''},
            current:  {name: '', progress: '0%'},
            next:     {name: ''},
        },
        source: null,
        on_air: false,
    },
});

App.ProgressStatus = Backbone.Model.extend({
    urlRoot: 'status-progress',
    backend: 'statusbackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();

            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new App.Model');

        return Backbone.Model.prototype.initialize.call (this);
    },
    defaults: {
        id: 3,
        currentFrame: 0,
        totalFrames: 0,
    },
});

if(server) module.exports = App;
else root.App = App;
<|endoftext|>


<commit_before>var _,
    csv,
    download,
    downloads,
    destination,
    filename,
    fs,
    mongoose,
    processRats,
    processRescues,
    Rat,
    ratSheet,
    removeArchives,
    winston

// Node Modules
_ = require( 'underscore' )
csv = require( 'csv' )
download = require( 'download' )
fs = require( 'fs' )
mongoose = require( 'mongoose' )
winston = require( 'winston' )

// Mongoose Models
Rat = require( '../api/models/rat' )
Rescue = require( '../api/models/rescue' )

mongoose.Promise = global.Promise

// Google Sheet URLs
spreadsheets = {
  rats: {
    workbookId: '1JoTrC3TmBNFkEtU6lWcGhOZkUaRr9YUY24kLA5LQnoc',
    sheetId: '445147052'
  },
  rescues: {
    workbookId: '1JoTrC3TmBNFkEtU6lWcGhOZkUaRr9YUY24kLA5LQnoc',
    sheetId: '1657880365'
  },
  rescueDrilledRats: {
    workbookId: '1_e0kJcMqjzoDfB2qRPYRIdR3naeEA19Y-ZzmYHo6yzE',
    sheetId: '72806282'
  },
  dispatchDrilledRats: {
    workbookId: '1_e0kJcMqjzoDfB2qRPYRIdR3naeEA19Y-ZzmYHo6yzE',
    sheetId: '84232353'
  }
}

// Config options
destinationFolder = 'data'

// Array to store our download promises in
downloads = []

mongoose.connect( 'mongodb://localhost/fuelrats' )

processRats = function ( ratData, rescueDrills, dispatchDrills ) {
  winston.info( 'Processing rats' )

  return new Promise( function ( resolve, reject ) {
    var rats

    rats = []

    ratData.forEach( function ( ratDatum, index, ratData ) {
      var dispatchDrill, rat, rescueDrill

      rat = {
        archive: true,
        drilled: {
          dispatch: false,
          rescue: false
        },
        joined: new Date( ratDatum[0] ) || new Date,
        rescues: []
      }
      console.log(rat.joined)

      if ( dispatchDrill = _.findWhere( dispatchDrills, { 3: ratDatum[2] } ) ) {
        rat.drilled.dispatch = dispatchDrill[4].toLowerCase() === 'pass'
      }

      if ( rescueDrill = _.findWhere( rescueDrills, { 3: ratDatum[2] } ) ) {
        rat.drilled.rescue = rescueDrill[4].toLowerCase() === 'pass'
      }

      if ( ratDatum[1] === 'CMDR' || ratDatum[1] === 'GameTag' ) {
        rat.CMDRname = ratDatum[2]
      }

      if ( ratDatum[1] === 'GameTag' ) {
        rat.platform = 'xb'
      }

      if ( rat.CMDRname ) {
        rats.push( Rat.create( rat ) )
      }
    })

    Promise.all( rats )
    .then( resolve )
    .catch( reject )
  })
}

processRescues = function ( rescuesData ) {
  winston.info( 'Processing rescues' )

  return new Promise( function ( resolve, reject ) {
    var rescues

    rescues = []

    rescuesData.forEach( function ( rescueDatum, index, rescuesData ) {
      var rescue

      rescue = {
        archive: true,
        createdAt: new Date( rescueDatum[0] ),
        notes: rescueDatum[4],
        open: false,
        rats: [],
        tempRats: [rescueDatum[1]],
        successful: rescueDatum[3].toLowerCase() === 'successful' ? true : false,
        system: rescueDatum[2]
      }

      rescues.push( Rescue.create( rescue ) )
    })

    Promise.all( rescues )
    .then( resolve )
    .catch( reject )
  })
}

removeArchives = function removeArchives ( models ) {
  winston.info( 'Removing archives' )

  return new Promise( function ( resolve, reject ) {
    var promises

    promises = []

    models.forEach( function ( model, index, models ) {
      promises.push( model.remove( { archive: true } ) )
    })

    Promise.all( promises )
    .then( resolve )
    .catch( reject )
  })
}

// Download all of the spreadsheets
winston.info( 'Downloading spreadsheets' )
Object.keys( spreadsheets ).forEach( function ( name, index, names ) {
  var url, spreadsheet

  spreadsheet = spreadsheets[name]
  url = 'https://docs.google.com/spreadsheets/d/' + spreadsheet.workbookId + '/export?gid=' + spreadsheet.sheetId + '&format=csv'

  downloads.push( new Promise( function ( resolve, reject ) {
    download()
    .get( url )
    .dest( destinationFolder )
    .rename( name + '.csv' )
    .run( function ( error ) {
      if ( error ) {
        reject( error )
      } else {
        winston.info( 'Parsing spreadsheet:', name )
        csv.parse( fs.readFileSync( destinationFolder + '/' + name + '.csv' ), function ( error, data ) {
          if ( error ) {
            reject( error )
          } else {
            spreadsheets[name].data = data
            resolve()
          }
        })
      }
    })
  }))
})

Promise.all( downloads )
.then( function () {
  var dispatchDrills, promises, rats, removals, rescues, rescueDrills

  promises = []

  dispatchDrills = spreadsheets.dispatchDrilledRats.data
  rats = spreadsheets.rats.data
  rescues = spreadsheets.rescues.data
  rescueDrills = spreadsheets.rescueDrilledRats.data

  rats.shift()
  rescues.shift()

  // Clear out the archives
  removeArchives( [ Rat, Rescue ] )
  .then( function () {
    var promises

    promises = []

    promises.push( processRats( rats, rescueDrills, dispatchDrills ) )
    promises.push( processRescues( rescues ) )

    Promise.all( promises )
    .then( function () {
      var promises

      promises = []

      promises.push( Rat.count({}) )
      promises.push( Rescue.count({}) )

      Promise.all( promises )
      .then( function ( results ) {
        var newRatCount, newRescuesCount, oldRatCount, oldRescuesCount

        newRatCount = rats.length
        newRescuesCount = rescues.length
        oldRatCount = results[0]
        oldRescuesCount = results[1]

        winston.info( 'Created', newRatCount, 'rats,', oldRatCount, 'total' )
        winston.info( 'Created', newRescuesCount, 'rescues,', oldRescuesCount, 'total' )

        mongoose.disconnect()
      })
      .catch( function ( error ) {
        winston.error( error )
      })
    })
    .catch( function ( error ) {
      winston.error( error )
    })
  })
  .catch( function ( error ) {
    winston.error( error )
  })
})
.catch( function ( error ) {
  winston.error( error )
})
<commit_msg>update import to use the unidentifiedRats field instead of tempRats<commit_after>var _,
    csv,
    download,
    downloads,
    destination,
    filename,
    fs,
    mongoose,
    processRats,
    processRescues,
    Rat,
    ratSheet,
    removeArchives,
    winston

// Node Modules
_ = require( 'underscore' )
csv = require( 'csv' )
download = require( 'download' )
fs = require( 'fs' )
mongoose = require( 'mongoose' )
winston = require( 'winston' )

// Mongoose Models
Rat = require( '../api/models/rat' )
Rescue = require( '../api/models/rescue' )

mongoose.Promise = global.Promise

// Google Sheet URLs
spreadsheets = {
  rats: {
    workbookId: '1JoTrC3TmBNFkEtU6lWcGhOZkUaRr9YUY24kLA5LQnoc',
    sheetId: '445147052'
  },
  rescues: {
    workbookId: '1JoTrC3TmBNFkEtU6lWcGhOZkUaRr9YUY24kLA5LQnoc',
    sheetId: '1657880365'
  },
  rescueDrilledRats: {
    workbookId: '1_e0kJcMqjzoDfB2qRPYRIdR3naeEA19Y-ZzmYHo6yzE',
    sheetId: '72806282'
  },
  dispatchDrilledRats: {
    workbookId: '1_e0kJcMqjzoDfB2qRPYRIdR3naeEA19Y-ZzmYHo6yzE',
    sheetId: '84232353'
  }
}

// Config options
destinationFolder = 'data'

// Array to store our download promises in
downloads = []

mongoose.connect( 'mongodb://localhost/fuelrats' )

processRats = function ( ratData, rescueDrills, dispatchDrills ) {
  winston.info( 'Processing rats' )

  return new Promise( function ( resolve, reject ) {
    var rats

    rats = []

    ratData.forEach( function ( ratDatum, index, ratData ) {
      var dispatchDrill, rat, rescueDrill

      rat = {
        archive: true,
        drilled: {
          dispatch: false,
          rescue: false
        },
        joined: new Date( ratDatum[0] ) || new Date,
        rescues: []
      }
      console.log(rat.joined)

      if ( dispatchDrill = _.findWhere( dispatchDrills, { 3: ratDatum[2] } ) ) {
        rat.drilled.dispatch = dispatchDrill[4].toLowerCase() === 'pass'
      }

      if ( rescueDrill = _.findWhere( rescueDrills, { 3: ratDatum[2] } ) ) {
        rat.drilled.rescue = rescueDrill[4].toLowerCase() === 'pass'
      }

      if ( ratDatum[1] === 'CMDR' || ratDatum[1] === 'GameTag' ) {
        rat.CMDRname = ratDatum[2]
      }

      if ( ratDatum[1] === 'GameTag' ) {
        rat.platform = 'xb'
      }

      if ( rat.CMDRname ) {
        rats.push( Rat.create( rat ) )
      }
    })

    Promise.all( rats )
    .then( resolve )
    .catch( reject )
  })
}

processRescues = function ( rescuesData ) {
  winston.info( 'Processing rescues' )

  return new Promise( function ( resolve, reject ) {
    var rescues

    rescues = []

    rescuesData.forEach( function ( rescueDatum, index, rescuesData ) {
      var rescue

      rescue = {
        archive: true,
        createdAt: new Date( rescueDatum[0] ),
        notes: rescueDatum[4],
        open: false,
        rats: [],
        unidentifiedRats: [rescueDatum[1]],
        successful: rescueDatum[3].toLowerCase() === 'successful' ? true : false,
        system: rescueDatum[2]
      }

      rescues.push( Rescue.create( rescue ) )
    })

    Promise.all( rescues )
    .then( resolve )
    .catch( reject )
  })
}

removeArchives = function removeArchives ( models ) {
  winston.info( 'Removing archives' )

  return new Promise( function ( resolve, reject ) {
    var promises

    promises = []

    models.forEach( function ( model, index, models ) {
      promises.push( model.remove( { archive: true } ) )
    })

    Promise.all( promises )
    .then( resolve )
    .catch( reject )
  })
}

// Download all of the spreadsheets
winston.info( 'Downloading spreadsheets' )
Object.keys( spreadsheets ).forEach( function ( name, index, names ) {
  var url, spreadsheet

  spreadsheet = spreadsheets[name]
  url = 'https://docs.google.com/spreadsheets/d/' + spreadsheet.workbookId + '/export?gid=' + spreadsheet.sheetId + '&format=csv'

  downloads.push( new Promise( function ( resolve, reject ) {
    download()
    .get( url )
    .dest( destinationFolder )
    .rename( name + '.csv' )
    .run( function ( error ) {
      if ( error ) {
        reject( error )
      } else {
        winston.info( 'Parsing spreadsheet:', name )
        csv.parse( fs.readFileSync( destinationFolder + '/' + name + '.csv' ), function ( error, data ) {
          if ( error ) {
            reject( error )
          } else {
            spreadsheets[name].data = data
            resolve()
          }
        })
      }
    })
  }))
})

Promise.all( downloads )
.then( function () {
  var dispatchDrills, promises, rats, removals, rescues, rescueDrills

  promises = []

  dispatchDrills = spreadsheets.dispatchDrilledRats.data
  rats = spreadsheets.rats.data
  rescues = spreadsheets.rescues.data
  rescueDrills = spreadsheets.rescueDrilledRats.data

  rats.shift()
  rescues.shift()

  // Clear out the archives
  removeArchives( [ Rat, Rescue ] )
  .then( function () {
    var promises

    promises = []

    promises.push( processRats( rats, rescueDrills, dispatchDrills ) )
    promises.push( processRescues( rescues ) )

    Promise.all( promises )
    .then( function () {
      var promises

      promises = []

      promises.push( Rat.count({}) )
      promises.push( Rescue.count({}) )

      Promise.all( promises )
      .then( function ( results ) {
        var newRatCount, newRescuesCount, oldRatCount, oldRescuesCount

        newRatCount = rats.length
        newRescuesCount = rescues.length
        oldRatCount = results[0]
        oldRescuesCount = results[1]

        winston.info( 'Created', newRatCount, 'rats,', oldRatCount, 'total' )
        winston.info( 'Created', newRescuesCount, 'rescues,', oldRescuesCount, 'total' )

        mongoose.disconnect()
      })
      .catch( function ( error ) {
        winston.error( error )
      })
    })
    .catch( function ( error ) {
      winston.error( error )
    })
  })
  .catch( function ( error ) {
    winston.error( error )
  })
})
.catch( function ( error ) {
  winston.error( error )
})
<|endoftext|>