<commit_before>/*jshint strict:false, undef:false, unused:false, latedef:false */

var getNodeBefore = function ( node, offset ) {
    var children = node.childNodes;
    while ( offset && node.nodeType === ELEMENT_NODE ) {
        node = children[ offset - 1 ];
        children = node.childNodes;
        offset = children.length;
    }
    return node;
};

var getNodeAfter = function ( node, offset ) {
    if ( node.nodeType === ELEMENT_NODE ) {
        var children = node.childNodes;
        if ( offset < children.length ) {
            node = children[ offset ];
        } else {
            while ( node && !node.nextSibling ) {
                node = node.parentNode;
            }
            if ( node ) { node = node.nextSibling; }
        }
    }
    return node;
};

// ---

var forEachTextNodeInRange = function ( range, fn ) {
    range = range.cloneRange();
    moveRangeBoundariesDownTree( range );

    var startContainer = range.startContainer,
        endContainer = range.endContainer,
        root = range.commonAncestorContainer,
        walker = new TreeWalker(
            root, SHOW_TEXT, function (/* node */) {
                return true;
        }, false ),
        textnode = walker.currentNode = startContainer;

    while ( !fn( textnode, range ) &&
        textnode !== endContainer &&
        ( textnode = walker.nextNode() ) ) {}
};

var getTextContentInRange = function ( range ) {
    var textContent = '';
    forEachTextNodeInRange( range, function ( textnode, range ) {
        var value = textnode.data;
        if ( value && ( /\S/.test( value ) ) ) {
            if ( textnode === range.endContainer ) {
                value = value.slice( 0, range.endOffset );
            }
            if ( textnode === range.startContainer ) {
                value = value.slice( range.startOffset );
            }
            textContent += value;
        }
    });
    return textContent;
};

// ---

var insertNodeInRange = function ( range, node ) {
    // Insert at start.
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        parent, children, childCount, afterSplit;

    // If part way through a text node, split it.
    if ( startContainer.nodeType === TEXT_NODE ) {
        parent = startContainer.parentNode;
        children = parent.childNodes;
        if ( startOffset === startContainer.length ) {
            startOffset = indexOf.call( children, startContainer ) + 1;
            if ( range.collapsed ) {
                endContainer = parent;
                endOffset = startOffset;
            }
        } else {
            if ( startOffset ) {
                afterSplit = startContainer.splitText( startOffset );
                if ( endContainer === startContainer ) {
                    endOffset -= startOffset;
                    endContainer = afterSplit;
                }
                else if ( endContainer === parent ) {
                    endOffset += 1;
                }
                startContainer = afterSplit;
            }
            startOffset = indexOf.call( children, startContainer );
        }
        startContainer = parent;
    } else {
        children = startContainer.childNodes;
    }

    childCount = children.length;

    if ( startOffset === childCount) {
        startContainer.appendChild( node );
    } else {
        startContainer.insertBefore( node, children[ startOffset ] );
    }

    if ( startContainer === endContainer ) {
        endOffset += children.length - childCount;
    }

    range.setStart( startContainer, startOffset );
    range.setEnd( endContainer, endOffset );
};

var extractContentsOfRange = function ( range, common ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset;

    if ( !common ) {
        common = range.commonAncestorContainer;
    }

    if ( common.nodeType === TEXT_NODE ) {
        common = common.parentNode;
    }

    var endNode = split( endContainer, endOffset, common ),
        startNode = split( startContainer, startOffset, common ),
        frag = common.ownerDocument.createDocumentFragment(),
        next, before, after;

    // End node will be null if at end of child nodes list.
    while ( startNode !== endNode ) {
        next = startNode.nextSibling;
        frag.appendChild( startNode );
        startNode = next;
    }

    startContainer = common;
    startOffset = endNode ?
        indexOf.call( common.childNodes, endNode ) :
        common.childNodes.length;

    // Merge text nodes if adjacent. IE10 in particular will not focus
    // between two text nodes
    after = common.childNodes[ startOffset ];
    before = after && after.previousSibling;
    if ( before &&
            before.nodeType === TEXT_NODE &&
            after.nodeType === TEXT_NODE ) {
        startContainer = before;
        startOffset = before.length;
        before.appendData( after.data );
        detach( after );
    }

    range.setStart( startContainer, startOffset );
    range.collapse( true );

    fixCursor( common );

    return frag;
};

var deleteContentsOfRange = function ( range ) {
    // Move boundaries up as much as possible to reduce need to split.
    moveRangeBoundariesUpTree( range );

    // Remove selected range
    extractContentsOfRange( range );

    // Move boundaries back down tree so that they are inside the blocks.
    // If we don't do this, the range may be collapsed to a point between
    // two blocks, so get(Start|End)BlockOfRange will return null.
    moveRangeBoundariesDownTree( range );

    // If we split into two different blocks, merge the blocks.
    var startBlock = getStartBlockOfRange( range ),
        endBlock = getEndBlockOfRange( range );
    if ( startBlock && endBlock && startBlock !== endBlock ) {
        mergeWithBlock( startBlock, endBlock, range );
    }

    // Ensure block has necessary children
    if ( startBlock ) {
        fixCursor( startBlock );
    }

    // Ensure body has a block-level element in it.
    var body = range.endContainer.ownerDocument.body,
        child = body.firstChild;
    if ( !child || child.nodeName === 'BR' ) {
        fixCursor( body );
        range.selectNodeContents( body.firstChild );
    }
};

// ---

var insertTreeFragmentIntoRange = function ( range, frag ) {
    // Check if it's all inline content
    var allInline = true,
        children = frag.childNodes,
        l = children.length;
    while ( l-- ) {
        if ( !isInline( children[l] ) ) {
            allInline = false;
            break;
        }
    }

    // Delete any selected content
    if ( !range.collapsed ) {
        deleteContentsOfRange( range );
    }

    // Move range down into text ndoes
    moveRangeBoundariesDownTree( range );

    // If inline, just insert at the current position.
    if ( allInline ) {
        insertNodeInRange( range, frag );
        range.collapse( false );
    }
    // Otherwise, split up to body, insert inline before and after split
    // and insert block in between split, then merge containers.
    else {
        var nodeAfterSplit = split( range.startContainer, range.startOffset,
                range.startContainer.ownerDocument.body ),
            nodeBeforeSplit = nodeAfterSplit.previousSibling,
            startContainer = nodeBeforeSplit,
            startOffset = startContainer.childNodes.length,
            endContainer = nodeAfterSplit,
            endOffset = 0,
            parent = nodeAfterSplit.parentNode,
            child, node;

        while ( ( child = startContainer.lastChild ) &&
                child.nodeType === ELEMENT_NODE &&
                child.nodeName !== 'BR' ) {
            startContainer = child;
            startOffset = startContainer.childNodes.length;
        }
        while ( ( child = endContainer.firstChild ) &&
                child.nodeType === ELEMENT_NODE &&
                child.nodeName !== 'BR' ) {
            endContainer = child;
        }
        while ( ( child = frag.firstChild ) && isInline( child ) ) {
            startContainer.appendChild( child );
        }
        while ( ( child = frag.lastChild ) && isInline( child ) ) {
            endContainer.insertBefore( child, endContainer.firstChild );
            endOffset += 1;
        }

        // Fix cursor then insert block(s)
        node = frag;
        while ( node = getNextBlock( node ) ) {
            fixCursor( node );
        }
        parent.insertBefore( frag, nodeAfterSplit );

        // Remove empty nodes created by split and merge inserted containers
        // with edges of split
        node = nodeAfterSplit.previousSibling;
        if ( !nodeAfterSplit.textContent ) {
            parent.removeChild( nodeAfterSplit );
        } else {
            mergeContainers( nodeAfterSplit );
        }
        if ( !nodeAfterSplit.parentNode ) {
            endContainer = node;
            endOffset = getLength( endContainer );
        }

        if ( !nodeBeforeSplit.textContent) {
            startContainer = nodeBeforeSplit.nextSibling;
            startOffset = 0;
            parent.removeChild( nodeBeforeSplit );
        } else {
            mergeContainers( nodeBeforeSplit );
        }

        range.setStart( startContainer, startOffset );
        range.setEnd( endContainer, endOffset );
        moveRangeBoundariesDownTree( range );
    }
};

// ---

var isNodeContainedInRange = function ( range, node, partial ) {
    var nodeRange = node.ownerDocument.createRange();

    nodeRange.selectNode( node );

    if ( partial ) {
        // Node must not finish before range starts or start after range
        // finishes.
        var nodeEndBeforeStart = ( range.compareBoundaryPoints(
                END_TO_START, nodeRange ) > -1 ),
            nodeStartAfterEnd = ( range.compareBoundaryPoints(
                START_TO_END, nodeRange ) < 1 );
        return ( !nodeEndBeforeStart && !nodeStartAfterEnd );
    }
    else {
        // Node must start after range starts and finish before range
        // finishes
        var nodeStartAfterStart = ( range.compareBoundaryPoints(
                START_TO_START, nodeRange ) < 1 ),
            nodeEndBeforeEnd = ( range.compareBoundaryPoints(
                END_TO_END, nodeRange ) > -1 );
        return ( nodeStartAfterStart && nodeEndBeforeEnd );
    }
};

var moveRangeBoundariesDownTree = function ( range ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        child;

    while ( startContainer.nodeType !== TEXT_NODE ) {
        child = startContainer.childNodes[ startOffset ];
        if ( !child || isLeaf( child ) ) {
            break;
        }
        startContainer = child;
        startOffset = 0;
    }
    if ( endOffset ) {
        while ( endContainer.nodeType !== TEXT_NODE ) {
            child = endContainer.childNodes[ endOffset - 1 ];
            if ( !child || isLeaf( child ) ) {
                break;
            }
            endContainer = child;
            endOffset = getLength( endContainer );
        }
    } else {
        while ( endContainer.nodeType !== TEXT_NODE ) {
            child = endContainer.firstChild;
            if ( !child || isLeaf( child ) ) {
                break;
            }
            endContainer = child;
        }
    }

    // If collapsed, this algorithm finds the nearest text node positions
    // *outside* the range rather than inside, but also it flips which is
    // assigned to which.
    if ( range.collapsed ) {
        range.setStart( endContainer, endOffset );
        range.setEnd( startContainer, startOffset );
    } else {
        range.setStart( startContainer, startOffset );
        range.setEnd( endContainer, endOffset );
    }
};

var moveRangeBoundariesUpTree = function ( range, common ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        parent;

    if ( !common ) {
        common = range.commonAncestorContainer;
    }

    while ( startContainer !== common && !startOffset ) {
        parent = startContainer.parentNode;
        startOffset = indexOf.call( parent.childNodes, startContainer );
        startContainer = parent;
    }

    while ( endContainer !== common &&
            endOffset === getLength( endContainer ) ) {
        parent = endContainer.parentNode;
        endOffset = indexOf.call( parent.childNodes, endContainer ) + 1;
        endContainer = parent;
    }

    range.setStart( startContainer, startOffset );
    range.setEnd( endContainer, endOffset );
};

// Returns the first block at least partially contained by the range,
// or null if no block is contained by the range.
var getStartBlockOfRange = function ( range ) {
    var container = range.startContainer,
        block;

    // If inline, get the containing block.
    if ( isInline( container ) ) {
        block = getPreviousBlock( container );
    } else if ( isBlock( container ) ) {
        block = container;
    } else {
        block = getNodeBefore( container, range.startOffset );
        block = getNextBlock( block );
    }
    // Check the block actually intersects the range
    return block && isNodeContainedInRange( range, block, true ) ? block : null;
};

// Returns the last block at least partially contained by the range,
// or null if no block is contained by the range.
var getEndBlockOfRange = function ( range ) {
    var container = range.endContainer,
        block, child;

    // If inline, get the containing block.
    if ( isInline( container ) ) {
        block = getPreviousBlock( container );
    } else if ( isBlock( container ) ) {
        block = container;
    } else {
        block = getNodeAfter( container, range.endOffset );
        if ( !block ) {
            block = container.ownerDocument.body;
            while ( child = block.lastChild ) {
                block = child;
            }
        }
        block = getPreviousBlock( block );

    }
    // Check the block actually intersects the range
    return block && isNodeContainedInRange( range, block, true ) ? block : null;
};

var contentWalker = new TreeWalker( null,
    SHOW_TEXT|SHOW_ELEMENT,
    function ( node ) {
        return node.nodeType === TEXT_NODE ?
            notWS.test( node.data ) :
            node.nodeName === 'IMG';
    }
);

var rangeDoesStartAtBlockBoundary = function ( range ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset;

    // If in the middle or end of a text node, we're not at the boundary.
    if ( startContainer.nodeType === TEXT_NODE ) {
        if ( startOffset ) {
            return false;
        }
        contentWalker.currentNode = startContainer;
    } else {
        contentWalker.currentNode = getNodeAfter( startContainer, startOffset );
    }

    // Otherwise, look for any previous content in the same block.
    contentWalker.root = getStartBlockOfRange( range );

    return !contentWalker.previousNode();
};

var rangeDoesEndAtBlockBoundary = function ( range ) {
    var endContainer = range.endContainer,
        endOffset = range.endOffset,
        length;

    // If in a text node with content, and not at the end, we're not
    // at the boundary
    if ( endContainer.nodeType === TEXT_NODE ) {
        length = endContainer.data.length;
        if ( length && endOffset < length ) {
            return false;
        }
        contentWalker.currentNode = endContainer;
    } else {
        contentWalker.currentNode = getNodeBefore( endContainer, endOffset );
    }

    // Otherwise, look for any further content in the same block.
    contentWalker.root = getEndBlockOfRange( range );

    return !contentWalker.nextNode();
};

var expandRangeToBlockBoundaries = function ( range ) {
    var start = getStartBlockOfRange( range ),
        end = getEndBlockOfRange( range ),
        parent;

    if ( start && end ) {
        parent = start.parentNode;
        range.setStart( parent, indexOf.call( parent.childNodes, start ) );
        parent = end.parentNode;
        range.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 );
    }
};
<commit_msg>fix typo: ndoes -> nodes<commit_after>/*jshint strict:false, undef:false, unused:false, latedef:false */

var getNodeBefore = function ( node, offset ) {
    var children = node.childNodes;
    while ( offset && node.nodeType === ELEMENT_NODE ) {
        node = children[ offset - 1 ];
        children = node.childNodes;
        offset = children.length;
    }
    return node;
};

var getNodeAfter = function ( node, offset ) {
    if ( node.nodeType === ELEMENT_NODE ) {
        var children = node.childNodes;
        if ( offset < children.length ) {
            node = children[ offset ];
        } else {
            while ( node && !node.nextSibling ) {
                node = node.parentNode;
            }
            if ( node ) { node = node.nextSibling; }
        }
    }
    return node;
};

// ---

var forEachTextNodeInRange = function ( range, fn ) {
    range = range.cloneRange();
    moveRangeBoundariesDownTree( range );

    var startContainer = range.startContainer,
        endContainer = range.endContainer,
        root = range.commonAncestorContainer,
        walker = new TreeWalker(
            root, SHOW_TEXT, function (/* node */) {
                return true;
        }, false ),
        textnode = walker.currentNode = startContainer;

    while ( !fn( textnode, range ) &&
        textnode !== endContainer &&
        ( textnode = walker.nextNode() ) ) {}
};

var getTextContentInRange = function ( range ) {
    var textContent = '';
    forEachTextNodeInRange( range, function ( textnode, range ) {
        var value = textnode.data;
        if ( value && ( /\S/.test( value ) ) ) {
            if ( textnode === range.endContainer ) {
                value = value.slice( 0, range.endOffset );
            }
            if ( textnode === range.startContainer ) {
                value = value.slice( range.startOffset );
            }
            textContent += value;
        }
    });
    return textContent;
};

// ---

var insertNodeInRange = function ( range, node ) {
    // Insert at start.
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        parent, children, childCount, afterSplit;

    // If part way through a text node, split it.
    if ( startContainer.nodeType === TEXT_NODE ) {
        parent = startContainer.parentNode;
        children = parent.childNodes;
        if ( startOffset === startContainer.length ) {
            startOffset = indexOf.call( children, startContainer ) + 1;
            if ( range.collapsed ) {
                endContainer = parent;
                endOffset = startOffset;
            }
        } else {
            if ( startOffset ) {
                afterSplit = startContainer.splitText( startOffset );
                if ( endContainer === startContainer ) {
                    endOffset -= startOffset;
                    endContainer = afterSplit;
                }
                else if ( endContainer === parent ) {
                    endOffset += 1;
                }
                startContainer = afterSplit;
            }
            startOffset = indexOf.call( children, startContainer );
        }
        startContainer = parent;
    } else {
        children = startContainer.childNodes;
    }

    childCount = children.length;

    if ( startOffset === childCount) {
        startContainer.appendChild( node );
    } else {
        startContainer.insertBefore( node, children[ startOffset ] );
    }

    if ( startContainer === endContainer ) {
        endOffset += children.length - childCount;
    }

    range.setStart( startContainer, startOffset );
    range.setEnd( endContainer, endOffset );
};

var extractContentsOfRange = function ( range, common ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset;

    if ( !common ) {
        common = range.commonAncestorContainer;
    }

    if ( common.nodeType === TEXT_NODE ) {
        common = common.parentNode;
    }

    var endNode = split( endContainer, endOffset, common ),
        startNode = split( startContainer, startOffset, common ),
        frag = common.ownerDocument.createDocumentFragment(),
        next, before, after;

    // End node will be null if at end of child nodes list.
    while ( startNode !== endNode ) {
        next = startNode.nextSibling;
        frag.appendChild( startNode );
        startNode = next;
    }

    startContainer = common;
    startOffset = endNode ?
        indexOf.call( common.childNodes, endNode ) :
        common.childNodes.length;

    // Merge text nodes if adjacent. IE10 in particular will not focus
    // between two text nodes
    after = common.childNodes[ startOffset ];
    before = after && after.previousSibling;
    if ( before &&
            before.nodeType === TEXT_NODE &&
            after.nodeType === TEXT_NODE ) {
        startContainer = before;
        startOffset = before.length;
        before.appendData( after.data );
        detach( after );
    }

    range.setStart( startContainer, startOffset );
    range.collapse( true );

    fixCursor( common );

    return frag;
};

var deleteContentsOfRange = function ( range ) {
    // Move boundaries up as much as possible to reduce need to split.
    moveRangeBoundariesUpTree( range );

    // Remove selected range
    extractContentsOfRange( range );

    // Move boundaries back down tree so that they are inside the blocks.
    // If we don't do this, the range may be collapsed to a point between
    // two blocks, so get(Start|End)BlockOfRange will return null.
    moveRangeBoundariesDownTree( range );

    // If we split into two different blocks, merge the blocks.
    var startBlock = getStartBlockOfRange( range ),
        endBlock = getEndBlockOfRange( range );
    if ( startBlock && endBlock && startBlock !== endBlock ) {
        mergeWithBlock( startBlock, endBlock, range );
    }

    // Ensure block has necessary children
    if ( startBlock ) {
        fixCursor( startBlock );
    }

    // Ensure body has a block-level element in it.
    var body = range.endContainer.ownerDocument.body,
        child = body.firstChild;
    if ( !child || child.nodeName === 'BR' ) {
        fixCursor( body );
        range.selectNodeContents( body.firstChild );
    }
};

// ---

var insertTreeFragmentIntoRange = function ( range, frag ) {
    // Check if it's all inline content
    var allInline = true,
        children = frag.childNodes,
        l = children.length;
    while ( l-- ) {
        if ( !isInline( children[l] ) ) {
            allInline = false;
            break;
        }
    }

    // Delete any selected content
    if ( !range.collapsed ) {
        deleteContentsOfRange( range );
    }

    // Move range down into text nodes
    moveRangeBoundariesDownTree( range );

    // If inline, just insert at the current position.
    if ( allInline ) {
        insertNodeInRange( range, frag );
        range.collapse( false );
    }
    // Otherwise, split up to body, insert inline before and after split
    // and insert block in between split, then merge containers.
    else {
        var nodeAfterSplit = split( range.startContainer, range.startOffset,
                range.startContainer.ownerDocument.body ),
            nodeBeforeSplit = nodeAfterSplit.previousSibling,
            startContainer = nodeBeforeSplit,
            startOffset = startContainer.childNodes.length,
            endContainer = nodeAfterSplit,
            endOffset = 0,
            parent = nodeAfterSplit.parentNode,
            child, node;

        while ( ( child = startContainer.lastChild ) &&
                child.nodeType === ELEMENT_NODE &&
                child.nodeName !== 'BR' ) {
            startContainer = child;
            startOffset = startContainer.childNodes.length;
        }
        while ( ( child = endContainer.firstChild ) &&
                child.nodeType === ELEMENT_NODE &&
                child.nodeName !== 'BR' ) {
            endContainer = child;
        }
        while ( ( child = frag.firstChild ) && isInline( child ) ) {
            startContainer.appendChild( child );
        }
        while ( ( child = frag.lastChild ) && isInline( child ) ) {
            endContainer.insertBefore( child, endContainer.firstChild );
            endOffset += 1;
        }

        // Fix cursor then insert block(s)
        node = frag;
        while ( node = getNextBlock( node ) ) {
            fixCursor( node );
        }
        parent.insertBefore( frag, nodeAfterSplit );

        // Remove empty nodes created by split and merge inserted containers
        // with edges of split
        node = nodeAfterSplit.previousSibling;
        if ( !nodeAfterSplit.textContent ) {
            parent.removeChild( nodeAfterSplit );
        } else {
            mergeContainers( nodeAfterSplit );
        }
        if ( !nodeAfterSplit.parentNode ) {
            endContainer = node;
            endOffset = getLength( endContainer );
        }

        if ( !nodeBeforeSplit.textContent) {
            startContainer = nodeBeforeSplit.nextSibling;
            startOffset = 0;
            parent.removeChild( nodeBeforeSplit );
        } else {
            mergeContainers( nodeBeforeSplit );
        }

        range.setStart( startContainer, startOffset );
        range.setEnd( endContainer, endOffset );
        moveRangeBoundariesDownTree( range );
    }
};

// ---

var isNodeContainedInRange = function ( range, node, partial ) {
    var nodeRange = node.ownerDocument.createRange();

    nodeRange.selectNode( node );

    if ( partial ) {
        // Node must not finish before range starts or start after range
        // finishes.
        var nodeEndBeforeStart = ( range.compareBoundaryPoints(
                END_TO_START, nodeRange ) > -1 ),
            nodeStartAfterEnd = ( range.compareBoundaryPoints(
                START_TO_END, nodeRange ) < 1 );
        return ( !nodeEndBeforeStart && !nodeStartAfterEnd );
    }
    else {
        // Node must start after range starts and finish before range
        // finishes
        var nodeStartAfterStart = ( range.compareBoundaryPoints(
                START_TO_START, nodeRange ) < 1 ),
            nodeEndBeforeEnd = ( range.compareBoundaryPoints(
                END_TO_END, nodeRange ) > -1 );
        return ( nodeStartAfterStart && nodeEndBeforeEnd );
    }
};

var moveRangeBoundariesDownTree = function ( range ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        child;

    while ( startContainer.nodeType !== TEXT_NODE ) {
        child = startContainer.childNodes[ startOffset ];
        if ( !child || isLeaf( child ) ) {
            break;
        }
        startContainer = child;
        startOffset = 0;
    }
    if ( endOffset ) {
        while ( endContainer.nodeType !== TEXT_NODE ) {
            child = endContainer.childNodes[ endOffset - 1 ];
            if ( !child || isLeaf( child ) ) {
                break;
            }
            endContainer = child;
            endOffset = getLength( endContainer );
        }
    } else {
        while ( endContainer.nodeType !== TEXT_NODE ) {
            child = endContainer.firstChild;
            if ( !child || isLeaf( child ) ) {
                break;
            }
            endContainer = child;
        }
    }

    // If collapsed, this algorithm finds the nearest text node positions
    // *outside* the range rather than inside, but also it flips which is
    // assigned to which.
    if ( range.collapsed ) {
        range.setStart( endContainer, endOffset );
        range.setEnd( startContainer, startOffset );
    } else {
        range.setStart( startContainer, startOffset );
        range.setEnd( endContainer, endOffset );
    }
};

var moveRangeBoundariesUpTree = function ( range, common ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset,
        endContainer = range.endContainer,
        endOffset = range.endOffset,
        parent;

    if ( !common ) {
        common = range.commonAncestorContainer;
    }

    while ( startContainer !== common && !startOffset ) {
        parent = startContainer.parentNode;
        startOffset = indexOf.call( parent.childNodes, startContainer );
        startContainer = parent;
    }

    while ( endContainer !== common &&
            endOffset === getLength( endContainer ) ) {
        parent = endContainer.parentNode;
        endOffset = indexOf.call( parent.childNodes, endContainer ) + 1;
        endContainer = parent;
    }

    range.setStart( startContainer, startOffset );
    range.setEnd( endContainer, endOffset );
};

// Returns the first block at least partially contained by the range,
// or null if no block is contained by the range.
var getStartBlockOfRange = function ( range ) {
    var container = range.startContainer,
        block;

    // If inline, get the containing block.
    if ( isInline( container ) ) {
        block = getPreviousBlock( container );
    } else if ( isBlock( container ) ) {
        block = container;
    } else {
        block = getNodeBefore( container, range.startOffset );
        block = getNextBlock( block );
    }
    // Check the block actually intersects the range
    return block && isNodeContainedInRange( range, block, true ) ? block : null;
};

// Returns the last block at least partially contained by the range,
// or null if no block is contained by the range.
var getEndBlockOfRange = function ( range ) {
    var container = range.endContainer,
        block, child;

    // If inline, get the containing block.
    if ( isInline( container ) ) {
        block = getPreviousBlock( container );
    } else if ( isBlock( container ) ) {
        block = container;
    } else {
        block = getNodeAfter( container, range.endOffset );
        if ( !block ) {
            block = container.ownerDocument.body;
            while ( child = block.lastChild ) {
                block = child;
            }
        }
        block = getPreviousBlock( block );

    }
    // Check the block actually intersects the range
    return block && isNodeContainedInRange( range, block, true ) ? block : null;
};

var contentWalker = new TreeWalker( null,
    SHOW_TEXT|SHOW_ELEMENT,
    function ( node ) {
        return node.nodeType === TEXT_NODE ?
            notWS.test( node.data ) :
            node.nodeName === 'IMG';
    }
);

var rangeDoesStartAtBlockBoundary = function ( range ) {
    var startContainer = range.startContainer,
        startOffset = range.startOffset;

    // If in the middle or end of a text node, we're not at the boundary.
    if ( startContainer.nodeType === TEXT_NODE ) {
        if ( startOffset ) {
            return false;
        }
        contentWalker.currentNode = startContainer;
    } else {
        contentWalker.currentNode = getNodeAfter( startContainer, startOffset );
    }

    // Otherwise, look for any previous content in the same block.
    contentWalker.root = getStartBlockOfRange( range );

    return !contentWalker.previousNode();
};

var rangeDoesEndAtBlockBoundary = function ( range ) {
    var endContainer = range.endContainer,
        endOffset = range.endOffset,
        length;

    // If in a text node with content, and not at the end, we're not
    // at the boundary
    if ( endContainer.nodeType === TEXT_NODE ) {
        length = endContainer.data.length;
        if ( length && endOffset < length ) {
            return false;
        }
        contentWalker.currentNode = endContainer;
    } else {
        contentWalker.currentNode = getNodeBefore( endContainer, endOffset );
    }

    // Otherwise, look for any further content in the same block.
    contentWalker.root = getEndBlockOfRange( range );

    return !contentWalker.nextNode();
};

var expandRangeToBlockBoundaries = function ( range ) {
    var start = getStartBlockOfRange( range ),
        end = getEndBlockOfRange( range ),
        parent;

    if ( start && end ) {
        parent = start.parentNode;
        range.setStart( parent, indexOf.call( parent.childNodes, start ) );
        parent = end.parentNode;
        range.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 );
    }
};
<|endoftext|>


<commit_before>"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
exports.__esModule = true;
var React = require("react");
var Unity = /** @class */ (function (_super) {
    __extends(Unity, _super);
    function Unity(props) {
        return _super.call(this, props) || this;
    }
    Unity.prototype.render = function () {
        return React.createElement("div", null, "Fullscreen? " + this.props.content.unityConfig.isFullscreen);
    };
    return Unity;
}(React.Component));
exports["default"] = Unity;
//# sourceMappingURL=Unity.js.map<commit_msg>Removed TSX artifacts<commit_after><|endoftext|>


<commit_before>import {sync as parse} from 'conventional-commits-parser';

export getConfiguration from './library/get-configuration';
export getMessages from './library/get-messages';
export getPreset from './library/get-preset';
export format from './library/format';

export default (message, options = {}) => {
	const {
		preset: {
			parserOpts: parserOptions
		},
		configuration: {
			rules,
			wildcards
		}
	} = options;

	const parsed = parse(message, parserOptions);

	// wildcard matches skip the linting
	const bails = Object.entries(wildcards || {})
		.filter(entry => {
			const [, pattern] = entry;
			return Array.isArray(pattern);
		})
		.filter(entry => {
			const [, pattern] = entry;
			const expression = new RegExp(...pattern);
			return parsed.header.match(expression);
		})
		.map(entry => entry[0]);

	if (bails.length > 0) {
		return {
			valid: true,
			wildcards: bails,
			rules: [],
			warnings: [],
			errors: []
		};
	}

	// validate against all rules
	const results = Object.entries(rules || {})
		.filter(entry => {
			const [, [level]] = entry;
			return level > 0;
		})
		.map(entry => {
			const [name, config] = entry;
			const [level, when, value] = config;

			// Level 0 rules are ignored
			if (level === 0) {
				return null;
			}

			const rule = require(`./rules/${name}`);
			const [valid, message] = rule(parsed, when, value);

			return {
				level,
				valid,
				name,
				message
			};
		})
		.filter(Boolean);

	const errors = results.filter(result =>
		result.level > 1 && !result.valid);

	const warnings = results.filter(result =>
		result.level < 2 && !result.valid);

	const valid = errors.length === 0;

	return {
		valid,
		errors,
		warnings
	};
};
<commit_msg>refactor: expose the entire commit message as raw to rules<commit_after>import {sync as parse} from 'conventional-commits-parser';
import {merge} from 'lodash';

export getConfiguration from './library/get-configuration';
export getMessages from './library/get-messages';
export getPreset from './library/get-preset';
export format from './library/format';

export default (message, options = {}) => {
	const {
		preset: {
			parserOpts: parserOptions
		},
		configuration: {
			rules,
			wildcards
		}
	} = options;

	const parsed = merge(
		{raw: message},
		parse(message, parserOptions)
	);

	// wildcard matches skip the linting
	const bails = Object.entries(wildcards || {})
		.filter(entry => {
			const [, pattern] = entry;
			return Array.isArray(pattern);
		})
		.filter(entry => {
			const [, pattern] = entry;
			const expression = new RegExp(...pattern);
			return parsed.header.match(expression);
		})
		.map(entry => entry[0]);

	if (bails.length > 0) {
		return {
			valid: true,
			wildcards: bails,
			rules: [],
			warnings: [],
			errors: []
		};
	}

	// validate against all rules
	const results = Object.entries(rules || {})
		.filter(entry => {
			const [, [level]] = entry;
			return level > 0;
		})
		.map(entry => {
			const [name, config] = entry;
			const [level, when, value] = config;

			// Level 0 rules are ignored
			if (level === 0) {
				return null;
			}

			const rule = require(`./rules/${name}`);
			const [valid, message] = rule(parsed, when, value);

			return {
				level,
				valid,
				name,
				message
			};
		})
		.filter(Boolean);

	const errors = results.filter(result =>
		result.level > 1 && !result.valid);

	const warnings = results.filter(result =>
		result.level < 2 && !result.valid);

	const valid = errors.length === 0;

	return {
		valid,
		errors,
		warnings
	};
};
<|endoftext|>


<commit_before>import bundle from './bundle';
import createBundler from './create-bundler';
import loadTransforms from './load-transforms';
import rewriteImports from './rewrite-imports';
import promiseBundle from './promise-bundle';

const defaultVendors = ['react', 'react-dom', 'classnames', 'classnames/bind'];

export default application => {
	return async (file, demo, configuration) => {
		const vendorCacheKey = ['browserify', 'vendor'].join(':');
		const applicationCacheKey = ['browserify', 'application', file.path].join(':');

		const transformConfig = configuration.transforms || {};

		// load browserify transforms
		const transforms = loadTransforms(transformConfig, application);

		// create bundler for external vendors
		const vendors = configuration.vendors || defaultVendors;
		const vendorBundler = createBundler(configuration.opts, []);
		vendors.forEach(lib => vendorBundler.require(lib));

		// create configured browserify bundler
		const bundler = createBundler(configuration.opts, transforms, application);
		bundler.external(vendors);

		// rewrite imports to global names
		const rewritten = rewriteImports(file);

		const vendorCode = application.cache.get(vendorCacheKey, file.mtime) ||
			await promiseBundle(vendorBundler);

		const applicationCode = application.cache.get(applicationCacheKey, file.mtime) ||
			await bundle(bundler, rewritten);

		application.cache.set(vendorCacheKey, file.mtime, vendorCode);
		application.cache.set(applicationCacheKey, file.mtime, applicationCode);

		// bundle the rewritten file
		file.buffer = `${vendorCode}\n\n${applicationCode}`;
		return file;
	};
};
<commit_msg>feat: run browserify bundlers in parallel<commit_after>import bundle from './bundle';
import createBundler from './create-bundler';
import loadTransforms from './load-transforms';
import rewriteImports from './rewrite-imports';
import promiseBundle from './promise-bundle';

const defaultVendors = ['react', 'react-dom', 'classnames', 'classnames/bind'];

export default application => {
	return async (file, demo, configuration) => {
		const vendorCacheKey = ['browserify', 'vendor'].join(':');
		const applicationCacheKey = ['browserify', 'application', file.path].join(':');
		const {cache} = application;

		const transformConfig = configuration.transforms || {};

		// load browserify transforms
		const transforms = loadTransforms(transformConfig, application);

		// create bundler for external vendors
		const vendors = configuration.vendors || defaultVendors;
		const vendorBundler = createBundler(configuration.opts, []);
		vendors.forEach(lib => vendorBundler.require(lib));

		// create configured browserify bundler
		const bundler = createBundler(configuration.opts, transforms, application);
		bundler.external(vendors);

		// rewrite imports to global names
		const rewritten = rewriteImports(file);

		const [vendorCode, applicationCode] = await Promise.all([
			cache.get(vendorCacheKey, file.mtime) || promiseBundle(vendorBundler),
			cache.get(applicationCacheKey, file.mtime) || bundle(bundler, rewritten)
		]);

		cache.set(vendorCacheKey, file.mtime, vendorCode);
		cache.set(applicationCacheKey, file.mtime, applicationCode);

		// bundle the rewritten file
		file.buffer = `${vendorCode}\n\n${applicationCode}`;
		return file;
	};
};
<|endoftext|>


<commit_before>/*
	Copyright (c) 2010, Micah N Gorrell
	All rights reserved.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
*/

var prefs =
{

defaults: {
	accounts: [],

	panels: [
		{ "type": "timeline"	},
		{ "type": "mentions"	},
		{ "type": "messages"	},
		{ "type": "favorites"	}
	],

	theme:				"light",
	toolbar:			"top",
	tabs:				"bottom",

	hideAvatar:			false,
	showUserName:		true,
	showScreenName:		true,
	showVia:			false,
	showTime:			"relative",

	fontSize:			"tiny"
},

ready: function(cb)
{
	if (chrome && chrome.storage) {
		/* Load all local and remote settings before continuing */
		chrome.storage.local.get(null, function(items) {
			this.local = items;

			chrome.storage.sync.get(null, function(items) {
				this.sync = items;

				cb();
			}.bind(this));
		}.bind(this));
	} else {
		/* Other storage mechanisms are already ready */
		cb();
	}
},

get: function get(name, account)
{
	var key		= name;
	var result	= null;
	var json	= null;

	if (account) {
		name += account.id;
	}

	if (chrome && chrome.storage) {
		/* Chrome storage is synced at load time */
		if ('undefined' != typeof(this.local[key])) {
			result = this.local[key];
		} else if ('undefined' != typeof(this.sync[key])) {
			result = this.sync[key];
		}
	} else if (window.localStorage) {
		json = window.localStorage.getItem(name);
	} else {
		json = enyo.getCookie(name);
	}

	if (!result) {
		try {
			if (json) {
				result = enyo.json.parse(json);
			} else {
				result = null;
			}
		} catch(e) {
			result = null;
		}
	}

	if (result == null) {
		result = this.defaults[key];
	}

	return(result);
},

set: function set(name, value, account)
{
	if (account) {
		name += account.id;
	}

	if (chrome && chrome.storage) {
		var data = {};

		data[name] = value;

		if ('undefined' != typeof(this.defaults[name])) {
			chrome.storage.sync.set(data);
		} else {
			chrome.storage.local.set(data);
		}
	} else if (window.localStorage) {
		window.localStorage.setItem(name,
			enyo.json.stringify(value));
	} else {
		enyo.setCookie(name, enyo.json.stringify(value));
	}

	if ('undefined' != typeof(this.defaults[name])) {
		this.updateClasses();
	}
},

/* Add a class based on the name of each boolean option if enabled */
updateClasses: function(component)
{
	var value;
	var classes	= [];

	if (component) {
		/* Remember the component for future calls */
		this.component = component;
	} else {
		/* Use the remembered component */
		component = this.component;
	}

	if (!component) {
		return;
	}

	for (var key in this.defaults) {
		switch (typeof(this.defaults[key])) {
			case "boolean":
				if (this.get(key)) {
					classes.push(key);
				}
				break;

			case "string":
				if ((value = this.get(key))) {
					classes.push(key + enyo.cap(value));
				}
				break;
		}
	}

	component.setClasses(classes.join(' '));
	console.log('User option classes: ' + component.getClasses());

	/* Ensure that the correct theme stylesheet is loaded */
	if (this.get('theme')) {
		var e = document.createElement("link");

		e.setAttribute("rel",	"stylesheet");
		e.setAttribute("type",	"text/css");
		e.setAttribute("href",	"assets/" + this.get('theme') + ".css");

		if (this.themeElement) {
			document.getElementsByTagName("head")[0].replaceChild(e, this.themeElement);
		} else {
			document.getElementsByTagName("head")[0].appendChild(e);
		}
		this.themeElement = e;
	}
}

};
<commit_msg>Corrected logic when changing preferences with chrome<commit_after>/*
	Copyright (c) 2010, Micah N Gorrell
	All rights reserved.

	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
*/

var prefs =
{

defaults: {
	accounts: [],

	panels: [
		{ "type": "timeline"	},
		{ "type": "mentions"	},
		{ "type": "messages"	},
		{ "type": "favorites"	}
	],

	theme:				"light",
	toolbar:			"top",
	tabs:				"bottom",

	hideAvatar:			false,
	showUserName:		true,
	showScreenName:		true,
	showVia:			false,
	showTime:			"relative",

	fontSize:			"tiny"
},

ready: function(cb)
{
	if (chrome && chrome.storage) {
		/* Load all local and remote settings before continuing */
		chrome.storage.local.get(null, function(items) {
			this.local = items;

			chrome.storage.sync.get(null, function(items) {
				this.sync = items;

				cb();
			}.bind(this));
		}.bind(this));
	} else {
		/* Other storage mechanisms are already ready */
		cb();
	}
},

get: function get(name, account)
{
	var key		= name;
	var result	= null;
	var json	= null;

	if (account) {
		name += account.id;
	}

	if (chrome && chrome.storage) {
		/* Chrome storage is synced at load time */
		if ('undefined' != typeof(this.local[key])) {
			result = this.local[key];
		} else if ('undefined' != typeof(this.sync[key])) {
			result = this.sync[key];
		}
	} else if (window.localStorage) {
		json = window.localStorage.getItem(name);
	} else {
		json = enyo.getCookie(name);
	}

	if (!result) {
		try {
			if (json) {
				result = enyo.json.parse(json);
			} else {
				result = null;
			}
		} catch(e) {
			result = null;
		}
	}

	if (result == null) {
		result = this.defaults[key];
	}

	return(result);
},

set: function set(name, value, account)
{
	if (account) {
		name += account.id;
	}

	if (chrome && chrome.storage) {
		var data = {};

		data[name] = value;

		if ('undefined' != typeof(this.defaults[name])) {
			chrome.storage.sync.set(data);
			this.sync[name] = value;
		} else {
			chrome.storage.local.set(data);
			this.local[name] = value;
		}
	} else if (window.localStorage) {
		window.localStorage.setItem(name,
			enyo.json.stringify(value));
	} else {
		enyo.setCookie(name, enyo.json.stringify(value));
	}

	if ('undefined' != typeof(this.defaults[name])) {
		this.updateClasses();
	}
},

/* Add a class based on the name of each boolean option if enabled */
updateClasses: function(component)
{
	var value;
	var classes	= [];

	if (component) {
		/* Remember the component for future calls */
		this.component = component;
	} else {
		/* Use the remembered component */
		component = this.component;
	}

	if (!component) {
		return;
	}

	for (var key in this.defaults) {
		switch (typeof(this.defaults[key])) {
			case "boolean":
				if (this.get(key)) {
					classes.push(key);
				}
				break;

			case "string":
				if ((value = this.get(key))) {
					classes.push(key + enyo.cap(value));
				}
				break;
		}
	}

	component.setClasses(classes.join(' '));
	console.log('User option classes: ' + component.getClasses());

	/* Ensure that the correct theme stylesheet is loaded */
	if (this.get('theme')) {
		var e = document.createElement("link");

		e.setAttribute("rel",	"stylesheet");
		e.setAttribute("type",	"text/css");
		e.setAttribute("href",	"assets/" + this.get('theme') + ".css");

		if (this.themeElement) {
			document.getElementsByTagName("head")[0].replaceChild(e, this.themeElement);
		} else {
			document.getElementsByTagName("head")[0].appendChild(e);
		}
		this.themeElement = e;
	}
}

};
<|endoftext|>


<commit_before>//
// Backbone-associations.js 0.2.0
//
// (c) 2012 Dhruva Ray, Jaynti Kanani
//
// Backbone-associations may be freely distributed under the MIT license; see the accompanying LICENSE.txt.
//
// Depends on [Backbone](https://github.com/documentcloud/backbone) (and thus on [Underscore](https://github.com/documentcloud/underscore/) as well)
//
// A complete [Test & Benchmark Suite](../test/test-suite.html) is included for your perusal.

// Initial Setup
// --------------
(function () {
    "use strict";

    // The top-level namespace. All public Backbone classes and modules will be attached to this.
    // Exported for the browser and CommonJS.
    var _, Backbone, BackboneModel, defaultEvents;
    if (typeof require !== 'undefined') {
        _ = require('underscore');
        Backbone = require('backbone');
        exports = module.exports = Backbone;
    } else {
        _ = window._;
        Backbone = window.Backbone;
    }

    BackboneModel = Backbone.Model.prototype;
    defaultEvents = ["change", "add", "remove", "reset", "destroy", "sync", "error"];

    // Backbone.AssociatedModel
    // --------------

    //Add `Many` and `One` relations to Backbone Object
    Backbone.Many = "Many";
    Backbone.One = "One";
    //Define `AssociatedModel` (Extends Backbone.Model)
    Backbone.AssociatedModel = Backbone.Model.extend({
        //Define relations with Associated Model
        relations:undefined,
        _proxyCalls:undefined,
        //Set a hash of model attributes on the object,
        //firing `"change"` unless you choose to silence it.
        //It maintains relations between models during the set operation. It also bubbles up child events to the parent.
        set:function (key, value, options) {
            var attributes, processedRelations, tbp, attr;
            // Duplicate backbone's behavior to allow separate key/value parameters, instead of a single 'attributes' object.
            if (_.isObject(key) || key == null) {
                attributes = key;
                options = value;
            } else {
                attributes = {};
                attributes[key] = value;
            }
            // Extract attributes and options.
            options || (options = {});
            if (!attributes) return this;
            if (options.unset) for (attr in attributes) attributes[attr] = void 0;
            //Check for existence of relations in this model
            if (this.relations) {
                //Iterate over `this.relations` and `set` model and collection values
                _.each(this.relations, function (relation) {
                    var relationKey = relation.key, relatedModel = relation.relatedModel, collectionType = relation.collectionType,
                        val, relationOptions, data;
                    if (attributes[relationKey]) {
                        //Get value of attribute with relation key in `val`
                        val = _.result(attributes, relationKey);
                        //Get class if relation is stored as a string
                        relatedModel && _.isString(relatedModel) && (relatedModel = eval(relatedModel));
                        collectionType && _.isString(collectionType) && (collectionType = eval(collectionType));
                        //Merge in options specific to this relation
                        relationOptions = relation.options ? _.extend({}, relation.options, options) : options;
                        //If `relation` defines model as associated collection...
                        if (relation.type === Backbone.Many) {
                            //`collectionType` should be instance of `Backbone.Collection`
                            if (collectionType && !collectionType.prototype instanceof Backbone.Collection) {
                                throw new Error('collectionType must inherit from Backbone.Collection');
                            }

                            if (val instanceof Backbone.Collection) {
                                BackboneModel.set.call(this, relationKey, val, relationOptions);
                            } else if (!this.attributes[relationKey]) {
                                data = collectionType ? new collectionType() : this._createCollection(relatedModel);
                                data.add(val, relationOptions);
                                BackboneModel.set.call(this, relationKey, data, relationOptions);
                            } else {
                                this.attributes[relationKey].reset(val, relationOptions);
                            }

                            //If `relation` defines model as associated model...
                        } else if (relation.type === Backbone.One && relatedModel) {
                            if (val instanceof Backbone.AssociatedModel) {
                                BackboneModel.set.call(this, relationKey, val, relationOptions);
                            } else { //if (!this.attributes[relationKey]) {
                                data = new relatedModel(val);
                                BackboneModel.set.call(this, relationKey, data, relationOptions);
                            }
                        }

                        //Add proxy events to respective parents. Only add callback if not defined
                        if (!this.attributes[relationKey]._proxyCallback) {
                            this.attributes[relationKey]._proxyCallback = function () {
                                var args = arguments,
                                    opt = args[0].split(":"),
                                    eventType = opt[0],
                                    eventObject = args[1],
                                    indexEventObject = -1,
                                    _proxyCalls = this.attributes[relationKey]._proxyCalls,
                                    eventPath,
                                    eventAvailable;

                                //Change the event name to a fully qualified path
                                if (_.contains(defaultEvents, eventType)) {
                                    if (opt && _.size(opt) > 1) {
                                        eventPath = opt[1];
                                    }
                                    //find the specific object in the collection which has changed
                                    if (this.attributes[relationKey] instanceof Backbone.Collection && "change" === eventType) {
                                        indexEventObject = _.indexOf(this.attributes[relationKey].models, eventObject);
                                    }

                                    eventPath = relationKey + (indexEventObject !== -1 ? "[" + indexEventObject + "]" : "") + (eventPath ? "." + eventPath : "");
                                    args[0] = eventType + ":" + eventPath;

                                    if (_proxyCalls) {
                                        //If event has been already triggered as result of same source `eventPath`,
                                        //no need to re-trigger event to prevent cycle
                                        eventAvailable = _.find(_proxyCalls, function (value, eventKey) {
                                            //`event` ends with eventKey
                                            var d = eventPath.length - eventKey.length;
                                            return eventPath.indexOf(eventKey, d) !== -1;
                                        });
                                        if (eventAvailable) {
                                            return this;
                                        }
                                    } else {
                                        _proxyCalls = this.attributes[relationKey]._proxyCalls = {};
                                    }
                                    // Add `eventPath` in `_proxyCalls` hash to track of.
                                    _proxyCalls[eventPath] = true;
                                }

                                // bubble up event to parent `model`
                                this.trigger.apply(this, args);

                                // remove `eventPath` from `_proxyCalls`, if `eventPath` and `_proxCalls` are available.
                                if (eventPath && _proxyCalls) {
                                    delete _proxyCalls[eventPath];
                                }
                                return this;
                            };
                            this.attributes[relationKey].on("all", this.attributes[relationKey]._proxyCallback, this);
                        }

                        //Create a local `processedRelations` array to store the relation key which has been processed.
                        //We cannot use `this.relations` because if there is no value defined for `relationKey`, it will not get processed by either Backbone `set` or the `AssociatedModel` set
                        !processedRelations && (processedRelations = []);
                        if (_.indexOf(processedRelations, relationKey) === -1) {
                            processedRelations.push(relationKey);
                        }
                    }
                }, this);
            }
            if (processedRelations) {
                //Find attributes yet to be processed - `tbp`
                tbp = {};
                for (attr in attributes) {
                    if (_.indexOf(processedRelations, attr) === -1) {
                        tbp[attr] = attributes[attr];
                    }
                }
            } else {
                //Set all `attributes` to `tbp`
                tbp = attributes;
            }
            //Returns results for `BackboneModel.set`
            return BackboneModel.set.call(this, tbp, options);
        },
        //Returns New `collection` of type `relation.relatedModel`
        _createCollection:function (type) {
            var collection, relatedModel = type;
            _.isString(relatedModel) && (relatedModel = eval(relatedModel));
            if (relatedModel && relatedModel.prototype instanceof Backbone.AssociatedModel) {
                //Creates new `Backbone.Collection` and defines model class
                collection = new Backbone.Collection();
                collection.model = relatedModel;
            } else {
                throw new Error('type must inherit from Backbone.AssociatedModel');
            }
            return collection;
        },
        //Has the model changed. Traverse the object hierarchy to compute dirtyness
        hasChanged:function (attr) {
            var isDirty, relation, attrValue, i, dirtyObjects;
            //To prevent cycles, check if this node is visited
            if (!this.visitedHC) {
                this.visitedHC = true;
                isDirty = BackboneModel.hasChanged.apply(this, arguments);
                if (!isDirty && this.relations) {
                    //Go down the hierarchy to see if anything has `changed`
                    for (i = 0; i < this.relations.length; ++i) {
                        relation = this.relations[i];
                        attrValue = this.attributes[relation.key];
                        if (attrValue) {
                            if (attrValue instanceof Backbone.Collection) {
                                dirtyObjects = attrValue.filter(function (m) {
                                    return m.hasChanged() === true;
                                });
                                _.size(dirtyObjects) > 0 && (isDirty = true);
                            } else {
                                isDirty = attrValue.hasChanged && attrValue.hasChanged();
                            }
                            if (isDirty) {
                                break;
                            }
                        }
                    }
                }
                delete this.visitedHC;
            }
            return !!isDirty;
        },
        //Returns a hash of the changed attributes
        changedAttributes:function (diff) {
            var delta, relation, attrValue, changedCollection, i;
            //To prevent cycles, check if this node is visited
            if (!this.visited) {
                this.visited = true;
                delta = BackboneModel.changedAttributes.apply(this, arguments);
                if (this.relations) {
                    for (i = 0; i < this.relations.length; ++i) {
                        relation = this.relations[i];
                        attrValue = this.attributes[relation.key];
                        if (attrValue) {
                            if (attrValue instanceof Backbone.Collection) {
                                changedCollection = _.filter(attrValue.map(function (m) {
                                    return m.changedAttributes();
                                }), function (m) {
                                    return !!m;
                                });
                                if (_.size(changedCollection) > 0) {
                                    delta[relation.key] = changedCollection;
                                }
                            } else if (attrValue instanceof Backbone.AssociatedModel && attrValue.hasChanged()) {
                                delta[relation.key] = attrValue.toJSON();
                            }
                        }
                    }
                }
                delete this.visited;
            }
            return !delta ? false : delta;
        },
        //Returns the hash of the previous attributes of the graph
        previousAttributes:function () {
            var pa, attrValue, pattrValue, pattrJSON;
            //To prevent cycles, check if this node is visited
            if (!this.visited) {
                this.visited = true;
                pa = BackboneModel.previousAttributes.apply(this, arguments);
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        attrValue = this.attributes[relation.key];
                        pattrValue = pa[relation.key];
                        pattrJSON = pattrValue ? pattrValue.toJSON() : undefined;
                        if (pattrValue && pattrValue == attrValue) {
                            if (attrValue instanceof Backbone.AssociatedModel) {
                                pa[relation.key] = attrValue.previousAttributes();
                            } else if (attrValue instanceof Backbone.Collection) {
                                pa[relation.key] = attrValue.map(function (m) {
                                    return m.previousAttributes();
                                });
                            }
                        } else {
                            if (pattrValue)
                                pa[relation.key] = pattrJSON;
                        }
                    }, this);
                }
                delete this.visited;
            }
            return pa;
        },
        //Return the previous value of the passed in attribute
        previous:function (attr) {
            return this.previousAttributes()[attr];
        },
        //The JSON representation of the model.
        toJSON:function (options) {
            var json, aJson;
            if (!this.visited) {
                this.visited = true;
                //Get json representation from `BackboneModel.toJSON`
                json = BackboneModel.toJSON.apply(this, arguments);
                //If `this.relations` is defined, iterate through each `relation` and added it's json representation to parents' json representation
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        var attr = this.attributes[relation.key];
                        if (attr) {
                            aJson = attr.toJSON(options);
                            json[relation.key] = _.isArray(aJson) ? _.compact(aJson) : aJson;
                        }
                    }, this);
                }
                delete this.visited;
            }
            return json;
        },
        //deep `clone` the model.
        clone:function () {
            var cloneObj, newCollection;
            if (!this.visited) {
                this.visited = true;
                //Get shallow clone from `BackboneModel.clone`
                cloneObj = BackboneModel.clone.apply(this, arguments);
                //If `this.relations` is defined, iterate through each `relation` and `clone`
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        if (this.attributes[relation.key]) {
                            var sourceObj = cloneObj.attributes[relation.key];
                            if (sourceObj instanceof Backbone.Collection) {
                                //Creates new `collection` using `relation`
                                newCollection = relation.collectionType ? new relation.collectionType() : this._createCollection(relation.relatedModel);
                                //Added each `clone` model to `newCollection`
                                sourceObj.each(function (model) {
                                    var mClone = model.clone();
                                    mClone && newCollection.add(mClone);
                                });
                                cloneObj.attributes[relation.key] = newCollection;
                            } else if (sourceObj instanceof Backbone.Model) {
                                cloneObj.attributes[relation.key] = sourceObj.clone();
                            }
                        }
                    }, this);
                }
                delete this.visited;
            }
            return cloneObj;
        }
    });
})();<commit_msg>Treat passed-in external hash of attributes as a new AssociatedModel instance while performing a set operation<commit_after>//
// Backbone-associations.js 0.2.0
//
// (c) 2012 Dhruva Ray, Jaynti Kanani
//
// Backbone-associations may be freely distributed under the MIT license; see the accompanying LICENSE.txt.
//
// Depends on [Backbone](https://github.com/documentcloud/backbone) (and thus on [Underscore](https://github.com/documentcloud/underscore/) as well)
//
// A complete [Test & Benchmark Suite](../test/test-suite.html) is included for your perusal.

// Initial Setup
// --------------
(function () {
    "use strict";

    // The top-level namespace. All public Backbone classes and modules will be attached to this.
    // Exported for the browser and CommonJS.
    var _, Backbone, BackboneModel, defaultEvents;
    if (typeof require !== 'undefined') {
        _ = require('underscore');
        Backbone = require('backbone');
        exports = module.exports = Backbone;
    } else {
        _ = window._;
        Backbone = window.Backbone;
    }

    BackboneModel = Backbone.Model.prototype;
    defaultEvents = ["change", "add", "remove", "reset", "destroy", "sync", "error"];

    // Backbone.AssociatedModel
    // --------------

    //Add `Many` and `One` relations to Backbone Object
    Backbone.Many = "Many";
    Backbone.One = "One";
    //Define `AssociatedModel` (Extends Backbone.Model)
    Backbone.AssociatedModel = Backbone.Model.extend({
        //Define relations with Associated Model
        relations:undefined,
        _proxyCalls:undefined,
        //Set a hash of model attributes on the object,
        //firing `"change"` unless you choose to silence it.
        //It maintains relations between models during the set operation. It also bubbles up child events to the parent.
        set:function (key, value, options) {
            var attributes, processedRelations, tbp, attr;
            // Duplicate backbone's behavior to allow separate key/value parameters, instead of a single 'attributes' object.
            if (_.isObject(key) || key == null) {
                attributes = key;
                options = value;
            } else {
                attributes = {};
                attributes[key] = value;
            }
            // Extract attributes and options.
            options || (options = {});
            if (!attributes) return this;
            if (options.unset) for (attr in attributes) attributes[attr] = void 0;
            //Check for existence of relations in this model
            if (this.relations) {
                //Iterate over `this.relations` and `set` model and collection values
                _.each(this.relations, function (relation) {
                    var relationKey = relation.key, relatedModel = relation.relatedModel, collectionType = relation.collectionType,
                        val, relationOptions, data;
                    if (attributes[relationKey]) {
                        //Get value of attribute with relation key in `val`
                        val = _.result(attributes, relationKey);
                        //Get class if relation is stored as a string
                        relatedModel && _.isString(relatedModel) && (relatedModel = eval(relatedModel));
                        collectionType && _.isString(collectionType) && (collectionType = eval(collectionType));
                        //Merge in options specific to this relation
                        relationOptions = relation.options ? _.extend({}, relation.options, options) : options;
                        //If `relation` defines model as associated collection...
                        if (relation.type === Backbone.Many) {
                            //`collectionType` should be instance of `Backbone.Collection`
                            if (collectionType && !collectionType.prototype instanceof Backbone.Collection) {
                                throw new Error('collectionType must inherit from Backbone.Collection');
                            }

                            if (val instanceof Backbone.Collection) {
                                BackboneModel.set.call(this, relationKey, val, relationOptions);
                            } else if (!this.attributes[relationKey]) {
                                data = collectionType ? new collectionType() : this._createCollection(relatedModel);
                                data.add(val, relationOptions);
                                BackboneModel.set.call(this, relationKey, data, relationOptions);
                            } else {
                                this.attributes[relationKey].reset(val, relationOptions);
                            }

                            //If `relation` defines model as associated model...
                        } else if (relation.type === Backbone.One && relatedModel) {
                            if (val instanceof Backbone.AssociatedModel) {
                                BackboneModel.set.call(this, relationKey, val, relationOptions);
                            } else {
                                data = new relatedModel(val);
                                BackboneModel.set.call(this, relationKey, data, relationOptions);
                            }
                        }

                        //Add proxy events to respective parents. Only add callback if not defined
                        if (!this.attributes[relationKey]._proxyCallback) {
                            this.attributes[relationKey]._proxyCallback = function () {
                                var args = arguments,
                                    opt = args[0].split(":"),
                                    eventType = opt[0],
                                    eventObject = args[1],
                                    indexEventObject = -1,
                                    _proxyCalls = this.attributes[relationKey]._proxyCalls,
                                    eventPath,
                                    eventAvailable;

                                //Change the event name to a fully qualified path
                                if (_.contains(defaultEvents, eventType)) {
                                    if (opt && _.size(opt) > 1) {
                                        eventPath = opt[1];
                                    }
                                    //find the specific object in the collection which has changed
                                    if (this.attributes[relationKey] instanceof Backbone.Collection && "change" === eventType) {
                                        indexEventObject = _.indexOf(this.attributes[relationKey].models, eventObject);
                                    }

                                    eventPath = relationKey + (indexEventObject !== -1 ? "[" + indexEventObject + "]" : "") + (eventPath ? "." + eventPath : "");
                                    args[0] = eventType + ":" + eventPath;

                                    if (_proxyCalls) {
                                        //If event has been already triggered as result of same source `eventPath`,
                                        //no need to re-trigger event to prevent cycle
                                        eventAvailable = _.find(_proxyCalls, function (value, eventKey) {
                                            //`event` ends with eventKey
                                            var d = eventPath.length - eventKey.length;
                                            return eventPath.indexOf(eventKey, d) !== -1;
                                        });
                                        if (eventAvailable) {
                                            return this;
                                        }
                                    } else {
                                        _proxyCalls = this.attributes[relationKey]._proxyCalls = {};
                                    }
                                    // Add `eventPath` in `_proxyCalls` hash to track of.
                                    _proxyCalls[eventPath] = true;
                                }

                                // bubble up event to parent `model`
                                this.trigger.apply(this, args);

                                // remove `eventPath` from `_proxyCalls`, if `eventPath` and `_proxCalls` are available.
                                if (eventPath && _proxyCalls) {
                                    delete _proxyCalls[eventPath];
                                }
                                return this;
                            };
                            this.attributes[relationKey].on("all", this.attributes[relationKey]._proxyCallback, this);
                        }

                        //Create a local `processedRelations` array to store the relation key which has been processed.
                        //We cannot use `this.relations` because if there is no value defined for `relationKey`, it will not get processed by either Backbone `set` or the `AssociatedModel` set
                        !processedRelations && (processedRelations = []);
                        if (_.indexOf(processedRelations, relationKey) === -1) {
                            processedRelations.push(relationKey);
                        }
                    }
                }, this);
            }
            if (processedRelations) {
                //Find attributes yet to be processed - `tbp`
                tbp = {};
                for (attr in attributes) {
                    if (_.indexOf(processedRelations, attr) === -1) {
                        tbp[attr] = attributes[attr];
                    }
                }
            } else {
                //Set all `attributes` to `tbp`
                tbp = attributes;
            }
            //Returns results for `BackboneModel.set`
            return BackboneModel.set.call(this, tbp, options);
        },
        //Returns New `collection` of type `relation.relatedModel`
        _createCollection:function (type) {
            var collection, relatedModel = type;
            _.isString(relatedModel) && (relatedModel = eval(relatedModel));
            if (relatedModel && relatedModel.prototype instanceof Backbone.AssociatedModel) {
                //Creates new `Backbone.Collection` and defines model class
                collection = new Backbone.Collection();
                collection.model = relatedModel;
            } else {
                throw new Error('type must inherit from Backbone.AssociatedModel');
            }
            return collection;
        },
        //Has the model changed. Traverse the object hierarchy to compute dirtyness
        hasChanged:function (attr) {
            var isDirty, relation, attrValue, i, dirtyObjects;
            //To prevent cycles, check if this node is visited
            if (!this.visitedHC) {
                this.visitedHC = true;
                isDirty = BackboneModel.hasChanged.apply(this, arguments);
                if (!isDirty && this.relations) {
                    //Go down the hierarchy to see if anything has `changed`
                    for (i = 0; i < this.relations.length; ++i) {
                        relation = this.relations[i];
                        attrValue = this.attributes[relation.key];
                        if (attrValue) {
                            if (attrValue instanceof Backbone.Collection) {
                                dirtyObjects = attrValue.filter(function (m) {
                                    return m.hasChanged() === true;
                                });
                                _.size(dirtyObjects) > 0 && (isDirty = true);
                            } else {
                                isDirty = attrValue.hasChanged && attrValue.hasChanged();
                            }
                            if (isDirty) {
                                break;
                            }
                        }
                    }
                }
                delete this.visitedHC;
            }
            return !!isDirty;
        },
        //Returns a hash of the changed attributes
        changedAttributes:function (diff) {
            var delta, relation, attrValue, changedCollection, i;
            //To prevent cycles, check if this node is visited
            if (!this.visited) {
                this.visited = true;
                delta = BackboneModel.changedAttributes.apply(this, arguments);
                if (this.relations) {
                    for (i = 0; i < this.relations.length; ++i) {
                        relation = this.relations[i];
                        attrValue = this.attributes[relation.key];
                        if (attrValue) {
                            if (attrValue instanceof Backbone.Collection) {
                                changedCollection = _.filter(attrValue.map(function (m) {
                                    return m.changedAttributes();
                                }), function (m) {
                                    return !!m;
                                });
                                if (_.size(changedCollection) > 0) {
                                    delta[relation.key] = changedCollection;
                                }
                            } else if (attrValue instanceof Backbone.AssociatedModel && attrValue.hasChanged()) {
                                delta[relation.key] = attrValue.toJSON();
                            }
                        }
                    }
                }
                delete this.visited;
            }
            return !delta ? false : delta;
        },
        //Returns the hash of the previous attributes of the graph
        previousAttributes:function () {
            var pa, attrValue, pattrValue, pattrJSON;
            //To prevent cycles, check if this node is visited
            if (!this.visited) {
                this.visited = true;
                pa = BackboneModel.previousAttributes.apply(this, arguments);
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        attrValue = this.attributes[relation.key];
                        pattrValue = pa[relation.key];
                        pattrJSON = pattrValue ? pattrValue.toJSON() : undefined;
                        if (pattrValue && pattrValue == attrValue) {
                            if (attrValue instanceof Backbone.AssociatedModel) {
                                pa[relation.key] = attrValue.previousAttributes();
                            } else if (attrValue instanceof Backbone.Collection) {
                                pa[relation.key] = attrValue.map(function (m) {
                                    return m.previousAttributes();
                                });
                            }
                        } else {
                            if (pattrValue)
                                pa[relation.key] = pattrJSON;
                        }
                    }, this);
                }
                delete this.visited;
            }
            return pa;
        },
        //Return the previous value of the passed in attribute
        previous:function (attr) {
            return this.previousAttributes()[attr];
        },
        //The JSON representation of the model.
        toJSON:function (options) {
            var json, aJson;
            if (!this.visited) {
                this.visited = true;
                //Get json representation from `BackboneModel.toJSON`
                json = BackboneModel.toJSON.apply(this, arguments);
                //If `this.relations` is defined, iterate through each `relation` and added it's json representation to parents' json representation
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        var attr = this.attributes[relation.key];
                        if (attr) {
                            aJson = attr.toJSON(options);
                            json[relation.key] = _.isArray(aJson) ? _.compact(aJson) : aJson;
                        }
                    }, this);
                }
                delete this.visited;
            }
            return json;
        },
        //deep `clone` the model.
        clone:function () {
            var cloneObj, newCollection;
            if (!this.visited) {
                this.visited = true;
                //Get shallow clone from `BackboneModel.clone`
                cloneObj = BackboneModel.clone.apply(this, arguments);
                //If `this.relations` is defined, iterate through each `relation` and `clone`
                if (this.relations) {
                    _.each(this.relations, function (relation) {
                        if (this.attributes[relation.key]) {
                            var sourceObj = cloneObj.attributes[relation.key];
                            if (sourceObj instanceof Backbone.Collection) {
                                //Creates new `collection` using `relation`
                                newCollection = relation.collectionType ? new relation.collectionType() : this._createCollection(relation.relatedModel);
                                //Added each `clone` model to `newCollection`
                                sourceObj.each(function (model) {
                                    var mClone = model.clone();
                                    mClone && newCollection.add(mClone);
                                });
                                cloneObj.attributes[relation.key] = newCollection;
                            } else if (sourceObj instanceof Backbone.Model) {
                                cloneObj.attributes[relation.key] = sourceObj.clone();
                            }
                        }
                    }, this);
                }
                delete this.visited;
            }
            return cloneObj;
        }
    });
})();<|endoftext|>


<commit_before>$.when(
  $.getScript('src/js/app/format.js'),
  $.getScript('src/js/pnotif/pnotif.js'),
  $.getScript('src/js/storage.js'),
  $.getScript('src/js/app/mediainfo.js'),
  $.getScript('src/js/jquery/jquery-ui.min.js'),
  $.getScript('src/js/jquery/jquery-ui.touch-punch.min.js'),
  $.getScript('src/js/app/directory.js'),
  $.getScript('src/js/app/torrent.js'),
  $.getScript('src/js/app/top-menu.js'),
  $.getScript('src/js/jquery/jquery.tablesorter.min.js'),
  $.getScript('src/js/app/list.js'),
  $.getScript('src/js/app/searchtorrent.js'),
  $.getScript('src/js/pnotif/pnotif.js'),
  $.getScript('src/js/app/left-menu.js'),
  $.getScript('src/js/app/mediainfo.js'),
  $.getScript('src/js/app/searchtorrent.js'),
  $.getScript('src/js/storage.js'),
  $.getScript('src/js/popup/popup.js')
).then(function(){
  var LeftMenu = new _LeftMenu()
  var MediaInfo = new _MediaInfo()
  var SearchTorrent = new _SearchTorrent()
})
<commit_msg>standard<commit_after>$.when(
  $.getScript('src/js/app/format.js'),
  $.getScript('src/js/pnotif/pnotif.js'),
  $.getScript('src/js/storage.js'),
  $.getScript('src/js/app/mediainfo.js'),
  $.getScript('src/js/jquery/jquery-ui.min.js'),
  $.getScript('src/js/jquery/jquery-ui.touch-punch.min.js'),
  $.getScript('src/js/app/directory.js'),
  $.getScript('src/js/app/torrent.js'),
  $.getScript('src/js/app/top-menu.js'),
  $.getScript('src/js/jquery/jquery.tablesorter.min.js'),
  $.getScript('src/js/app/list.js'),
  $.getScript('src/js/app/searchtorrent.js'),
  $.getScript('src/js/pnotif/pnotif.js'),
  $.getScript('src/js/app/left-menu.js'),
  $.getScript('src/js/app/mediainfo.js'),
  $.getScript('src/js/app/searchtorrent.js'),
  $.getScript('src/js/storage.js'),
  $.getScript('src/js/popup/popup.js')
).then(function () {
  var LeftMenu = new _LeftMenu()
  var MediaInfo = new _MediaInfo()
  var SearchTorrent = new _SearchTorrent()
})
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var routesRoot = require('./routesRoot.js');

//localhost:8080/api/..
router.route('/').get(routesRoot.GET);
router.route('/').get(routesRoot.POST);

module.exports = router;<commit_msg>fixed router.js typo (get -> post)<commit_after>var express = require('express');
var router = express.Router();
var routesRoot = require('./routesRoot.js');

//localhost:8080/api/..
router.route('/').get(routesRoot.GET);
router.route('/').post(routesRoot.POST);

module.exports = router;<|endoftext|>