<commit_before>var Book = function($, title, path, cover, author, textBytes, authorInstance){
    var self = {};

    self.title     = title;
    self.path      = path;
    self.cover     = cover;
    self.author    = author;
    self.textBytes = textBytes;
    self.authorInstance = authorInstance;

    self.$bookWithImage = null;
    self.$bookInList = null;

    self.init = function(){

    }

    self.render = function(){
        self._renderWithImage();
        self._renderInList();
    }

    self.matchesKeywords = function(keywords){
        return keywords.every(function(keyword){
            return self.title.toLowerCase().indexOf(keyword) > -1
        })
    }

    self.show = function(){
        self.$bookWithImage.show();
        self.$bookInList.show();
    }

    self.hide = function(){
        self.$bookWithImage.hide();
        self.$bookInList.hide();
    }

    self._renderWithImage = function(){
        var $book = $('.prototype-book').clone();

        $book.removeClass('prototype-book').addClass('book');

        if (self.cover){
            $book.find('.image a').attr('href', self.path);
            $book.find('img').attr('src', self.cover._thumbnailPath);
        }

        $book.find('.title').html(self.title);
        $book.find('.creator').html(self.author);

        $('#books').append($book);

        self.$bookWithImage = $book;
    }

    self._renderInList = function(){
        var $book = $('.prototype-creator-book').clone();

        var lengthIndicator = Math.round(3 * Math.pow(self.textBytes / (1024 * 10), 2/3));

        $book.removeClass('prototype-creator-book').addClass('book');
        $book.find('a').attr('href', self.path).html(self.title);
        $book.find('span').css('width', lengthIndicator + 'px').html(' ');

        self.authorInstance.$author.find('.books').append($book);

        self.$bookInList = $book;
    }

    self.init();

    return self;
}

var Author = function($, name, books){
    var self = {};

    self.name = "";
    self.books = [];

    self.$author = null;

    self.init = function(){
        self.name = name;

        self.books = books.map(function(book){
            return Book($, book._titles[0], book._path, book._maybeCover, self.name, book._textBytes, self);
        });

        self.render();
    }

    self.showOnMatch = function(keywords){
        var matchingBooks = self.books.filter(function(book){
            return book.matchesKeywords(keywords);
        })

        var authorMatch = keywords.every(function(keyword){
            return self.name.toLowerCase().indexOf(keyword) > -1
        })

        // Start with hiding everything
        self.$author.hide();
        $.each(self.books, function(i, book) { book.hide() });

        // Display all books from this author
        if (authorMatch) {
            self.$author.show();

            $.each(self.books, function(i, book) { book.show() });
        }
        // Display all matching books
        else if (matchingBooks.length > 0) {
            self.$author.show();

            $.each(matchingBooks, function(i, book) { book.show() });
        }
        // Hide author and books
        else {
            self.$author.hide();

            $.each(self.books, function(i, book) { book.hide() });
        }
    }

    self.showAll = function(){
        self.$author.show();

        $.each(self.books, function(i, book) { book.show() });
    }

    self.render = function(){
        self.$author = $('.prototype-creator').clone();

        self.$author.removeClass('prototype-creator').addClass('creator');

        self.$author.find('.name').html(self.name);

        self.$author.appendTo($('#creators'));

        $.each(self.books, function(i, book){
            book.render();
        });
    }

    self.init();

    return self;
}

var App = function($, books){
    var self = {};

    self.authors = [];

    self.init = function(books){
        var creators = self._groupBooksByAuthor(books);

        $('#loading').hide();

        self._createAuthors(creators);

        $('#filter').show();

        self._makeAuthorsGoToBottom();
    };

    self.search = function(query){
        var keywords = query.trim().toLowerCase().split(" ");

        $.each(self.authors, function(i, author){
            author.showOnMatch(keywords);
        });
    }

    self.showAll = function(){
        $.each(self.authors, function(i, author){
            author.showAll();
        });
    }

    self._groupBooksByAuthor = function(books){
        var authors = {};

        // Add books to their author

        $.each(books, function(i, book){
            var author = book._creators[0];

            if (!(author in authors)){
                authors[author] = [];
            }

            authors[author].push(book);
        });

        // Sort books within the authors

        Object.keys(authors).map(function(key, index){
            authors[key].sort(function(book1, book2) {
                var title1 = book1._titles[0];
                var title2 = book2._titles[0];

                if (title1 > title2) {
                    return 1;
                }
                else if (title1 < title2) {
                    return -1;
                }
                else {
                    return 0;
                }
            });
        });

        return authors;
    };

    self._createAuthors = function(creators){
        self._iterate_over_dict_sorted(creators, function(creator, books) {
            self.authors.push(Author($, creator, books));
        });
    }

    self._iterate_over_dict_sorted = function(dict, f){
        var keys = Object.keys(dict);
        keys.sort();

        $.each(keys, function(i, key){
            f(key, dict[key]);
        });
    };

    self._makeAuthorsGoToBottom = function(){
        if ($(window).width() > 650){
            $('#creators').height($(document).height());
        }
    };

    self.init(books);

    return self;
};

(function($){
    $(function(){
        $.getJSON('app.cgi', function(books){
            var app = App($, books);

            $('#filter input').on('change', function(){
                var query = $(this).val();

                if (query == ''){
                    app.showAll();
                }
                else {
                    app.search(query);
                }
            });
        });
    });
})(jQuery);
<commit_msg>Update text length bar algoritm to be more exponential<commit_after>var Book = function($, title, path, cover, author, textBytes, authorInstance){
    var self = {};

    self.title     = title;
    self.path      = path;
    self.cover     = cover;
    self.author    = author;
    self.textBytes = textBytes;
    self.authorInstance = authorInstance;

    self.$bookWithImage = null;
    self.$bookInList = null;

    self.init = function(){

    }

    self.render = function(){
        self._renderWithImage();
        self._renderInList();
    }

    self.matchesKeywords = function(keywords){
        return keywords.every(function(keyword){
            return self.title.toLowerCase().indexOf(keyword) > -1
        })
    }

    self.show = function(){
        self.$bookWithImage.show();
        self.$bookInList.show();
    }

    self.hide = function(){
        self.$bookWithImage.hide();
        self.$bookInList.hide();
    }

    self._renderWithImage = function(){
        var $book = $('.prototype-book').clone();

        $book.removeClass('prototype-book').addClass('book');

        if (self.cover){
            $book.find('.image a').attr('href', self.path);
            $book.find('img').attr('src', self.cover._thumbnailPath);
        }

        $book.find('.title').html(self.title);
        $book.find('.creator').html(self.author);

        $('#books').append($book);

        self.$bookWithImage = $book;
    }

    self._renderInList = function(){
        var $book = $('.prototype-creator-book').clone();

        var lengthIndicator = Math.round(5 * Math.pow(self.textBytes / (1024 * 10), 1/2));

        $book.removeClass('prototype-creator-book').addClass('book');
        $book.find('a').attr('href', self.path).html(self.title);
        $book.find('span').css('width', lengthIndicator + 'px').html(' ');

        self.authorInstance.$author.find('.books').append($book);

        self.$bookInList = $book;
    }

    self.init();

    return self;
}

var Author = function($, name, books){
    var self = {};

    self.name = "";
    self.books = [];

    self.$author = null;

    self.init = function(){
        self.name = name;

        self.books = books.map(function(book){
            return Book($, book._titles[0], book._path, book._maybeCover, self.name, book._textBytes, self);
        });

        self.render();
    }

    self.showOnMatch = function(keywords){
        var matchingBooks = self.books.filter(function(book){
            return book.matchesKeywords(keywords);
        })

        var authorMatch = keywords.every(function(keyword){
            return self.name.toLowerCase().indexOf(keyword) > -1
        })

        // Start with hiding everything
        self.$author.hide();
        $.each(self.books, function(i, book) { book.hide() });

        // Display all books from this author
        if (authorMatch) {
            self.$author.show();

            $.each(self.books, function(i, book) { book.show() });
        }
        // Display all matching books
        else if (matchingBooks.length > 0) {
            self.$author.show();

            $.each(matchingBooks, function(i, book) { book.show() });
        }
        // Hide author and books
        else {
            self.$author.hide();

            $.each(self.books, function(i, book) { book.hide() });
        }
    }

    self.showAll = function(){
        self.$author.show();

        $.each(self.books, function(i, book) { book.show() });
    }

    self.render = function(){
        self.$author = $('.prototype-creator').clone();

        self.$author.removeClass('prototype-creator').addClass('creator');

        self.$author.find('.name').html(self.name);

        self.$author.appendTo($('#creators'));

        $.each(self.books, function(i, book){
            book.render();
        });
    }

    self.init();

    return self;
}

var App = function($, books){
    var self = {};

    self.authors = [];

    self.init = function(books){
        var creators = self._groupBooksByAuthor(books);

        $('#loading').hide();

        self._createAuthors(creators);

        $('#filter').show();

        self._makeAuthorsGoToBottom();
    };

    self.search = function(query){
        var keywords = query.trim().toLowerCase().split(" ");

        $.each(self.authors, function(i, author){
            author.showOnMatch(keywords);
        });
    }

    self.showAll = function(){
        $.each(self.authors, function(i, author){
            author.showAll();
        });
    }

    self._groupBooksByAuthor = function(books){
        var authors = {};

        // Add books to their author

        $.each(books, function(i, book){
            var author = book._creators[0];

            if (!(author in authors)){
                authors[author] = [];
            }

            authors[author].push(book);
        });

        // Sort books within the authors

        Object.keys(authors).map(function(key, index){
            authors[key].sort(function(book1, book2) {
                var title1 = book1._titles[0];
                var title2 = book2._titles[0];

                if (title1 > title2) {
                    return 1;
                }
                else if (title1 < title2) {
                    return -1;
                }
                else {
                    return 0;
                }
            });
        });

        return authors;
    };

    self._createAuthors = function(creators){
        self._iterate_over_dict_sorted(creators, function(creator, books) {
            self.authors.push(Author($, creator, books));
        });
    }

    self._iterate_over_dict_sorted = function(dict, f){
        var keys = Object.keys(dict);
        keys.sort();

        $.each(keys, function(i, key){
            f(key, dict[key]);
        });
    };

    self._makeAuthorsGoToBottom = function(){
        if ($(window).width() > 650){
            $('#creators').height($(document).height());
        }
    };

    self.init(books);

    return self;
};

(function($){
    $(function(){
        $.getJSON('app.cgi', function(books){
            var app = App($, books);

            $('#filter input').on('change', function(){
                var query = $(this).val();

                if (query == ''){
                    app.showAll();
                }
                else {
                    app.search(query);
                }
            });
        });
    });
})(jQuery);
<|endoftext|>


<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */

/**
 * @class
 *
 * @requires OpenLayers/Control.js
 */
OpenLayers.Control.MouseDefaults = Class.create();
OpenLayers.Control.MouseDefaults.prototype =
  Object.extend( new OpenLayers.Control(), {

    /** @type Boolean */
    performedDrag: false,

    /**
     * @constructor
     */
    initialize: function() {
        OpenLayers.Control.prototype.initialize.apply(this, arguments);

        //register mousewheel events specifically on the window and document
        Event.observe(window, "DOMMouseScroll",
                      this.onWheelEvent.bindAsEventListener(this));
        Event.observe(window, "mousewheel",
                      this.onWheelEvent.bindAsEventListener(this));
        Event.observe(document, "mousewheel",
                      this.onWheelEvent.bindAsEventListener(this));
    },

    /**
     *
     */
    draw: function() {
        this.map.events.register( "click", this, this.defaultClick );
        this.map.events.register( "dblclick", this, this.defaultDblClick );
        this.map.events.register( "mousedown", this, this.defaultMouseDown );
        this.map.events.register( "mouseup", this, this.defaultMouseUp );
        this.map.events.register( "mousemove", this, this.defaultMouseMove );
        this.map.events.register( "mouseout", this, this.defaultMouseOut );
    },

    /**
     * @param {Event} evt
     *
     * @type Boolean
     */
    defaultClick: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        var notAfterDrag = !this.performedDrag;
        this.performedDrag = false;
        return notAfterDrag;
    },

    /**
    * @param {Event} evt
    */
    defaultDblClick: function (evt) {
        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
        this.map.setCenter(newCenter, this.map.zoom + 1);
        Event.stop(evt);
        return false;
    },

    /**
    * @param {Event} evt
    */
    defaultMouseDown: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        this.mouseDragStart = evt.xy.clone();
        this.performedDrag  = false;
        if (evt.shiftKey) {
            this.map.div.style.cursor = "crosshair";
            this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
                                                     this.mouseDragStart,
                                                     null,
                                                     null,
                                                     "absolute",
                                                     "2px solid red");
            this.zoomBox.style.backgroundColor = "white";
            this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
            this.zoomBox.style.opacity = "0.50";
            this.zoomBox.style.fontSize = "1px";
            this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
            this.map.viewPortDiv.appendChild(this.zoomBox);
        }
        document.onselectstart=function() { return false; }
        Event.stop(evt);
    },

    /**
    * @param {Event} evt
    */
    defaultMouseMove: function (evt) {
        if (this.mouseDragStart != null) {
            if (this.zoomBox) {
                var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
                var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
                this.zoomBox.style.width = Math.max(1, deltaX) + "px";
                this.zoomBox.style.height = Math.max(1, deltaY) + "px";
                if (evt.xy.x < this.mouseDragStart.x) {
                    this.zoomBox.style.left = evt.xy.x+"px";
                }
                if (evt.xy.y < this.mouseDragStart.y) {
                    this.zoomBox.style.top = evt.xy.y+"px";
                }
            } else {
                var deltaX = this.mouseDragStart.x - evt.xy.x;
                var deltaY = this.mouseDragStart.y - evt.xy.y;
                var size = this.map.getSize();
                var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
                                                 size.h / 2 + deltaY);
                var newCenter = this.map.getLonLatFromViewPortPx( newXY );
                this.map.setCenter(newCenter, null, true);
                this.mouseDragStart = evt.xy.clone();
                this.map.div.style.cursor = "move";
            }
            this.performedDrag = true;
        }
    },

    /**
    * @param {Event} evt
    */
    defaultMouseUp: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        if (this.zoomBox) {
            this.zoomBoxEnd(evt);
        } else {
            if (this.performedDrag) {
                this.map.setCenter(this.map.center);
            }
        }
        document.onselectstart=null;
        this.mouseDragStart = null;
        this.map.div.style.cursor = "default";
    },

    /**
    * @param {Event} evt
    */
    defaultMouseOut: function (evt) {
        if (this.mouseDragStart != null
            && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
                if (this.zoomBox) {
                    this.removeZoomBox();
                }
                this.mouseDragStart = null;
        }
    },

    /** User spun scroll wheel up
     *
     */
    defaultWheelUp: function()  {
        this.map.zoomIn();
    },

    /** User spun scroll wheel down
     *
     */
    defaultWheelDown: function()  {
        this.map.zoomOut();
    },

    /** Zoombox function.
     *
     */
    zoomBoxEnd: function(evt) {
        if (this.mouseDragStart != null) {
            if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||
                Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {
                var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart );
                var end = this.map.getLonLatFromViewPortPx( evt.xy );
                var top = Math.max(start.lat, end.lat);
                var bottom = Math.min(start.lat, end.lat);
                var left = Math.min(start.lon, end.lon);
                var right = Math.max(start.lon, end.lon);
                var bounds = new OpenLayers.Bounds(left, bottom, right, top);
                var zoom = this.map.getZoomForExtent(bounds);
                this.map.setCenter(new OpenLayers.LonLat(
                  (start.lon + end.lon) / 2,
                  (start.lat + end.lat) / 2
                 ), zoom);
            } else {
                var end = this.map.getLonLatFromViewPortPx( evt.xy );
                this.map.setCenter(new OpenLayers.LonLat(
                  (end.lon),
                  (end.lat)
                 ), this.map.getZoom() + 1);
            }
            this.removeZoomBox();
       }
    },

    /**
     * Remove the zoombox from the screen and nullify our reference to it.
     */
    removeZoomBox: function() {
        this.map.viewPortDiv.removeChild(this.zoomBox);
        this.zoomBox = null;
    },

/**
 *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
 */

    /** Catch the wheel event and handle it xbrowserly
     *
     * @param {Event} e
     */
    onWheelEvent: function(e){

        // first determine whether or not the wheeling was inside the map
        var inMap = false;
        var elem = Event.element(e);
        while(elem != null) {
            if (this.map && elem == this.map.div) {
                inMap = true;
                break;
            }
            elem = elem.parentNode;
        }

        if (inMap) {

            var delta = 0;
            if (!e) {
                e = window.event;
            }
            if (e.wheelDelta) {
                delta = e.wheelDelta/120;
                if (window.opera) {
                    delta = -delta;
                }
            } else if (e.detail) {
                delta = -e.detail / 3;
            }
            if (delta) {
                if (delta < 0) {
                   this.defaultWheelDown();
                } else {
                   this.defaultWheelUp();
                }
            }

            //only wheel the map, not the window
            Event.stop(e);
        }
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Control.MouseDefaults"
});

<commit_msg>coding standards -- spacing<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
 * text of the license. */

/**
 * @class
 *
 * @requires OpenLayers/Control.js
 */
OpenLayers.Control.MouseDefaults = Class.create();
OpenLayers.Control.MouseDefaults.prototype =
  Object.extend( new OpenLayers.Control(), {

    /** @type Boolean */
    performedDrag: false,

    /**
     * @constructor
     */
    initialize: function() {
        OpenLayers.Control.prototype.initialize.apply(this, arguments);

        //register mousewheel events specifically on the window and document
        Event.observe(window, "DOMMouseScroll",
                      this.onWheelEvent.bindAsEventListener(this));
        Event.observe(window, "mousewheel",
                      this.onWheelEvent.bindAsEventListener(this));
        Event.observe(document, "mousewheel",
                      this.onWheelEvent.bindAsEventListener(this));
    },

    /**
     *
     */
    draw: function() {
        this.map.events.register( "click", this, this.defaultClick );
        this.map.events.register( "dblclick", this, this.defaultDblClick );
        this.map.events.register( "mousedown", this, this.defaultMouseDown );
        this.map.events.register( "mouseup", this, this.defaultMouseUp );
        this.map.events.register( "mousemove", this, this.defaultMouseMove );
        this.map.events.register( "mouseout", this, this.defaultMouseOut );
    },

    /**
     * @param {Event} evt
     *
     * @type Boolean
     */
    defaultClick: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        var notAfterDrag = !this.performedDrag;
        this.performedDrag = false;
        return notAfterDrag;
    },

    /**
    * @param {Event} evt
    */
    defaultDblClick: function (evt) {
        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
        this.map.setCenter(newCenter, this.map.zoom + 1);
        Event.stop(evt);
        return false;
    },

    /**
    * @param {Event} evt
    */
    defaultMouseDown: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        this.mouseDragStart = evt.xy.clone();
        this.performedDrag  = false;
        if (evt.shiftKey) {
            this.map.div.style.cursor = "crosshair";
            this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
                                                     this.mouseDragStart,
                                                     null,
                                                     null,
                                                     "absolute",
                                                     "2px solid red");
            this.zoomBox.style.backgroundColor = "white";
            this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
            this.zoomBox.style.opacity = "0.50";
            this.zoomBox.style.fontSize = "1px";
            this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
            this.map.viewPortDiv.appendChild(this.zoomBox);
        }
        document.onselectstart=function() { return false; }
        Event.stop(evt);
    },

    /**
    * @param {Event} evt
    */
    defaultMouseMove: function (evt) {
        if (this.mouseDragStart != null) {
            if (this.zoomBox) {
                var deltaX = Math.abs(this.mouseDragStart.x - evt.xy.x);
                var deltaY = Math.abs(this.mouseDragStart.y - evt.xy.y);
                this.zoomBox.style.width = Math.max(1, deltaX) + "px";
                this.zoomBox.style.height = Math.max(1, deltaY) + "px";
                if (evt.xy.x < this.mouseDragStart.x) {
                    this.zoomBox.style.left = evt.xy.x+"px";
                }
                if (evt.xy.y < this.mouseDragStart.y) {
                    this.zoomBox.style.top = evt.xy.y+"px";
                }
            } else {
                var deltaX = this.mouseDragStart.x - evt.xy.x;
                var deltaY = this.mouseDragStart.y - evt.xy.y;
                var size = this.map.getSize();
                var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
                                                 size.h / 2 + deltaY);
                var newCenter = this.map.getLonLatFromViewPortPx( newXY );
                this.map.setCenter(newCenter, null, true);
                this.mouseDragStart = evt.xy.clone();
                this.map.div.style.cursor = "move";
            }
            this.performedDrag = true;
        }
    },

    /**
    * @param {Event} evt
    */
    defaultMouseUp: function (evt) {
        if (!Event.isLeftClick(evt)) return;
        if (this.zoomBox) {
            this.zoomBoxEnd(evt);
        } else {
            if (this.performedDrag) {
                this.map.setCenter(this.map.center);
            }
        }
        document.onselectstart=null;
        this.mouseDragStart = null;
        this.map.div.style.cursor = "default";
    },

    /**
    * @param {Event} evt
    */
    defaultMouseOut: function (evt) {
        if (this.mouseDragStart != null &&
            OpenLayers.Util.mouseLeft(evt, this.map.div)) {
            if (this.zoomBox) {
                this.removeZoomBox();
            }
            this.mouseDragStart = null;
        }
    },

    /** User spun scroll wheel up
     *
     */
    defaultWheelUp: function()  {
        this.map.zoomIn();
    },

    /** User spun scroll wheel down
     *
     */
    defaultWheelDown: function()  {
        this.map.zoomOut();
    },

    /** Zoombox function.
     *
     */
    zoomBoxEnd: function(evt) {
        if (this.mouseDragStart != null) {
            if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||
                Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {
                var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart );
                var end = this.map.getLonLatFromViewPortPx( evt.xy );
                var top = Math.max(start.lat, end.lat);
                var bottom = Math.min(start.lat, end.lat);
                var left = Math.min(start.lon, end.lon);
                var right = Math.max(start.lon, end.lon);
                var bounds = new OpenLayers.Bounds(left, bottom, right, top);
                var zoom = this.map.getZoomForExtent(bounds);
                this.map.setCenter(new OpenLayers.LonLat(
                  (start.lon + end.lon) / 2,
                  (start.lat + end.lat) / 2
                 ), zoom);
            } else {
                var end = this.map.getLonLatFromViewPortPx( evt.xy );
                this.map.setCenter(new OpenLayers.LonLat(
                  (end.lon),
                  (end.lat)
                 ), this.map.getZoom() + 1);
            }
            this.removeZoomBox();
       }
    },

    /**
     * Remove the zoombox from the screen and nullify our reference to it.
     */
    removeZoomBox: function() {
        this.map.viewPortDiv.removeChild(this.zoomBox);
        this.zoomBox = null;
    },

/**
 *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
 */

    /** Catch the wheel event and handle it xbrowserly
     *
     * @param {Event} e
     */
    onWheelEvent: function(e){

        // first determine whether or not the wheeling was inside the map
        var inMap = false;
        var elem = Event.element(e);
        while(elem != null) {
            if (this.map && elem == this.map.div) {
                inMap = true;
                break;
            }
            elem = elem.parentNode;
        }

        if (inMap) {

            var delta = 0;
            if (!e) {
                e = window.event;
            }
            if (e.wheelDelta) {
                delta = e.wheelDelta/120;
                if (window.opera) {
                    delta = -delta;
                }
            } else if (e.detail) {
                delta = -e.detail / 3;
            }
            if (delta) {
                if (delta < 0) {
                   this.defaultWheelDown();
                } else {
                   this.defaultWheelUp();
                }
            }

            //only wheel the map, not the window
            Event.stop(e);
        }
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Control.MouseDefaults"
});

<|endoftext|>


<commit_before>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer.js
 */

/**
 * Class: OpenLayers.Layer.FixedZoomLevels
 *   Some Layers will already have established zoom levels (like google
 *    or ve). Instead of trying to determine them and populate a resolutions[]
 *    Array with those values, we will hijack the resolution functionality
 *    here.
 *
 *   When you subclass FixedZoomLevels:
 *
 *   The initResolutions() call gets nullified, meaning no resolutions[] array
 *    is set up. Which would be a big problem getResolution() in Layer, since
 *    it merely takes map.zoom and indexes into resolutions[]... but....
 *
 *   The getResolution() call is also overridden. Instead of using the
 *    resolutions[] array, we simply calculate the current resolution based
 *    on the current extent and the current map size. But how will we be able
 *    to calculate the current extent without knowing the resolution...?
 *
 *   The getExtent() function is also overridden. Instead of calculating extent
 *    based on the center point and the current resolution, we instead
 *    calculate the extent by getting the lonlats at the top-left and
 *    bottom-right by using the getLonLatFromViewPortPx() translation function,
 *    taken from the pixel locations (0,0) and the size of the map. But how
 *    will we be able to do lonlat-px translation without resolution....?
 *
 *   The getZoomForResolution() method is overridden. Instead of indexing into
 *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
 *    the desired resolution. With this extent, we then call getZoomForExtent()
 *
 *
 *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
 *    it is your responsibility to provide the following three functions:
 *
 *   - getLonLatFromViewPortPx
 *   - getViewPortPxFromLonLat
 *   - getZoomForExtent
 *
 *  ...those three functions should generally be provided by any reasonable
 *  API that you might be working from.
 *
 */
OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({

  /********************************************************/
  /*                                                      */
  /*                 Baselayer Functions                  */
  /*                                                      */
  /*    The following functions must all be implemented   */
  /*                  by all base layers                  */
  /*                                                      */
  /********************************************************/

    /**
     * Constructor: OpenLayers.Layer.FixedZoomLevels
     * Create a new fixed zoom levels layer.
     */
    initialize: function() {
        //this class is only just to add the following functions...
        // nothing to actually do here... but it is probably a good
        // idea to have layers that use these functions call this
        // inititalize() anyways, in case at some point we decide we
        // do want to put some functionality or state in here.
    },

    /**
     * Method: initResolutions
     * Populate the resolutions array
     */
    initResolutions: function() {

        var props = new Array('minZoomLevel', 'maxZoomLevel', 'numZoomLevels');

        for(var i=0, len=props.length; i<len; i++) {
            var property = props[i];
            this[property] = (this.options[property] != null)
                                     ? this.options[property]
                                     : this.map[property];
        }

        if ( (this.minZoomLevel == null) ||
             (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
            this.minZoomLevel = this.MIN_ZOOM_LEVEL;
        }

        //
        // At this point, we know what the minimum desired zoom level is, and
        //  we must calculate the total number of zoom levels.
        //
        //  Because we allow for the setting of either the 'numZoomLevels'
        //   or the 'maxZoomLevel' properties... on either the layer or the
        //   map, we have to define some rules to see which we take into
        //   account first in this calculation.
        //
        // The following is the precedence list for these properties:
        //
        // (1) numZoomLevels set on layer
        // (2) maxZoomLevel set on layer
        // (3) numZoomLevels set on map
        // (4) maxZoomLevel set on map*
        // (5) none of the above*
        //
        // *Note that options (4) and (5) are only possible if the user
        //  _explicitly_ sets the 'numZoomLevels' property on the map to
        //  null, since it is set by default to 16.
        //

        //
        // Note to future: In 3.0, I think we should remove the default
        // value of 16 for map.numZoomLevels. Rather, I think that value
        // should be set as a default on the Layer.WMS class. If someone
        // creates a 3rd party layer and does not specify any 'minZoomLevel',
        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
        // specified any of those on the map object either.. then I think
        // it is fair to say that s/he wants all the zoom levels available.
        //
        // By making map.numZoomLevels *null* by default, that will be the
        // case. As it is, I don't feel comfortable changing that right now
        // as it would be a glaring API change and actually would probably
        // break many peoples' codes.
        //

        //the number of zoom levels we'd like to have.
        var desiredZoomLevels;

        //this is the maximum number of zoom levels the layer will allow,
        // given the specified starting minimum zoom level.
        var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;

        if ( ((this.options.numZoomLevels == null) &&
              (this.options.maxZoomLevel != null)) // (2)
              ||
             ((this.numZoomLevels == null) &&
              (this.maxZoomLevel != null)) // (4)
           ) {
            //calculate based on specified maxZoomLevel (on layer or map)
            desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
        } else {
            //calculate based on specified numZoomLevels (on layer or map)
            // this covers cases (1) and (3)
            desiredZoomLevels = this.numZoomLevels;
        }

        if (desiredZoomLevels != null) {
            //Now that we know what we would *like* the number of zoom levels
            // to be, based on layer or map options, we have to make sure that
            // it does not conflict with the actual limit, as specified by
            // the constants on the layer itself (and calculated into the
            // 'limitZoomLevels' variable).
            this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
        } else {
            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
            // set on either the layer or the map. So we just use the
            // maximum limit as calculated by the layer's constants.
            this.numZoomLevels = limitZoomLevels;
        }

        //now that the 'numZoomLevels' is appropriately, safely set,
        // we go back and re-calculate the 'maxZoomLevel'.
        this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;

        if (this.RESOLUTIONS != null) {
            var resolutionsIndex = 0;
            this.resolutions = [];
            for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
            }
            this.maxResolution = this.resolutions[0];
            this.minResolution = this.resolutions[this.resolutions.length - 1];
        }
    },

    /**
     * APIMethod: getResolution
     * Get the current map resolution
     *
     * Returns:
     * {Float} Map units per Pixel
     */
    getResolution: function() {

        if (this.resolutions != null) {
            return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
        } else {
            var resolution = null;

            var viewSize = this.map.getSize();
            var extent = this.getExtent();

            if ((viewSize != null) && (extent != null)) {
                resolution = Math.max( extent.getWidth()  / viewSize.w,
                                       extent.getHeight() / viewSize.h );
            }
            return resolution;
        }
     },

    /**
     * APIMethod: getExtent
     * Calculates using px-> lonlat translation functions on tl and br
     *     corners of viewport
     *
     * Returns:
     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
     *                       bounds of the current viewPort.
     */
    getExtent: function () {
        var extent = null;

        var size = this.map.getSize();

        var tlPx = new OpenLayers.Pixel(0,0);
        var tlLL = this.getLonLatFromViewPortPx(tlPx);

        var brPx = new OpenLayers.Pixel(size.w, size.h);
        var brLL = this.getLonLatFromViewPortPx(brPx);

        if ((tlLL != null) && (brLL != null)) {
            extent = new OpenLayers.Bounds(tlLL.lon,
                                       brLL.lat,
                                       brLL.lon,
                                       tlLL.lat);
        }

        return extent;
    },

    /**
     * Method: getZoomForResolution
     * Get the zoom level for a given resolution
     *
     * Parameters:
     * resolution - {Float}
     *
     * Returns:
     * {Integer} A suitable zoom level for the specified resolution.
     *           If no baselayer is set, returns null.
     */
    getZoomForResolution: function(resolution) {

        if (this.resolutions != null) {
            return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
        } else {
            var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
            return this.getZoomForExtent(extent);
        }
    },

    /********************************************************/
    /*                                                      */
    /*             Translation Functions                    */
    /*                                                      */
    /*    The following functions translate GMaps and OL    */
    /*     formats for Pixel, LonLat, Bounds, and Zoom      */
    /*                                                      */
    /********************************************************/

    //
    // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
    //

    /**
     * Method: getOLZoomFromMapObjectZoom
     * Get the OL zoom index from the map object zoom level
     *
     * Parameters:
     * moZoom - {Integer}
     *
     * Returns:
     * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
     *           Returns null if null value is passed in
     */
    getOLZoomFromMapObjectZoom: function(moZoom) {
        var zoom = null;
        if (moZoom != null) {
            zoom = moZoom - this.minZoomLevel;
        }
        return zoom;
    },

    /**
     * Method: getMapObjectZoomFromOLZoom
     * Get the map object zoom level from the OL zoom level
     *
     * Parameters:
     * olZoom - {Integer}
     *
     * Returns:
     * {Integer} A MapObject level, translated from the passed in olZoom
     *           Returns null if null value is passed in
     */
    getMapObjectZoomFromOLZoom: function(olZoom) {
        var zoom = null;
        if (olZoom != null) {
            zoom = olZoom + this.minZoomLevel;
        }
        return zoom;
    },

    CLASS_NAME: "FixedZoomLevels"
});

<commit_msg>set the CLASS_NAME to the complete class name (add OpenLayers.Layer.)<commit_after>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer.js
 */

/**
 * Class: OpenLayers.Layer.FixedZoomLevels
 *   Some Layers will already have established zoom levels (like google
 *    or ve). Instead of trying to determine them and populate a resolutions[]
 *    Array with those values, we will hijack the resolution functionality
 *    here.
 *
 *   When you subclass FixedZoomLevels:
 *
 *   The initResolutions() call gets nullified, meaning no resolutions[] array
 *    is set up. Which would be a big problem getResolution() in Layer, since
 *    it merely takes map.zoom and indexes into resolutions[]... but....
 *
 *   The getResolution() call is also overridden. Instead of using the
 *    resolutions[] array, we simply calculate the current resolution based
 *    on the current extent and the current map size. But how will we be able
 *    to calculate the current extent without knowing the resolution...?
 *
 *   The getExtent() function is also overridden. Instead of calculating extent
 *    based on the center point and the current resolution, we instead
 *    calculate the extent by getting the lonlats at the top-left and
 *    bottom-right by using the getLonLatFromViewPortPx() translation function,
 *    taken from the pixel locations (0,0) and the size of the map. But how
 *    will we be able to do lonlat-px translation without resolution....?
 *
 *   The getZoomForResolution() method is overridden. Instead of indexing into
 *    the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
 *    the desired resolution. With this extent, we then call getZoomForExtent()
 *
 *
 *   Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
 *    it is your responsibility to provide the following three functions:
 *
 *   - getLonLatFromViewPortPx
 *   - getViewPortPxFromLonLat
 *   - getZoomForExtent
 *
 *  ...those three functions should generally be provided by any reasonable
 *  API that you might be working from.
 *
 */
OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({

  /********************************************************/
  /*                                                      */
  /*                 Baselayer Functions                  */
  /*                                                      */
  /*    The following functions must all be implemented   */
  /*                  by all base layers                  */
  /*                                                      */
  /********************************************************/

    /**
     * Constructor: OpenLayers.Layer.FixedZoomLevels
     * Create a new fixed zoom levels layer.
     */
    initialize: function() {
        //this class is only just to add the following functions...
        // nothing to actually do here... but it is probably a good
        // idea to have layers that use these functions call this
        // inititalize() anyways, in case at some point we decide we
        // do want to put some functionality or state in here.
    },

    /**
     * Method: initResolutions
     * Populate the resolutions array
     */
    initResolutions: function() {

        var props = new Array('minZoomLevel', 'maxZoomLevel', 'numZoomLevels');

        for(var i=0, len=props.length; i<len; i++) {
            var property = props[i];
            this[property] = (this.options[property] != null)
                                     ? this.options[property]
                                     : this.map[property];
        }

        if ( (this.minZoomLevel == null) ||
             (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
            this.minZoomLevel = this.MIN_ZOOM_LEVEL;
        }

        //
        // At this point, we know what the minimum desired zoom level is, and
        //  we must calculate the total number of zoom levels.
        //
        //  Because we allow for the setting of either the 'numZoomLevels'
        //   or the 'maxZoomLevel' properties... on either the layer or the
        //   map, we have to define some rules to see which we take into
        //   account first in this calculation.
        //
        // The following is the precedence list for these properties:
        //
        // (1) numZoomLevels set on layer
        // (2) maxZoomLevel set on layer
        // (3) numZoomLevels set on map
        // (4) maxZoomLevel set on map*
        // (5) none of the above*
        //
        // *Note that options (4) and (5) are only possible if the user
        //  _explicitly_ sets the 'numZoomLevels' property on the map to
        //  null, since it is set by default to 16.
        //

        //
        // Note to future: In 3.0, I think we should remove the default
        // value of 16 for map.numZoomLevels. Rather, I think that value
        // should be set as a default on the Layer.WMS class. If someone
        // creates a 3rd party layer and does not specify any 'minZoomLevel',
        // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
        // specified any of those on the map object either.. then I think
        // it is fair to say that s/he wants all the zoom levels available.
        //
        // By making map.numZoomLevels *null* by default, that will be the
        // case. As it is, I don't feel comfortable changing that right now
        // as it would be a glaring API change and actually would probably
        // break many peoples' codes.
        //

        //the number of zoom levels we'd like to have.
        var desiredZoomLevels;

        //this is the maximum number of zoom levels the layer will allow,
        // given the specified starting minimum zoom level.
        var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;

        if ( ((this.options.numZoomLevels == null) &&
              (this.options.maxZoomLevel != null)) // (2)
              ||
             ((this.numZoomLevels == null) &&
              (this.maxZoomLevel != null)) // (4)
           ) {
            //calculate based on specified maxZoomLevel (on layer or map)
            desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
        } else {
            //calculate based on specified numZoomLevels (on layer or map)
            // this covers cases (1) and (3)
            desiredZoomLevels = this.numZoomLevels;
        }

        if (desiredZoomLevels != null) {
            //Now that we know what we would *like* the number of zoom levels
            // to be, based on layer or map options, we have to make sure that
            // it does not conflict with the actual limit, as specified by
            // the constants on the layer itself (and calculated into the
            // 'limitZoomLevels' variable).
            this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
        } else {
            // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
            // set on either the layer or the map. So we just use the
            // maximum limit as calculated by the layer's constants.
            this.numZoomLevels = limitZoomLevels;
        }

        //now that the 'numZoomLevels' is appropriately, safely set,
        // we go back and re-calculate the 'maxZoomLevel'.
        this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;

        if (this.RESOLUTIONS != null) {
            var resolutionsIndex = 0;
            this.resolutions = [];
            for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
                this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
            }
            this.maxResolution = this.resolutions[0];
            this.minResolution = this.resolutions[this.resolutions.length - 1];
        }
    },

    /**
     * APIMethod: getResolution
     * Get the current map resolution
     *
     * Returns:
     * {Float} Map units per Pixel
     */
    getResolution: function() {

        if (this.resolutions != null) {
            return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
        } else {
            var resolution = null;

            var viewSize = this.map.getSize();
            var extent = this.getExtent();

            if ((viewSize != null) && (extent != null)) {
                resolution = Math.max( extent.getWidth()  / viewSize.w,
                                       extent.getHeight() / viewSize.h );
            }
            return resolution;
        }
     },

    /**
     * APIMethod: getExtent
     * Calculates using px-> lonlat translation functions on tl and br
     *     corners of viewport
     *
     * Returns:
     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
     *                       bounds of the current viewPort.
     */
    getExtent: function () {
        var extent = null;

        var size = this.map.getSize();

        var tlPx = new OpenLayers.Pixel(0,0);
        var tlLL = this.getLonLatFromViewPortPx(tlPx);

        var brPx = new OpenLayers.Pixel(size.w, size.h);
        var brLL = this.getLonLatFromViewPortPx(brPx);

        if ((tlLL != null) && (brLL != null)) {
            extent = new OpenLayers.Bounds(tlLL.lon,
                                       brLL.lat,
                                       brLL.lon,
                                       tlLL.lat);
        }

        return extent;
    },

    /**
     * Method: getZoomForResolution
     * Get the zoom level for a given resolution
     *
     * Parameters:
     * resolution - {Float}
     *
     * Returns:
     * {Integer} A suitable zoom level for the specified resolution.
     *           If no baselayer is set, returns null.
     */
    getZoomForResolution: function(resolution) {

        if (this.resolutions != null) {
            return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
        } else {
            var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
            return this.getZoomForExtent(extent);
        }
    },

    /********************************************************/
    /*                                                      */
    /*             Translation Functions                    */
    /*                                                      */
    /*    The following functions translate GMaps and OL    */
    /*     formats for Pixel, LonLat, Bounds, and Zoom      */
    /*                                                      */
    /********************************************************/

    //
    // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
    //

    /**
     * Method: getOLZoomFromMapObjectZoom
     * Get the OL zoom index from the map object zoom level
     *
     * Parameters:
     * moZoom - {Integer}
     *
     * Returns:
     * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
     *           Returns null if null value is passed in
     */
    getOLZoomFromMapObjectZoom: function(moZoom) {
        var zoom = null;
        if (moZoom != null) {
            zoom = moZoom - this.minZoomLevel;
        }
        return zoom;
    },

    /**
     * Method: getMapObjectZoomFromOLZoom
     * Get the map object zoom level from the OL zoom level
     *
     * Parameters:
     * olZoom - {Integer}
     *
     * Returns:
     * {Integer} A MapObject level, translated from the passed in olZoom
     *           Returns null if null value is passed in
     */
    getMapObjectZoomFromOLZoom: function(olZoom) {
        var zoom = null;
        if (olZoom != null) {
            zoom = olZoom + this.minZoomLevel;
        }
        return zoom;
    },

    CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
});

<|endoftext|>


<commit_before>/*
    This is used after initialization for all feeds on first startup.
    The main RSS file that is looping.

    The steps are nearly the same except that this is on a loop, and
    there is no filtering because all unseen data by checkTable is,
    by default, new data because it is on a loop.

    It still has to check the table however because the feedparser
    grabs ALL the data each time, new and old, through the link.
*/
const fileOps = require('../util/updateJSON.js')
const FeedParser = require('feedparser');
const requestStream = require('./request.js')
const translator = require('./translator/translate.js')
const sqlConnect = require('./sql/connect.js')
const sqlCmds = require('./sql/commands.js')
const sendToDiscord = require('../util/sendToDiscord.js')

function isEmptyObject(obj) {
  for (var key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      return false;
    }
  }
  return true;
}

module.exports = function (con, channel, rssIndex, sendingTestMessage, callback) {

  var feedparser = new FeedParser()
  var currentFeed = []

  var guild = require(`../sources/${channel.guild.id}.json`)
  var rssList = guild.sources

  //sometimes feeds get deleted mid-retrieval process
  //in that case re-requiring it is necessary
  function isDeletedSource () {
    delete require.cache[require.resolve(`../sources/${channel.guild.id}.json`)]
    guild = require(`../sources/${channel.guild.id}.json`)
    rssList = guild.sources
    if (rssList[rssIndex] == null) return true;
    else return false;
  }

  requestStream(rssList[rssIndex].link, feedparser, con, function() {
    callback()
    feedparser.removeAllListeners('end')
  })

  feedparser.on('error', function (error) {
    console.log(`RSS Parsing Error: (${guild.id}, ${guild.name}) => ${error}, for link ${rssList[rssIndex].link}`)
    feedparser.removeAllListeners('end')
    return callback()
  });

  feedparser.on('readable',function () {
    var stream = this;
    var item;

    while (item = stream.read()) {
      currentFeed.push(item);
    }
});

  feedparser.on('end', function() {

    if (currentFeed.length == 0) {
      if (!sendingTestMessage) return callback();
      callback();
      console.log(`RSS Info: (${guild.id}, ${guild.name}) => "${rssList[rssIndex].name}" has no feeds to send for rsstest.`);
      return channel.sendMessage(`Feed "${rssList[rssIndex].link}" has no available RSS that can be sent.`);
    }

    if (guild.name !== channel.guild.name) {
      console.log(`Guild Info: (${guild.id}, ${guild.name}) => Name change detected, changing guild name from "${guild.name}" to "${channel.guild.name}".`);
      guild.name = channel.guild.name;
      fileOps.updateFile(channel.guild.id, guild, `../sources/${channel.guild.id}.json`);
    }

    let feedName = rssList[rssIndex].name
    var processedItems = 0
    var filteredItems = 0
    //console.log("RSS Info: Starting retrieval for: " + feedName);

    function startDataProcessing() {
      createTable();
    }

    function createTable() {
      if (isDeletedSource()) return callback();
      sqlCmds.createTable(con, feedName, function (err, rows) {
        if (err) {
          console.log(`Database fatal error!. (${guild.id}, ${guild.name}) => RSS index ${rssIndex} Feed ${rssList[rssIndex].link} and date ${new Date()}. Skipping.`);
          //throw err;
          return callback();
        }
        if (sendingTestMessage) {
          let randFeedIndex = Math.floor(Math.random() * (currentFeed.length - 1))
          checkTable(currentFeed[randFeedIndex].guid, currentFeed[randFeedIndex]);
        }
        else {
          let feedLength = currentFeed.length - 1
          for (var x = feedLength; x >= 0; x--){ //get feeds starting from oldest, ending with newest.
            checkTable(currentFeed[x].guid, currentFeed[x]); // .guid is the feed item for the table entry, the second param is the info needed to send the actual message
            filteredItems++;
          }
        }
      })
    }

    function checkTable(data, feed) {
      if (isDeletedSource()) return callback();
      if (sendingTestMessage) {
        filteredItems++;
        gatherResults();
        sendToDiscord(rssIndex, channel, feed, true);
      }
      else {
        sqlCmds.select(con, feedName, data, function (err, results, fields) {
          if (err) throw err;
          if (!isEmptyObject(results)) {
            //console.log(`already seen ${feed.link}, not logging`);
            gatherResults();
          }
          else {
            sendToDiscord(rssIndex, channel, feed, false);
            insertIntoTable(data);
          }
        })
      }
    }

    function insertIntoTable(data) { //inserting the feed into the table marks it as "seen"
    if (isDeletedSource()) return callback();
      sqlCmds.insert(con, feedName, data, function (err,res) {
        if (err) throw err;
        gatherResults();
      })
    }

    function gatherResults(){
      processedItems++;
      //console.log(`${rssList[rssIndex].name} ${filteredItems} ${processedItems}`) //for debugging
      if (processedItems == filteredItems) {
        callback();
      }
    }

    startDataProcessing();
  });
}
<commit_msg>feedback for failed test message<commit_after>/*
    This is used after initialization for all feeds on first startup.
    The main RSS file that is looping.

    The steps are nearly the same except that this is on a loop, and
    there is no filtering because all unseen data by checkTable is,
    by default, new data because it is on a loop.

    It still has to check the table however because the feedparser
    grabs ALL the data each time, new and old, through the link.
*/
const fileOps = require('../util/updateJSON.js')
const FeedParser = require('feedparser');
const requestStream = require('./request.js')
const translator = require('./translator/translate.js')
const sqlConnect = require('./sql/connect.js')
const sqlCmds = require('./sql/commands.js')
const sendToDiscord = require('../util/sendToDiscord.js')

function isEmptyObject(obj) {
  for (var key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      return false;
    }
  }
  return true;
}

module.exports = function (con, channel, rssIndex, sendingTestMessage, callback) {

  var feedparser = new FeedParser()
  var currentFeed = []

  var guild = require(`../sources/${channel.guild.id}.json`)
  var rssList = guild.sources

  //sometimes feeds get deleted mid-retrieval process
  //in that case re-requiring it is necessary
  function isDeletedSource () {
    delete require.cache[require.resolve(`../sources/${channel.guild.id}.json`)]
    guild = require(`../sources/${channel.guild.id}.json`)
    rssList = guild.sources
    if (rssList[rssIndex] == null) return true;
    else return false;
  }

  requestStream(rssList[rssIndex].link, feedparser, con, function() {
    if (sendingTestMessage) channel.sendMessage("Unable to get test feed. Could not connect to feed link.");
    callback()
    feedparser.removeAllListeners('end')
  })

  feedparser.on('error', function (error) {
    console.log(`RSS Parsing Error: (${guild.id}, ${guild.name}) => ${error}, for link ${rssList[rssIndex].link}`)
    feedparser.removeAllListeners('end')
    return callback()
  });

  feedparser.on('readable',function () {
    var stream = this;
    var item;

    while (item = stream.read()) {
      currentFeed.push(item);
    }
});

  feedparser.on('end', function() {

    if (currentFeed.length == 0) {
      if (!sendingTestMessage) return callback();
      callback();
      console.log(`RSS Info: (${guild.id}, ${guild.name}) => "${rssList[rssIndex].name}" has no feeds to send for rsstest.`);
      return channel.sendMessage(`Feed "${rssList[rssIndex].link}" has no available RSS that can be sent.`);
    }

    if (guild.name !== channel.guild.name) {
      console.log(`Guild Info: (${guild.id}, ${guild.name}) => Name change detected, changing guild name from "${guild.name}" to "${channel.guild.name}".`);
      guild.name = channel.guild.name;
      fileOps.updateFile(channel.guild.id, guild, `../sources/${channel.guild.id}.json`);
    }

    let feedName = rssList[rssIndex].name
    var processedItems = 0
    var filteredItems = 0
    //console.log("RSS Info: Starting retrieval for: " + feedName);

    function startDataProcessing() {
      createTable();
    }

    function createTable() {
      if (isDeletedSource()) return callback();
      sqlCmds.createTable(con, feedName, function (err, rows) {
        if (err) {
          console.log(`Database fatal error!. (${guild.id}, ${guild.name}) => RSS index ${rssIndex} Feed ${rssList[rssIndex].link} and date ${new Date()}. Skipping.`);
          //throw err;
          return callback();
        }
        if (sendingTestMessage) {
          let randFeedIndex = Math.floor(Math.random() * (currentFeed.length - 1))
          checkTable(currentFeed[randFeedIndex].guid, currentFeed[randFeedIndex]);
        }
        else {
          let feedLength = currentFeed.length - 1
          for (var x = feedLength; x >= 0; x--){ //get feeds starting from oldest, ending with newest.
            checkTable(currentFeed[x].guid, currentFeed[x]); // .guid is the feed item for the table entry, the second param is the info needed to send the actual message
            filteredItems++;
          }
        }
      })
    }

    function checkTable(data, feed) {
      if (isDeletedSource()) return callback();
      if (sendingTestMessage) {
        filteredItems++;
        gatherResults();
        sendToDiscord(rssIndex, channel, feed, true);
      }
      else {
        sqlCmds.select(con, feedName, data, function (err, results, fields) {
          if (err) throw err;
          if (!isEmptyObject(results)) {
            //console.log(`already seen ${feed.link}, not logging`);
            gatherResults();
          }
          else {
            sendToDiscord(rssIndex, channel, feed, false);
            insertIntoTable(data);
          }
        })
      }
    }

    function insertIntoTable(data) { //inserting the feed into the table marks it as "seen"
    if (isDeletedSource()) return callback();
      sqlCmds.insert(con, feedName, data, function (err,res) {
        if (err) throw err;
        gatherResults();
      })
    }

    function gatherResults(){
      processedItems++;
      //console.log(`${rssList[rssIndex].name} ${filteredItems} ${processedItems}`) //for debugging
      if (processedItems == filteredItems) {
        callback();
      }
    }

    startDataProcessing();
  });
}
<|endoftext|>


<commit_before>'use strict';

var url = require('url');
var util = require('util');
var md5 = require('MD5');
var request = require('request');
var _ = require('lodash');
var exec = require('exec');

var config = require('./config.json');

var host = config.host;
var apiKey = config.apiKey;
var secret = config.secret;

var sessionKey = config.sessionKey;

function getAPICommandURL(method, options) {
	return url.format({
		protocol: 'http',
		hostname: host,
		query: _.merge({
			method: method,
			api_key: apiKey,
		    format: 'json'
		}, options)
	});
}

function getAPIToken(callback) {
	var sign = util.format('api_key%smethodauth.getToken%s', apiKey, secret);
	var url = getAPICommandURL('auth.getToken', { api_sig: sign });

	request(url, function(error, data, body) {
		callback(JSON.parse(body).token);
	});
}

var browser = 'chromium-browser';

module.exports.userAuth = function(token) {
	var userAuthURL = util.format('http://www.last.fm/api/auth?api_key=%s&token=%s',apiKey, token);
	exec([browser, userAuthURL], function() {});
};

function getAPISig(method, params) {
	var allParams = _.merge(params, { method: method });
	var allParamsKeys = Object.keys(allParams).sort();

	var sign = allParamsKeys.map(function(paramKey) {
		return paramKey + allParams[paramKey];
	}).join('').concat(secret);

	return md5(sign);
}

function doLFMQuery(method, params, callback, authRequired, requestMethod) {

	params.api_key = apiKey;

	if (authRequired) {
   		params.sk = touzbiSessionKey;
		params.api_sig = getAPISig(method, params);
	}

	var url = getAPICommandURL(method, params);

	var rm = requestMethod === 'get' ? request.get : requestMethod === 'post' ? request.post : request.get;

	rm({
		url: url,
		form: params
	}, callback);
}

module.exports.getAPIToken = getAPIToken;
module.exports.doLFMQuery = doLFMQuery;

<commit_msg>fixed variable name<commit_after>'use strict';

var url = require('url');
var util = require('util');
var md5 = require('MD5');
var request = require('request');
var _ = require('lodash');
var exec = require('exec');

var config = require('./config.json');

var host = config.host;
var apiKey = config.apiKey;
var secret = config.secret;

var sessionKey = config.sessionKey;

function getAPICommandURL(method, options) {
	return url.format({
		protocol: 'http',
		hostname: host,
		query: _.merge({
			method: method,
			api_key: apiKey,
		    format: 'json'
		}, options)
	});
}

function getAPIToken(callback) {
	var sign = util.format('api_key%smethodauth.getToken%s', apiKey, secret);
	var url = getAPICommandURL('auth.getToken', { api_sig: sign });

	request(url, function(error, data, body) {
		callback(JSON.parse(body).token);
	});
}

var browser = 'chromium-browser';

module.exports.userAuth = function(token) {
	var userAuthURL = util.format('http://www.last.fm/api/auth?api_key=%s&token=%s',apiKey, token);
	exec([browser, userAuthURL], function() {});
};

function getAPISig(method, params) {
	var allParams = _.merge(params, { method: method });
	var allParamsKeys = Object.keys(allParams).sort();

	var sign = allParamsKeys.map(function(paramKey) {
		return paramKey + allParams[paramKey];
	}).join('').concat(secret);

	return md5(sign);
}

function doLFMQuery(method, params, callback, authRequired, requestMethod) {

	params.api_key = apiKey;

	if (authRequired) {
   		params.sk = sessionKey;
		params.api_sig = getAPISig(method, params);
	}

	var url = getAPICommandURL(method, params);

	var rm = requestMethod === 'get' ? request.get : requestMethod === 'post' ? request.post : request.get;

	rm({
		url: url,
		form: params
	}, callback);
}

module.exports.getAPIToken = getAPIToken;
module.exports.doLFMQuery = doLFMQuery;

<|endoftext|>


<commit_before>/**
 @module Client

 This module represents an encapsulation of Creator Client Services
 in the Creator REST API.
 uses http request module
 */

var Q = require('q'),
    request = require('request'),
    moduleinfo = require('../package.json'),

    /* Resources */
    config = require('./resources/config'),
    Navigator = require('./resources/navigator'),
    Authenticator = require('./resources/authenticator');

/**
 Client
 @constructor
 @param {string} key - Login access key, as seen in the creator developer console
 @param {string} secret - Login access secret token, as seen in the creator developer console
 @param {object} options (optional) - optional config for the REST client
 - @member {string} host - host for the Creator Device Server REST API
 **/
function Client(key, secret, host, timeout) {

    /* Required client config */

    /* if auth key and secret are passed in manually we might need to trim spaces */
    this.authKey = key.replace(/ /g, '');
    this.authSecret = secret.replace(/ /g, '');

    /* Optional config */
    this.host = host || config.defaultHost;
    config.defaultHost = host || config.defaultHost;
    this.timeout = timeout || 31000; // request timeout in milliseconds

    Authenticator.authenticate(key, secret).then(function (t) {
        this.authorization = t;
    });

}

/**
 Construct URL helper for request funciton
 @returns {string} - the full URL
 */
Client.prototype.constructURL = function (extension) {
    return this.host + '/' + extension;
};

/**
 Make an authenticated request against the Creator Device Server.
 */
Client.prototype.request = function (options, callback) {
    var client = this,
        deferred = Q.defer();

    /* Set Options fields */
    options.headers = {
        'Accept': 'application/json',
        'Accept-Charset': 'utf-8',
        'User-Agent': 'creator-node/' + moduleinfo.version,
    };
    if (!options.timeout) options.timeout = client.timeout; // default timeout
    if (options.follow === undefined) options.follow = true; // following by default
    if (!options.method) options.method = "GET";
    if (!options.nocache) options.nocache = false;

    var rel = options.relativeEntryPoint;
    if (rel)
        if (rel.indexOf('http') > -1 || rel.indexOf('https') > -1 || rel.indexOf('www') > -1)
            throw config.ONLY_RELATIVE_ERROR;

    switch (options.method) {
        case "PUT":
        case "POST":
            if (typeof options.data === 'object') {
                options.body = JSON.stringify(options.data);
                options.headers["content-type"] = "application/json";
            }
            break;
    }

    if (options.follow) {
        if (!options.steps) throw config.STEPS_ERROR;
        else {
            // Authenticate first
            Authenticator.authenticate(this.authKey, this.authSecret).then(function (t) {
                this.authorization = t;

                // Then navigate
                Navigator.getURL(options.steps, this.authorization, options.relativeEntryPoint, options.nocache).then(function (url) {
                    options.headers.Authorization = this.authorization.token;
                    options.url = url;

                    // And finally send out the final request
                    request(options, function (err, response, body) {
                        if (err) {
                            deferred.reject(err);
                            return;
                        }
                        deferred.resolve(new Client.prototype.response(response.statusCode, body));
                    });
                });
            });
        }
    }
    else throw config.FOLLOW_FLAG_ERROR; // TODO: support absolute URL

    // Return promise, but also support original node callback style
    deferred.promise.nodeify(callback);
    return deferred.promise;
};

/**
 * Store the response in a structured manner
 * TODO
 */

Client.prototype.response = function (statusCode, body) {
    this.statusCode = statusCode;
    this.body = body ? JSON.parse(body) : null;
};

module.exports = Client;
<commit_msg>Re-added support for callback style requests<commit_after>/**
 @module Client

 This module represents an encapsulation of Creator Client Services
 in the Creator REST API.
 uses http request module
 */

var Q = require('q'),
    request = require('request'),
    moduleinfo = require('../package.json'),

    /* Resources */
    config = require('./resources/config'),
    Navigator = require('./resources/navigator'),
    Authenticator = require('./resources/authenticator');

/**
 Client
 @constructor
 @param {string} key - Login access key, as seen in the creator developer console
 @param {string} secret - Login access secret token, as seen in the creator developer console
 @param {object} options (optional) - optional config for the REST client
 - @member {string} host - host for the Creator Device Server REST API
 **/
function Client(key, secret, host, timeout) {

    /* Required client config */

    /* if auth key and secret are passed in manually we might need to trim spaces */
    this.authKey = key.replace(/ /g, '');
    this.authSecret = secret.replace(/ /g, '');

    /* Optional config */
    this.host = host || config.defaultHost;
    config.defaultHost = host || config.defaultHost;
    this.timeout = timeout || 31000; // request timeout in milliseconds

    Authenticator.authenticate(key, secret).then(function (t) {
        this.authorization = t;
    });

}

/**
 Construct URL helper for request funciton
 @returns {string} - the full URL
 */
Client.prototype.constructURL = function (extension) {
    return this.host + '/' + extension;
};

/**
 Make an authenticated request against the Creator Device Server.
 */
Client.prototype.request = function (options, callback) {
    var client = this,
        deferred = Q.defer();

    /* Set Options fields */
    options.headers = {
        'Accept': 'application/json',
        'Accept-Charset': 'utf-8',
        'User-Agent': 'creator-node/' + moduleinfo.version,
    };
    if (!options.timeout) options.timeout = client.timeout; // default timeout
    if (options.follow === undefined) options.follow = true; // following by default
    if (!options.method) options.method = "GET";
    if (!options.nocache) options.nocache = false;

    var rel = options.relativeEntryPoint;
    if (rel)
        if (rel.indexOf('http') > -1 || rel.indexOf('https') > -1 || rel.indexOf('www') > -1)
            throw config.ONLY_RELATIVE_ERROR;

    switch (options.method) {
        case "PUT":
        case "POST":
            if (typeof options.data === 'object') {
                options.body = JSON.stringify(options.data);
                options.headers["content-type"] = "application/json";
            }
            break;
    }

    if (options.follow) {
        if (!options.steps) throw config.STEPS_ERROR;
        else {
            // Authenticate first
            Authenticator.authenticate(this.authKey, this.authSecret).then(function (t) {
                this.authorization = t;

                // Then navigate
                Navigator.getURL(options.steps, this.authorization, options.relativeEntryPoint, options.nocache).then(function (url) {
                    options.headers.Authorization = this.authorization.token;
                    options.url = url;

                    // And finally send out the final request
                    request(options, function (err, response, body) {
                        if (err) {
                            deferred.reject(err);
                            return;
                        }
                        else if(callback && body) callback(JSON.parse(body));
                        else deferred.resolve(new Client.prototype.response(response.statusCode, body));
                    });
                });
            });
        }
    }
    else throw config.FOLLOW_FLAG_ERROR; // TODO: support absolute URL

    // Return promise, but also support original node callback style
    deferred.promise.nodeify(callback);

    return deferred.promise;
};

/**
 * Store the response in a structured manner
 * TODO
 */

Client.prototype.response = function (statusCode, body) {
    this.statusCode = statusCode;
    this.body = body ? JSON.parse(body) : null;
};

module.exports = Client;
<|endoftext|>


<commit_before>/**
 * Created by apizzimenti on 12/28/15.
 */

/*
 The MIT License (MIT)
 Copyright (c) 2015 Anthony Pizzimenti

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions
 of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.
 */

var data = require('./data');

function Format(json) {
    var obj = JSON.parse(json),
        current = obj.currently,
        predict = obj.daily.data.slice(1, 4);

    this.dates = data.collectDates(predict);
    this.highs = data.collectHighs(predict);
    this.lows = data.collectLows(predict);
    this.summaries = data.collectSummary(predict);
    this.icons = data.icon(predict);

    this.currentWeather = data.display(current);
}

Format.prototype.tabled = function () {
    return data.displayTable(this.dates, this.highs, this.lows, this.icons);
};

function instance(json) {
    return new Format(json);
}

module.exports = instance;<commit_msg>formatting - lol for the 3rd tiem<commit_after>/**
 * Created by apizzimenti on 12/28/15.
 */

/*
 The MIT License (MIT)
 Copyright (c) 2015 Anthony Pizzimenti

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions
 of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.
 */

var data = require('./data');

function Format(json) {
    var obj = JSON.parse(json),
        current = obj.currently,
        predict = obj.daily.data.slice(1, 5);

    this.dates = data.collectDates(predict);
    this.highs = data.collectHighs(predict);
    this.lows = data.collectLows(predict);
    this.summaries = data.collectSummary(predict);
    this.icons = data.icon(predict);

    this.currentWeather = data.display(current);
}

Format.prototype.tabled = function () {
    return data.displayTable(this.dates, this.highs, this.lows, this.icons);
};

function instance(json) {
    return new Format(json);
}

module.exports = instance;<|endoftext|>


<commit_before>import {ERROR, WARN, INFO, DEBUG} from './logger/level.js';

/**
 * A logging class that can be used with most functions to provide status output
 * @param {Object} args the arguments for the class
 * @param {Object} [args.logger=console] the underlying logger that will be used to output the logging messages
 * @param {number} [args.level=logger.level.WARN] the logging level
 */
export default class {
  constructor({console=console, level=WARN} = {}) {
    Object.defineProperties(this, {
      level: {value: level, writable: true},
      console: {value: console}
    });
  }

  /**
   * Logs a debug message, this is usually useful to developers
   * @param {...*} args the objects to log
   */
  debug(...args) {
    if (DEBUG <= this.level) {
      this.console.debug(...args);
    }
  }

  /**
   * Logs a message that would be useful to a user
   * @param {...*} args the objects to log
   */
  info(...args) {
    if (INFO <= this.level) {
      this.console.info(...args);
    }
  }

  /**
   * Logs a recoverable error
   * @param {...*} args the objects to log
   */
  warn(...args) {
    if (WARN <= this.level) {
      this.console.warn(...args);
    }
  }

  /**
   * Logs a non-recoverable error
   * @param {...*} args the objects to log
   */
  error(...args) {
    if (ERROR <= this.level) {
      this.console.error(...args);
    }
  }
}
<commit_msg>Fix circular console references<commit_after>import {ERROR, WARN, INFO, DEBUG} from './logger/level.js';

const c = console;

/**
 * A logging class that can be used with most functions to provide status output
 * @param {Object} args the arguments for the class
 * @param {Object} [args.logger=console] the underlying logger that will be used to output the logging messages
 * @param {number} [args.level=logger.level.WARN] the logging level
 */
export default class {
  constructor({console=c, level=WARN} = {}) {
    Object.defineProperties(this, {
      level: {value: level, writable: true},
      console: {value: console}
    });
  }

  /**
   * Logs a debug message, this is usually useful to developers
   * @param {...*} args the objects to log
   */
  debug(...args) {
    if (DEBUG <= this.level) {
      this.console.debug(...args);
    }
  }

  /**
   * Logs a message that would be useful to a user
   * @param {...*} args the objects to log
   */
  info(...args) {
    if (INFO <= this.level) {
      this.console.info(...args);
    }
  }

  /**
   * Logs a recoverable error
   * @param {...*} args the objects to log
   */
  warn(...args) {
    if (WARN <= this.level) {
      this.console.warn(...args);
    }
  }

  /**
   * Logs a non-recoverable error
   * @param {...*} args the objects to log
   */
  error(...args) {
    if (ERROR <= this.level) {
      this.console.error(...args);
    }
  }
}
<|endoftext|>


<commit_before>var Model = require('./Model');
var triggerParams = require('./mixins/triggerParams');
var volumeParams = require('./mixins/volumeParams');
var oscillatorParams = require('./mixins/oscillatorParams');
var sampleParams = require('./mixins/sampleParams');
var numberInRangeType = require('./types/numberInRange');

var Params = Model.extend(triggerParams, volumeParams, oscillatorParams, sampleParams, {
  type: 'params',

  props: {
    tempo: ['positiveNumber', true, 120]
  },

  dataTypes: {
    positiveNumber: numberInRangeType('positiveNumber', 1, Infinity)
  },

  initialize: function () {
    Model.prototype.initialize.apply(this, arguments);
    this.vent.trigger('clock:tempo', this);
    this.length  = this.calculateLength();
  },

  calculateLength: function () {
    var existingLength = this.length || 0;
    var lengthFromDuration = this.duration && this.lengthFromDuration(this.duration) || 0;
    return lengthFromDuration && lengthFromDuration < existingLength ? lengthFromDuration : existingLength;
  },

  lengthFromDuration: function (duration) {
    var secondsPerBeat = 60 / this.tempo;
    var secondsPerTick = secondsPerBeat / 96;
    return duration * secondsPerTick;
  }
});

Params.fromSources = function () {
  var sources = [].slice.call(arguments).reverse();
  var params = {};

  var multipliers = ['volume'];
  var adders = ['pitch', 'pan'];
  var keys = Object.keys(Params.prototype._definition);

  keys.forEach(function (key) {
    if (key === 'id') { return; }
    sources.forEach(function (source) {
      if (!source) { return; }
      var value = source[key];
      if (~multipliers.indexOf(key)) {
        if (!value || value < 0) { return; }
        var multiplier = value / 100;
        params[key] = params[key] ? params[key] * multiplier : value;
      }
      else if (~adders.indexOf(key)) {
        value = value || 0;
        params[key] = (params[key] || 0) + value;
      }
      else {
        params[key] = value || params[key];
      }
    });

    if (key === 'pan' && params[key] < -100) {
      params[key] = -100;
    }
    else if (key === 'pan' && params[key] > 100) {
      params[key] = 100;
    }
    else if (typeof params[key] === 'undefined') {
      delete params[key];
    }
  });

  return new Params(params);
};

module.exports = Params;
<commit_msg>fix params not using length from duration if no existing length<commit_after>var Model = require('./Model');
var triggerParams = require('./mixins/triggerParams');
var volumeParams = require('./mixins/volumeParams');
var oscillatorParams = require('./mixins/oscillatorParams');
var sampleParams = require('./mixins/sampleParams');
var numberInRangeType = require('./types/numberInRange');

var Params = Model.extend(triggerParams, volumeParams, oscillatorParams, sampleParams, {
  type: 'params',

  props: {
    tempo: ['positiveNumber', true, 120]
  },

  dataTypes: {
    positiveNumber: numberInRangeType('positiveNumber', 1, Infinity)
  },

  initialize: function () {
    Model.prototype.initialize.apply(this, arguments);
    this.vent.trigger('clock:tempo', this);
    this.length  = this.calculateLength();
  },

  calculateLength: function () {
    var existingLength = this.length || 0;
    var lengthFromDuration = this.duration && this.lengthFromDuration(this.duration) || 0;
    if (lengthFromDuration && lengthFromDuration < existingLength || !existingLength) {
      return lengthFromDuration;
    }
    else {
      return existingLength;
    }
  },

  lengthFromDuration: function (duration) {
    var secondsPerBeat = 60 / this.tempo;
    var secondsPerTick = secondsPerBeat / 96;
    return duration * secondsPerTick;
  }
});

Params.fromSources = function () {
  var sources = [].slice.call(arguments).reverse();
  var params = {};

  var multipliers = ['volume'];
  var adders = ['pitch', 'pan'];
  var keys = Object.keys(Params.prototype._definition);

  keys.forEach(function (key) {
    if (key === 'id') { return; }
    sources.forEach(function (source) {
      if (!source) { return; }
      var value = source[key];
      if (~multipliers.indexOf(key)) {
        if (!value || value < 0) { return; }
        var multiplier = value / 100;
        params[key] = params[key] ? params[key] * multiplier : value;
      }
      else if (~adders.indexOf(key)) {
        value = value || 0;
        params[key] = (params[key] || 0) + value;
      }
      else {
        params[key] = value || params[key];
      }
    });

    if (key === 'pan' && params[key] < -100) {
      params[key] = -100;
    }
    else if (key === 'pan' && params[key] > 100) {
      params[key] = 100;
    }
    else if (typeof params[key] === 'undefined') {
      delete params[key];
    }
  });

  return new Params(params);
};

module.exports = Params;
<|endoftext|>