<commit_before>(function($) {

    /**
     * .slider
     *
     * Begins the slideshow by choosing the type of slide and duration
     *
     * type        Type of slideshow to run; Defaults to 'fade'
     * duration    Time in miliseconds that each element is visible; Defaults to
     *                 5000
     */
    $.fn.slider = function(options) {
        var defaults = {
            'type':'Fade',
            'duration':5000
        };
        options = overwrite(defaults, options);

        var type = options.type;
        var duration = options.duration;
        var $container = this;
        var count = 0;
        var validTypes = ['Fade','FadeInto','Horizontal','Vertical'];

        console.log(options);

        this.initActive();

        if(validTypes.indexOf(options.type) !== -1) {
            this["init"+options.type]();

            var intervalID = setInterval(function() {
                count = $container["slide"+options.type](intervalID, count);
            }, options.duration);
        } else {
            alert(options.type+" is not a supported slideshow type.");
            return false;
        }
    };

    $.fn.initActive = function() {
        this.children(":first").addClass('active');
    };

    /**
     * Sets the initial state for the FadeInto slideshow
     *
     * start    z-index for top-most element in slideshow; Defaults to 100
     */
    $.fn.initFadeInto = function() {
        // Iterates through all children of 'this'
        //     sets initiale z-index (start - order in 'this')
        //     sets position: absolute
        //     shows child
        var count = this.children().length;
        for(var i=1; i<=count; i=i+1) {
            this.find(":nth-child("+i+")")
            .css({
                'z-index':count - i,
                'position':'absolute'
            })
            .show();
        }
    };

    $.fn.slideFadeInto = function (intervalID, count, options) {
        var defaults = {
            'fadeSpeed':'slow',
            'stop':null
        };
        options = overwrite(defaults, options);

        if((options.stop !== null)&&(count == options.stop))
            clearInterval(intervalID);

        var $swap = this.swap();
        var $container = this;

        $swap["active"].fadeOut(options.fadeSpeed, function() {
            $swap["active"].hide(function() {
                $swap["next"].addClass('active');
                var $element = $swap["next"];

                for(var count=$container.children().length;count>0;count=count-1) {
                    $element.css({'z-index':count}).show();

                    $element = $element.next().length ? $element.next()
                        : $container.children(":first");
                }
            });
        });
    };

    $.fn.initFade = function() {
        this.children().hide().fadeOut();
        this.children(".active").show();
    };

    $.fn.slideFade = function (intervalID, count, options) {
        var defaults = {
            'fadeSpeed':'slow',
            'stop':null
        };
        options = overwrite(defaults, options);

        if((options.stop !== null)&&(count == options.stop))
            clearInterval(intervalID);

        var $swap = this.swap();

        $swap["active"].fadeOut(fadeSpeed, function () {
            $swap["active"].hide(function () {
                $swap["next"].addClass('active')
                    .fadeIn(fadeSpeed);
            });
        });
    };

    $.fn.initHorizontal = function() {
        this.children().hide();
        this.children(".active").show();
        console.log('.initHorizontal()');
        return true;
    };

    $.fn.slideHorizontal = function(options) {
        console.log('.slideHorizontal()');
        var defaults = {
            'fadeSpeed':'slow'
        };
        options = overwrite(defaults, options);

        var $swap = this.swap();
        console.log($swap);
        $swap['next'].show().addClass('active');
        $swap['active'].slide().hide();
    };

    $.fn.swap = function () {
        var $active = this.children(".active").removeClass('active');
        var $next = $active.next().length ? $active.next()
            : this.children(":first");

        return {"active":$active,"next":$next};
    };

}) (jQuery);
<commit_msg>Creates initActive() to set the first active div<commit_after>(function($) {

    /**
     * .slider
     *
     * Begins the slideshow by choosing the type of slide and duration
     *
     * type        Type of slideshow to run; Defaults to 'fade'
     * duration    Time in miliseconds that each element is visible; Defaults to
     *                 5000
     */
    $.fn.slider = function(options) {
        var defaults = {
            'type':'Fade',
            'duration':5000
        };
        options = overwrite(defaults, options);

        var type = options.type;
        var duration = options.duration;
        var $container = this;
        var count = 0;
        var validTypes = ['Fade','FadeInto','Horizontal','Vertical'];

        console.log(options);

        this.initActive();

        if(validTypes.indexOf(options.type) !== -1) {
            this["init"+options.type]();

            var intervalID = setInterval(function() {
                count = $container["slide"+options.type](intervalID, count);
            }, options.duration);
        } else {
            alert(options.type+" is not a supported slideshow type.");
            return false;
        }
    };

    $.fn.initActive = function() {
        this.children(":first").addClass('active');
    };

    /**
     * Sets the initial state for the FadeInto slideshow
     *
     * start    z-index for top-most element in slideshow; Defaults to 100
     */
    $.fn.initFadeInto = function() {
        // Iterates through all children of 'this'
        //     sets initiale z-index (start - order in 'this')
        //     sets position: absolute
        //     shows child
        var count = this.children().length;
        for(var i=1; i<=count; i=i+1) {
            this.find(":nth-child("+i+")")
            .css({
                'z-index':count - i,
                'position':'absolute'
            })
            .show();
        }
    };

    $.fn.slideFadeInto = function (intervalID, count, options) {
        var defaults = {
            'fadeSpeed':'slow',
            'stop':null
        };
        options = overwrite(defaults, options);

        if((options.stop !== null)&&(count == options.stop))
            clearInterval(intervalID);

        var $swap = this.swap();
        var $container = this;

        $swap["active"].fadeOut(options.fadeSpeed, function() {
            $swap["active"].hide(function() {
                $swap["next"].addClass('active');
                var $element = $swap["next"];

                for(var count=$container.children().length;count>0;count=count-1) {
                    $element.css({'z-index':count}).show();

                    $element = $element.next().length ? $element.next()
                        : $container.children(":first");
                }
            });
        });
    };

    $.fn.initFade = function() {
        this.children().hide().fadeOut();
        this.children(".active").show();
    };

    $.fn.slideFade = function (intervalID, count, options) {
        var defaults = {
            'fadeSpeed':'slow',
            'stop':null
        };
        options = overwrite(defaults, options);

        if((options.stop !== null)&&(count == options.stop))
            clearInterval(intervalID);

        var $swap = this.swap();

        $swap["active"].fadeOut(fadeSpeed, function () {
            $swap["active"].hide(function () {
                $swap["next"].addClass('active')
                    .fadeIn(fadeSpeed);
            });
        });
    };

    $.fn.initHorizontal = function() {
        this.children().hide();
        this.children(".active").show();
        console.log('.initHorizontal()');
        return true;
    };

    $.fn.slideHorizontal = function(options) {
        console.log('.slideHorizontal()');
        var defaults = {
            'fadeSpeed':'slow'
        };
        options = overwrite(defaults, options);

        var $swap = this.swap();
        console.log($swap);
        $swap['next'].show().addClass('active');
        $swap['active'].slide(function(){
            this.hide();
        });
    };

    $.fn.swap = function () {
        var $active = this.children(".active").removeClass('active');
        var $next = $active.next().length ? $active.next()
            : this.children(":first");

        return {"active":$active,"next":$next};
    };

}) (jQuery);
<|endoftext|>


<commit_before>(function($) {

    /**
     * .slider
     *
     * Begins the slideshow by choosing the type of slide and duration
     *
     * type        Type of slideshow to run; Defaults to 'fade'
     * duration    Time in miliseconds that each element is visible; Defaults to
     *                 5000
     */
    $.fn.slider = function(options) {
        var defaults = {
            'type':'Fade',
            'duration':5000
        };

        options = overwrite(defaults, options);
        var type = options.type;
        var duration = options.duration;
        var $container = this;
        var count = 0;
        var validTypes = ['Fade','FadeInto','Horizontal','Vertical'];

        console.log($.fn.slider);

        if(validTypes.indexOf(options.type) !== -1) {
            this["init"+options.type]();

            var intervalID = setInterval(function() {
                count = $container["slide"+options.type](intervalID, count);
            }, options.duration);
        } else {
            alert(options.type+" is not a supported slideshow type.");
            return false;
        }
    };

    /**
     * Sets the initial state for the FadeInto slideshow
     *
     * start    z-index for top-most element in slideshow; Defaults to 100
     */
    $.fn.initFadeInto = function() {
        // Adds .active to first element in 'this'
        this.children(":first").addClass('active');

        // Iterates through all children of 'this'
        //     sets initiale z-index (start - order in 'this')
        //     sets position: absolute
        //     shows child
        var count = this.children().length;
        for(var i=1; i<=count; i=i+1) {
            this.find(":nth-child("+i+")")
            .css({
                'z-index':count - i,
                'position':'absolute'
            })
            .show();
        }
    };

    $.fn.slideFadeInto = function (intervalID, count, fadeSpeed) {
        // if(count == 6) clearInterval(intervalID);
        // if(count !== 0 && count%7 == 0 ) this.reset();

        fadeSpeed = typeof fadeSpeed !== 'undefined' ? fadeSpeed : 'slow';
        var $swap = this.swap();
        var $container = this;

        $swap["active"].fadeOut(fadeSpeed, function() {
            $swap["active"].hide(function() {
                $swap["next"].addClass('active');
                var $element = $swap["next"];

                for(var count=$container.children().length;count>0;count=count-1) {
                    $element.css({'z-index':count}).show();

                    $element = $element.next().length ? $element.next()
                        : $container.children(":first");
                }
            });
        });
    };

    $.fn.initFade = function() {
        this.children().hide().fadeOut();
        this.children(":first").addClass('active').show();
    };

    $.fn.slideFade = function (fadeSpeed) {
        fadeSpeed = typeof fadeSpeed !== 'undefined' ? fadeSpeed : 'slow';
        var $swap = this.swap();

        $swap["active"].fadeOut(fadeSpeed, function () {
            $swap["active"].hide(function () {
                $swap["next"].addClass('active')
                    .fadeIn(fadeSpeed);
            });
        });
    };

    $.fn.swap = function () {
        var $active = this.children(".active").toggleClass('active');
        var $next = $active.next().length ? $active.next()
            : this.children(":first");

        return {"active":$active,"next":$next};
    };

}) (jQuery);
<commit_msg>Changes reference to type in options['type'] in slider()<commit_after>(function($) {

    /**
     * .slider
     *
     * Begins the slideshow by choosing the type of slide and duration
     *
     * type        Type of slideshow to run; Defaults to 'fade'
     * duration    Time in miliseconds that each element is visible; Defaults to
     *                 5000
     */
    $.fn.slider = function(options) {
        var defaults = {
            'type':'Fade',
            'duration':5000
        };

        options = overwrite(defaults, options);
        var type = options.type;
        var duration = options.duration;
        var $container = this;
        var count = 0;
        var validTypes = ['Fade','FadeInto','Horizontal','Vertical'];

        console.log(options);

        if(validTypes.indexOf(options.type) !== -1) {
            this["init"+options.type]();

            var intervalID = setInterval(function() {
                count = $container["slide"+options.type](intervalID, count);
            }, options.duration);
        } else {
            alert(options.type+" is not a supported slideshow type.");
            return false;
        }
    };

    /**
     * Sets the initial state for the FadeInto slideshow
     *
     * start    z-index for top-most element in slideshow; Defaults to 100
     */
    $.fn.initFadeInto = function() {
        // Adds .active to first element in 'this'
        this.children(":first").addClass('active');

        // Iterates through all children of 'this'
        //     sets initiale z-index (start - order in 'this')
        //     sets position: absolute
        //     shows child
        var count = this.children().length;
        for(var i=1; i<=count; i=i+1) {
            this.find(":nth-child("+i+")")
            .css({
                'z-index':count - i,
                'position':'absolute'
            })
            .show();
        }
    };

    $.fn.slideFadeInto = function (intervalID, count, fadeSpeed) {
        // if(count == 6) clearInterval(intervalID);
        // if(count !== 0 && count%7 == 0 ) this.reset();

        fadeSpeed = typeof fadeSpeed !== 'undefined' ? fadeSpeed : 'slow';
        var $swap = this.swap();
        var $container = this;

        $swap["active"].fadeOut(fadeSpeed, function() {
            $swap["active"].hide(function() {
                $swap["next"].addClass('active');
                var $element = $swap["next"];

                for(var count=$container.children().length;count>0;count=count-1) {
                    $element.css({'z-index':count}).show();

                    $element = $element.next().length ? $element.next()
                        : $container.children(":first");
                }
            });
        });
    };

    $.fn.initFade = function() {
        this.children().hide().fadeOut();
        this.children(":first").addClass('active').show();
    };

    $.fn.slideFade = function (fadeSpeed) {
        fadeSpeed = typeof fadeSpeed !== 'undefined' ? fadeSpeed : 'slow';
        var $swap = this.swap();

        $swap["active"].fadeOut(fadeSpeed, function () {
            $swap["active"].hide(function () {
                $swap["next"].addClass('active')
                    .fadeIn(fadeSpeed);
            });
        });
    };

    $.fn.swap = function () {
        var $active = this.children(".active").toggleClass('active');
        var $next = $active.next().length ? $active.next()
            : this.children(":first");

        return {"active":$active,"next":$next};
    };

}) (jQuery);
<|endoftext|>


<commit_before>/*======================================================
************   Slider   ************
======================================================*/
var Slider = function (container, options) {
    var defaults = {
        initialSlide: 0,
        spaceBetween: 0,
        speed: 300,
        slidesPerView: 1,
        direction: 'horizontal',
        pagination: '.slider-pagination',
        paginationHide: true,
        slideClass: 'slider-slide',
        slideActiveClass: 'slider-slide-active',
        slideNextClass: 'slider-slide-next',
        slidePrevClass: 'slider-slide-prev',
        wrapperClass: 'slider-wrapper',
        bulletClass: 'slider-pagination-bullet',
        bulletActiveClass: 'slider-pagination-active'
    };
    options = options || {};
    for (var def in defaults) {
        if (typeof options[def] === 'undefined') {
            options[def] = defaults[def];
        }
    }

    var s = this;
    s.options = options;
    s.container = $(container);
    if (s.container.length === 0) return;

    if (s.options.direction === 'vertical') {
        s.container.addClass('slider-container-vertical');
    }

    s.wrapper = s.container.find('.' + s.options.wrapperClass);

    if (s.options.pagination) {
        s.paginationContainer = $(s.options.pagination);
    }

    s.activeSlideIndex = s.previousSlideIndex = s.options.initialSlide || 0;

    var isH = s.options.direction === 'horizontal';

    s.updateSlides = function () {
        s.slides = s.wrapper.children('.' + s.options.slideClass);

        if (s.options.spaceBetween !== 0) {
            if (isH) s.slides.css({marginRight: s.options.spaceBetween + 'px'});
            else s.slides.css({marginBottom: s.options.spaceBetween + 'px'});
        }
        if (s.options.slidesPerView > 1) {
            var sizeValue = '(100% - ' + (s.options.slidesPerView - 1) * options.spaceBetween + 'px)/' + s.options.slidesPerView;
            if (isH) {
                s.slides.css('width', '-webkit-calc(' + sizeValue + ')');
                s.slides.css('width', '-moz-calc(' + sizeValue + ')');
                s.slides.css('width', 'calc(' + sizeValue + ')');
            }
            else {
                s.slides.css('height', '-webkit-calc(' + sizeValue + ')');
                s.slides.css('height', '-moz-calc(' + sizeValue + ')');
                s.slides.css('height', 'calc(' + sizeValue + ')');
            }
        }

    };

    s.updatePagination = function () {
        if (s.paginationContainer && s.paginationContainer.length > 0) {
            var bulletsHTML = '';
            for (var i = 0; i < s.slides.length - s.options.slidesPerView + 1; i++) {
                bulletsHTML += '';
            }
            s.paginationContainer.html(bulletsHTML);
            s.bullets = s.paginationContainer.find('.' + s.options.bulletClass);
        }
    };

    s.updateSize = function () {
        s.width = s.container.width();
        s.height = s.container.height();
        s.size = isH ? s.width : s.height;
    };

    s.attachEvents = function (detach) {
        var action = detach ? 'off' : 'on';
        // Slide between photos
        s.container[action](app.touchEvents.start, s.onTouchStart);
        s.container[action](app.touchEvents.move, s.onTouchMove);
        s.container[action](app.touchEvents.end, s.onTouchEnd);
        $(window)[action]('resize', s.onResize);

        // Next, Prev, Index
        if (s.options.nextButton) $(s.options.nextButton)[action]('click', s.onClickNext);
        if (s.options.prevButton) $(s.options.prevButton)[action]('click', s.onClickPrev);
        if (s.options.indexButton) $(s.options.indexButton)[action]('click', s.onClickIndex);
    };
    s.detachEvents = function () {
        s.attachEvents(true);
    };

    s.onResize = function () {
        s.updateSize();
    };

    var isTouched, isMoved, touchesStart = {}, touchesCurrent = {}, touchStartTime, isScrolling, animating = false, currentTranslate;
    var lastClickTime = Date.now(), clickTimeout, allowClick = true;

    s.onTouchStart = function (e) {
        isTouched = true;
        isMoved = false;
        isScrolling = undefined;
        touchesStart.x = touchesCurrent.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
        touchesStart.y = touchesCurrent.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
        touchStartTime = Date.now();
        s.width = s.container[0].offsetWidth;
        s.height = s.container[0].offsetHeight;
        e.preventDefault();
        allowClick = true;
        s.updateSize();
    };
    s.onTouchMove = function (e) {

        allowClick = false;
        if (!isTouched) return;
        if (e.targetTouches && e.targetTouches.length > 1) return;

        touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
        touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;

        if (typeof isScrolling === 'undefined') {
            isScrolling = !!(isScrolling || Math.abs(touchesCurrent.y - touchesStart.y) > Math.abs(touchesCurrent.x - touchesStart.x));
        }

        if ((isH && isScrolling) || (!isH && !isScrolling))  {
            isTouched = false;
            return;
        }

        e.preventDefault();
        e.stopPropagation();

        if (!isMoved) {
            if (animating) {
                currentTranslate = $.getTranslate(s.wrapper[0], isH ? 'x' : 'y');
                var slidesDiff = s.onSlideChangeEnd();
                currentTranslate += slidesDiff * (s.size + s.options.spaceBetween) / s.options.slidesPerView;
                s.wrapper.transition(0);
                var currTranslateX = isH ? currentTranslate : 0;
                var currTranslateY = isH ? 0 : currentTranslate;
                s.wrapper.transform('translate3d(' + currTranslateX + 'px,' + currTranslateY + 'px,0)');
            }
            else {
                currentTranslate = 0;
            }
        }

        isMoved = true;
        var diff = isH ? touchesCurrent.x - touchesStart.x  + currentTranslate : touchesCurrent.y - touchesStart.y  + currentTranslate;
        if ((diff > 0 && s.activeSlideIndex === 0)) diff = Math.pow(diff, 0.85);
        else if (diff < 0 && s.activeSlideIndex === s.slides.length - s.options.slidesPerView) diff = -Math.pow(-diff, 0.85);

        var translateX = isH ? diff : 0, translateY = isH ? 0 : diff;
        s.wrapper.transform('translate3d(' + translateX + 'px, ' + translateY + 'px,0)');
    };
    s.onTouchEnd = function (e) {
        var touchEndTime = Date.now();
        var timeDiff = touchEndTime - touchStartTime;
        if (allowClick) {
            if (timeDiff < 300 && (touchEndTime - lastClickTime) > 300) {
                if (clickTimeout) clearTimeout(clickTimeout);
                clickTimeout = setTimeout(function () {
                    if (s.options.paginationHide && s.paginationContainer) {
                        s.paginationContainer.toggleClass('slider-pagination-hidden');
                    }
                    if (s.options.onClick) s.options.onClick();
                }, 300);

            }
            if (timeDiff < 300 && (touchEndTime - lastClickTime) < 300 && s.options.zoom) {
                if (clickTimeout) clearTimeout(clickTimeout);
                if (s.options.onDoubleTap) {
                    s.options.onDoubleTap();
                }
            }
        }

        lastClickTime = Date.now();
        allowClick = true;

        if (!isTouched || !isMoved) {
            isTouched = isMoved = false;
            return;
        }
        isTouched = isMoved = false;
        var touchesDiff = isH ? touchesCurrent.x - touchesStart.x : touchesCurrent.y - touchesStart.y;

        if (touchesDiff === 0) {
            return;
        }
        var skipSlides = 1;
        var slideSize = s.size / s.options.slidesPerView;
        if (s.options.slidesPerView > 1) {
            skipSlides = Math.abs((Math.abs(touchesDiff) + slideSize / 2) / slideSize);
        }

        if (timeDiff > 300) {
            // Long touches
            if (touchesDiff <= -slideSize / 2) {
                s.slideTo(s.activeSlideIndex + Math.floor(skipSlides));
            }
            else if (touchesDiff > slideSize / 2) {
                s.slideTo(s.activeSlideIndex - Math.floor(skipSlides));
            }
            else {
                s.slideReset();
            }
        }
        else {
            if (Math.abs(touchesDiff) < 10) {
                s.slideReset();
            }
            else {
                if (touchesDiff < 0) {
                    s.slideTo(s.activeSlideIndex + Math.round(skipSlides));
                }
                else {
                    s.slideTo(s.activeSlideIndex - Math.round(skipSlides));
                }
            }

        }
    };

    s.slideTo = function (index, speed) {
        if (animating) return;
        if (typeof index === 'undefined') index = 0;
        if (index < 0) index = 0;
        if (index > s.slides.length - s.options.slidesPerView) index = s.slides.length - s.options.slidesPerView;
        var translate = (-index + s.activeSlideIndex) * (s.size + s.options.spaceBetween) / s.options.slidesPerView;

        if (typeof speed === 'undefined') speed = s.options.speed;
        s.previousSlideIndex = s.activeSlideIndex;
        s.activeSlideIndex = index;
        s.onSlideChangeStart();
        var translateX = isH ? translate : 0, translateY = isH ? 0 : translate;
        if (speed === 0) {
            s.onSlideChangeEnd();
        }
        else {
            animating = true;
            s.wrapper
                .transition(speed)
                .transform('translate3d(' + translateX + 'px,' + translateY + 'px,0)')
                .transitionEnd(function () {
                    s.onSlideChangeEnd();
                });
        }
    };
    s.updateClasses = function () {
        s.slides.removeClass(s.options.slideActiveClass + ' ' + s.options.slideNextClass + ' ' + s.options.slidePrevClass);
        var activeSlide = s.slides.eq(s.activeSlideIndex);
        activeSlide.addClass(s.options.slideActiveClass);
        activeSlide.next().addClass(s.options.slideNextClass);
        activeSlide.prev().addClass(s.options.slidePrevClass);

        if (s.bullets && s.bullets.length > 0) {
            s.bullets.removeClass(s.options.bulletActiveClass);
            s.bullets.eq(s.activeSlideIndex).addClass(s.options.bulletActiveClass);
        }
    };
    s.onSlideChangeStart = function () {
        s.updateClasses();
        if (s.options.onSlideChangeStart) s.options.onSlideChangeStart();
    };
    s.onSlideChangeEnd = function () {
        animating = false;
        s.wrapper.transition(0).transform('');
        if (isH) {
            s.wrapper.css({
                left: -100 * s.activeSlideIndex / s.options.slidesPerView + '%',
                marginLeft: -s.options.spaceBetween * s.activeSlideIndex / s.options.slidesPerView + 'px'
            });
        }
        else {
            s.wrapper.css({
                top: -100 * s.activeSlideIndex / s.options.slidesPerView + '%',
                marginTop: -s.options.spaceBetween * s.activeSlideIndex / s.options.slidesPerView + 'px'
            });
        }
        if (s.options.onSlideChangeEnd) s.options.onSlideChangeEnd();

        // Return slides diff
        return (s.activeSlideIndex - s.previousSlideIndex);
    };
    s.slideNext = function () {
        s.slideTo(s.activeSlideIndex + 1);
    };
    s.slidePrev = function () {
        s.slideTo(s.activeSlideIndex - 1);
    };
    s.slideReset = function () {
        s.slideTo(s.activeSlideIndex);
    };

    // Clicks
    s.onClickNext = function (e) {
        e.preventDefault();
        s.slideNext();
    };
    s.onClickPrev = function (e) {
        e.preventDefault();
        s.slidePrev();
    };
    s.onClickIndex = function (e) {
        e.preventDefault();
        s.slideTo($(this).index());
    };

    // init
    s.init = function () {
        s.updateSlides();
        s.updatePagination();
        s.updateSize();
        s.slideTo(s.options.initialSlide, 0);
        s.attachEvents();
    };

    // Destroy
    s.destroy = function () {
        s.detachEvents();
        if (s.options.onDestroy) s.options.onDestroy();
        s = undefined;
    };

    s.init();

    return s;
};
app.slider = function (container, options) {
    return new Slider(container, options);
};
app.initSlider = function (pageContainer) {
    var page = $(pageContainer);
    var sliders = page.find('.slider-init');
    if (sliders.length === 0) return;
    function destroySliderOnRemove(slider) {
        function destroySlider() {
            slider.destroy();
            page.off('pageBeforeRemove', destroySlider);
        }
        page.on('pageBeforeRemove', destroySlider);
    }
    for (var i = 0; i < sliders.length; i++) {
        var slider = sliders.eq(i);
        var options;
        if (slider.data('slider')) {
            options = JSON.parse(slider.data('slider'));
        }
        else {
            options = {
                initialSlide: parseInt(slider.data('initialSlide'), 10) || undefined,
                spaceBetween: parseInt(slider.data('spaceBetween'), 10) || undefined,
                speed: parseInt(slider.data('speed'), 10) || undefined,
                slidesPerView: slider.data('slidesPerView'),
                direction: slider.data('direction'),
                pagination: slider.data('pagination'),
                paginationHide: slider.data('paginationHide') && (slider.data('paginationHide') === 'true' ? true : false),
                slideClass: slider.data('slideClass'),
                slideActiveClass: slider.data('slideActiveClass'),
                slideNextClass: slider.data('slideNextClass'),
                slidePrevClass: slider.data('slidePrevClass'),
                wrapperClass: slider.data('wrapperClass'),
                bulletClass: slider.data('bulletClass'),
                bulletActiveClass: slider.data('bulletActiveClass'),
                nextButton: slider.data('nextButton'),
                prevButton: slider.data('prevButton'),
                indexButton: slider.data('indexButton')
            };
        }
        var _slider = app.slider(slider[0], options);
        slider[0].slider = _slider;
        destroySliderOnRemove(_slider);
    }
};
<commit_msg>Pass slider instance to callbacks<commit_after>/*======================================================
************   Slider   ************
======================================================*/
var Slider = function (container, options) {
    var defaults = {
        initialSlide: 0,
        spaceBetween: 0,
        speed: 300,
        slidesPerView: 1,
        direction: 'horizontal',
        pagination: '',
        paginationHide: true,
        slideClass: 'slider-slide',
        slideActiveClass: 'slider-slide-active',
        slideNextClass: 'slider-slide-next',
        slidePrevClass: 'slider-slide-prev',
        wrapperClass: 'slider-wrapper',
        bulletClass: 'slider-pagination-bullet',
        bulletActiveClass: 'slider-pagination-active'
    };
    options = options || {};
    for (var def in defaults) {
        if (typeof options[def] === 'undefined') {
            options[def] = defaults[def];
        }
    }

    var s = this;
    s.options = options;
    s.container = $(container);
    if (s.container.length === 0) return;

    if (s.options.direction === 'vertical') {
        s.container.addClass('slider-container-vertical');
    }

    s.wrapper = s.container.find('.' + s.options.wrapperClass);

    if (s.options.pagination) {
        s.paginationContainer = $(s.options.pagination);
    }

    s.activeSlideIndex = s.previousSlideIndex = s.options.initialSlide || 0;

    var isH = s.options.direction === 'horizontal';

    s.updateSlides = function () {
        s.slides = s.wrapper.children('.' + s.options.slideClass);

        if (s.options.spaceBetween !== 0) {
            if (isH) s.slides.css({marginRight: s.options.spaceBetween + 'px'});
            else s.slides.css({marginBottom: s.options.spaceBetween + 'px'});
        }
        if (s.options.slidesPerView > 1) {
            var sizeValue = '(100% - ' + (s.options.slidesPerView - 1) * options.spaceBetween + 'px)/' + s.options.slidesPerView;
            if (isH) {
                s.slides.css('width', '-webkit-calc(' + sizeValue + ')');
                s.slides.css('width', '-moz-calc(' + sizeValue + ')');
                s.slides.css('width', 'calc(' + sizeValue + ')');
            }
            else {
                s.slides.css('height', '-webkit-calc(' + sizeValue + ')');
                s.slides.css('height', '-moz-calc(' + sizeValue + ')');
                s.slides.css('height', 'calc(' + sizeValue + ')');
            }
        }

    };

    s.updatePagination = function () {
        if (s.paginationContainer && s.paginationContainer.length > 0) {
            var bulletsHTML = '';
            for (var i = 0; i < s.slides.length - s.options.slidesPerView + 1; i++) {
                bulletsHTML += '';
            }
            s.paginationContainer.html(bulletsHTML);
            s.bullets = s.paginationContainer.find('.' + s.options.bulletClass);
        }
    };

    s.updateSize = function () {
        s.width = s.container.width();
        s.height = s.container.height();
        s.size = isH ? s.width : s.height;
    };

    s.attachEvents = function (detach) {
        var action = detach ? 'off' : 'on';
        // Slide between photos
        s.container[action](app.touchEvents.start, s.onTouchStart);
        s.container[action](app.touchEvents.move, s.onTouchMove);
        s.container[action](app.touchEvents.end, s.onTouchEnd);
        $(window)[action]('resize', s.onResize);

        // Next, Prev, Index
        if (s.options.nextButton) $(s.options.nextButton)[action]('click', s.onClickNext);
        if (s.options.prevButton) $(s.options.prevButton)[action]('click', s.onClickPrev);
        if (s.options.indexButton) $(s.options.indexButton)[action]('click', s.onClickIndex);
    };
    s.detachEvents = function () {
        s.attachEvents(true);
    };

    s.onResize = function () {
        s.updateSize();
    };

    var isTouched, isMoved, touchesStart = {}, touchesCurrent = {}, touchStartTime, isScrolling, animating = false, currentTranslate;
    var lastClickTime = Date.now(), clickTimeout;
    s.allowClick = true;

    s.onTouchStart = function (e) {
        isTouched = true;
        isMoved = false;
        isScrolling = undefined;
        touchesStart.x = touchesCurrent.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
        touchesStart.y = touchesCurrent.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
        touchStartTime = Date.now();
        s.width = s.container[0].offsetWidth;
        s.height = s.container[0].offsetHeight;
        e.preventDefault();
        s.allowClick = true;
        s.updateSize();
    };
    s.onTouchMove = function (e) {

        s.allowClick = false;
        if (!isTouched) return;
        if (e.targetTouches && e.targetTouches.length > 1) return;

        touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
        touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;

        if (typeof isScrolling === 'undefined') {
            isScrolling = !!(isScrolling || Math.abs(touchesCurrent.y - touchesStart.y) > Math.abs(touchesCurrent.x - touchesStart.x));
        }

        if ((isH && isScrolling) || (!isH && !isScrolling))  {
            isTouched = false;
            return;
        }

        e.preventDefault();
        e.stopPropagation();

        if (!isMoved) {
            if (animating) {
                currentTranslate = $.getTranslate(s.wrapper[0], isH ? 'x' : 'y');
                var slidesDiff = s.onSlideChangeEnd();
                currentTranslate += slidesDiff * (s.size + s.options.spaceBetween) / s.options.slidesPerView;
                s.wrapper.transition(0);
                var currTranslateX = isH ? currentTranslate : 0;
                var currTranslateY = isH ? 0 : currentTranslate;
                s.wrapper.transform('translate3d(' + currTranslateX + 'px,' + currTranslateY + 'px,0)');
            }
            else {
                currentTranslate = 0;
            }
        }

        isMoved = true;
        var diff = isH ? touchesCurrent.x - touchesStart.x  + currentTranslate : touchesCurrent.y - touchesStart.y  + currentTranslate;
        if ((diff > 0 && s.activeSlideIndex === 0)) diff = Math.pow(diff, 0.85);
        else if (diff < 0 && s.activeSlideIndex === s.slides.length - s.options.slidesPerView) diff = -Math.pow(-diff, 0.85);

        var translateX = isH ? diff : 0, translateY = isH ? 0 : diff;
        s.wrapper.transform('translate3d(' + translateX + 'px, ' + translateY + 'px,0)');
    };
    s.onTouchEnd = function (e) {
        var touchEndTime = Date.now();
        var timeDiff = touchEndTime - touchStartTime;
        if (s.allowClick) {
            if (timeDiff < 300 && (touchEndTime - lastClickTime) > 300) {
                if (clickTimeout) clearTimeout(clickTimeout);
                clickTimeout = setTimeout(function () {
                    if (s.options.paginationHide && s.paginationContainer) {
                        s.paginationContainer.toggleClass('slider-pagination-hidden');
                    }
                    if (s.options.onClick) s.options.onClick(e);
                }, 300);

            }
            if (timeDiff < 300 && (touchEndTime - lastClickTime) < 300) {
                if (clickTimeout) clearTimeout(clickTimeout);
                if (s.options.onDoubleTap) {
                    s.options.onDoubleTap(e);
                }
            }
        }

        lastClickTime = Date.now();
        s.allowClick = true;

        if (!isTouched || !isMoved) {
            isTouched = isMoved = false;
            return;
        }
        isTouched = isMoved = false;
        var touchesDiff = isH ? touchesCurrent.x - touchesStart.x : touchesCurrent.y - touchesStart.y;

        if (touchesDiff === 0) {
            return;
        }
        var skipSlides = 1;
        var slideSize = s.size / s.options.slidesPerView;
        if (s.options.slidesPerView > 1) {
            skipSlides = Math.abs((Math.abs(touchesDiff) + slideSize / 2) / slideSize);
        }

        if (timeDiff > 300) {
            // Long touches
            if (touchesDiff <= -slideSize / 2) {
                s.slideTo(s.activeSlideIndex + Math.floor(skipSlides));
            }
            else if (touchesDiff > slideSize / 2) {
                s.slideTo(s.activeSlideIndex - Math.floor(skipSlides));
            }
            else {
                s.slideReset();
            }
        }
        else {
            if (Math.abs(touchesDiff) < 10) {
                s.slideReset();
            }
            else {
                if (touchesDiff < 0) {
                    s.slideTo(s.activeSlideIndex + Math.round(skipSlides));
                }
                else {
                    s.slideTo(s.activeSlideIndex - Math.round(skipSlides));
                }
            }

        }
    };

    s.slideTo = function (index, speed) {
        if (animating) return;
        if (typeof index === 'undefined') index = 0;
        if (index < 0) index = 0;
        if (index > s.slides.length - s.options.slidesPerView) index = s.slides.length - s.options.slidesPerView;
        var translate = (-index + s.activeSlideIndex) * (s.size + s.options.spaceBetween) / s.options.slidesPerView;

        if (typeof speed === 'undefined') speed = s.options.speed;
        s.previousSlideIndex = s.activeSlideIndex;
        s.activeSlideIndex = index;
        s.onSlideChangeStart();
        var translateX = isH ? translate : 0, translateY = isH ? 0 : translate;
        if (speed === 0) {
            s.onSlideChangeEnd();
        }
        else {
            animating = true;
            s.wrapper
                .transition(speed)
                .transform('translate3d(' + translateX + 'px,' + translateY + 'px,0)')
                .transitionEnd(function () {
                    s.onSlideChangeEnd();
                });
        }
    };
    s.updateClasses = function () {
        s.slides.removeClass(s.options.slideActiveClass + ' ' + s.options.slideNextClass + ' ' + s.options.slidePrevClass);
        var activeSlide = s.slides.eq(s.activeSlideIndex);
        activeSlide.addClass(s.options.slideActiveClass);
        activeSlide.next().addClass(s.options.slideNextClass);
        activeSlide.prev().addClass(s.options.slidePrevClass);

        if (s.bullets && s.bullets.length > 0) {
            s.bullets.removeClass(s.options.bulletActiveClass);
            s.bullets.eq(s.activeSlideIndex).addClass(s.options.bulletActiveClass);
        }
    };
    s.onSlideChangeStart = function () {
        s.updateClasses();
        if (s.options.onSlideChangeStart) s.options.onSlideChangeStart(s);
    };
    s.onSlideChangeEnd = function () {
        animating = false;
        s.wrapper.transition(0).transform('');
        if (isH) {
            s.wrapper.css({
                left: -100 * s.activeSlideIndex / s.options.slidesPerView + '%',
                marginLeft: -s.options.spaceBetween * s.activeSlideIndex / s.options.slidesPerView + 'px'
            });
        }
        else {
            s.wrapper.css({
                top: -100 * s.activeSlideIndex / s.options.slidesPerView + '%',
                marginTop: -s.options.spaceBetween * s.activeSlideIndex / s.options.slidesPerView + 'px'
            });
        }
        if (s.options.onSlideChangeEnd) s.options.onSlideChangeEnd(s);

        // Return slides diff
        return (s.activeSlideIndex - s.previousSlideIndex);
    };
    s.slideNext = function () {
        s.slideTo(s.activeSlideIndex + 1);
    };
    s.slidePrev = function () {
        s.slideTo(s.activeSlideIndex - 1);
    };
    s.slideReset = function () {
        s.slideTo(s.activeSlideIndex);
    };

    // Clicks
    s.onClickNext = function (e) {
        e.preventDefault();
        s.slideNext();
    };
    s.onClickPrev = function (e) {
        e.preventDefault();
        s.slidePrev();
    };
    s.onClickIndex = function (e) {
        e.preventDefault();
        s.slideTo($(this).index());
    };

    // init
    s.init = function () {
        s.updateSlides();
        s.updatePagination();
        s.updateSize();
        s.slideTo(s.options.initialSlide, 0);
        s.attachEvents();
    };

    // Destroy
    s.destroy = function () {
        s.detachEvents();
        if (s.options.onDestroy) s.options.onDestroy();
        s = undefined;
    };

    s.init();

    return s;
};
app.slider = function (container, options) {
    return new Slider(container, options);
};
app.initSlider = function (pageContainer) {
    var page = $(pageContainer);
    var sliders = page.find('.slider-init');
    if (sliders.length === 0) return;
    function destroySliderOnRemove(slider) {
        function destroySlider() {
            slider.destroy();
            page.off('pageBeforeRemove', destroySlider);
        }
        page.on('pageBeforeRemove', destroySlider);
    }
    for (var i = 0; i < sliders.length; i++) {
        var slider = sliders.eq(i);
        var options;
        if (slider.data('slider')) {
            options = JSON.parse(slider.data('slider'));
        }
        else {
            options = {
                initialSlide: parseInt(slider.data('initialSlide'), 10) || undefined,
                spaceBetween: parseInt(slider.data('spaceBetween'), 10) || undefined,
                speed: parseInt(slider.data('speed'), 10) || undefined,
                slidesPerView: slider.data('slidesPerView'),
                direction: slider.data('direction'),
                pagination: slider.data('pagination'),
                paginationHide: slider.data('paginationHide') && (slider.data('paginationHide') === 'true' ? true : false),
                slideClass: slider.data('slideClass'),
                slideActiveClass: slider.data('slideActiveClass'),
                slideNextClass: slider.data('slideNextClass'),
                slidePrevClass: slider.data('slidePrevClass'),
                wrapperClass: slider.data('wrapperClass'),
                bulletClass: slider.data('bulletClass'),
                bulletActiveClass: slider.data('bulletActiveClass'),
                nextButton: slider.data('nextButton'),
                prevButton: slider.data('prevButton'),
                indexButton: slider.data('indexButton')
            };
        }
        var _slider = app.slider(slider[0], options);
        slider[0].slider = _slider;
        destroySliderOnRemove(_slider);
    }
};
<|endoftext|>


<commit_before>this.CAL = this.CAL || {};

this.CAL.lang = this.CAL.lang || {};

(function(undefined) {
	"use strict";

	var buttonCodeToName = {1:"Left",2:"Middle",3:"Right"};
	var buttonNameToCode = {"Left":1,"Middle":2,"Right":3};

	var Mouse = function(element) {

		var down = this._down = {};

		this._listeners = {};
		this._globalListeners = [];

		this._pressListeners = {};
		this._globalPressListeners = [];

		var globalCallback = function(mouse, evt) {
			for (var i = 0; i < mouse._globalListeners.length; ++i) {
				var c = mouse._globalListeners[i];
				c.callback.call(c.scope, evt);
			}
		}

		var pressCallback = function(keyboard, evt) {
			var arr = keyboard._pressListeners[evt.which];
			if (arr) {
				for (var i = 0; i < arr.length; ++i) {
					var c = arr[i];
					c.callback.call(c.scope, evt);
				}
			}
		}

		var globalPressCallback = function(mouse, evt) {
			for (var i = 0; i < mouse._globalPressListeners.length; ++i) {
				var c = mouse._globalPressListeners[i];
				c.callback.call(c.scope, evt);
			}
		}

		var _this = this;

		var mousedownListener = function(evt) {
			down[evt.which] = true;
			globalCallback(_this, evt);
		}

		var mouseupListener = function(evt) {
			if (typeof down[evt.which] === "undefined") {
				return;
			}
			delete down[evt.which];
			globalCallback(_this, evt);
			pressCallback(_this, evt);
			globalPressCallback(_this, evt);
		}

		element.addEventListener("mousedown", mousedownListener);
		element.addEventListener("mouseup", mouseupListener);
	}

	var p = Mouse.prototype = new CAL.lang.IUpdateableObject();

	var s = Mouse;

	p.pause = function() {
		this._paused = true;
	}

	p.resume = function() {
		delete this._paused;
	}

	p.addEventListener = function(buttonCode, callback, scope) {
		var toPush = {callback: callback, scope: scope || callback};
		if (buttonCode === -1) {
			this._globalListeners.push(toPush);
			return;
		}
		var listeners = this._listeners;
		if (!listeners[buttonCode]) {
			listeners[buttonCode] = [toPush];
		} else {
			listeners[buttonCode].push(toPush);
		}
	}

	p.addPressListener = function(buttonCode, callback, scope) {
		var toPush = {callback: callback, scope: scope || callback};
		if (buttonCode === -1) {
			this._globalPressListeners.push(toPush);
			return;
		}
		var pressListeners = this._pressListeners;
		if (!pressListeners[buttonCode]) {
			pressListeners[buttonCode] = [toPush];
		} else {
			pressListeners[buttonCode].push(toPush);
		}
	}

	p.removeEventListener = function(buttonCode, callbackObj) {
		if (buttonCode === -1) {
			var l = this._globalListeners;
			for (var i = 0; i < l.length; ++i) {
				if (callbackObj === l[i]) {
					delete this._globalListeners[i];
				}
			}
		}
		var listeners = this._listeners;
		var arr = listeners[buttonCode];
		if (!arr) {
			return;
		}
		for (var i = 0; i < arr.length; ++i) {
			if (arr[i] === callbackObj) {
				delete arr[i];
				if (arr.length = 0) {
					delete this._listeners[buttonCode];
				}
				return;
			}
		}
	}

	p.removePressListener = function(buttonCode, callbackObj) {
		if (buttonCode === -1) {
			var l = this._globalPressListeners;
			for (var i = 0; i < l.length; ++i) {
				if (callbackObj === l[i]) {
					delete this._globalPressListeners[i];
				}
			}
		}
		var listeners = this._pressListeners;
		var arr = listeners[buttonCode];
		if (!arr) {
			return;
		}
		for (var i = 0; i < arr.length; ++i) {
			if (arr[i] === callbackObj) {
				delete arr[i];
				if (arr.length = 0) {
					delete this._pressListeners[buttonCode];
				}
				return;
			}
		}
	}

	p.update = function(params) {
		if (this._paused) {
			return;
		}
		var listeners = this._listeners;
		var down = this._down;
		for (var buttonCode in down) {
			var arr = listeners[buttonCode];
			if (!arr) {
				continue;
			}
			for (var i = 0; i < arr.length; ++i) {
				var c = arr[i];
				c.callback.call(c.scope, buttonCode);
			}
		}
	}

	p.isDown = function(buttonCodeOrName) {
		if (!(typeof buttonCodeOrName === "number")) {
			buttonCodeOrName = buttonNameToCode[buttonCodeOrName.trim()];
		}
		return typeof buttonCodeOrName === "undefined" ? false : (this._down[buttonCodeOrName] ? true : false);
	}

	p.getButtonName = s.getButtonName = function(buttonCode) {
		return buttonCodeToName[buttonCode];
	}

	p.getButtonCode = s.getButtonCode = function(name) {
		return buttonNameToCode[name.trim()];
	}

	CAL.lang.Mouse = Mouse;

})();<commit_msg>Barely added mouse support<commit_after>this.CAL = this.CAL || {};

this.CAL.lang = this.CAL.lang || {};

(function(undefined) {
	"use strict";

	var buttonCodeToName = {1:"Left",2:"Middle",3:"Right"};
	var buttonNameToCode = {"Left":1,"Middle":2,"Right":3};

	var Mouse = function(element, attachTouch) {

		var down = this._down = {};

		this._listeners = {};
		this._globalListeners = [];

		this._pressListeners = {};
		this._globalPressListeners = [];

		var globalCallback = function(mouse, evt) {
			for (var i = 0; i < mouse._globalListeners.length; ++i) {
				var c = mouse._globalListeners[i];
				c.callback.call(c.scope, evt);
			}
		}

		var pressCallback = function(keyboard, evt) {
			var arr = keyboard._pressListeners[evt.which];
			if (arr) {
				for (var i = 0; i < arr.length; ++i) {
					var c = arr[i];
					c.callback.call(c.scope, evt);
				}
			}
		}

		var globalPressCallback = function(mouse, evt) {
			for (var i = 0; i < mouse._globalPressListeners.length; ++i) {
				var c = mouse._globalPressListeners[i];
				c.callback.call(c.scope, evt);
			}
		}

		var _this = this;

		var mousedownListener = function(evt) {
			down[evt.which] = true;
			globalCallback(_this, evt);
		}

		var mouseupListener = function(evt) {
			if (typeof down[evt.which] === "undefined") {
				return;
			}
			delete down[evt.which];
			globalCallback(_this, evt);
			pressCallback(_this, evt);
			globalPressCallback(_this, evt);
		}

		if (attachTouch) {

		}

		element.addEventListener("mousedown", mousedownListener);
		element.addEventListener("mouseup", mouseupListener);
	}

	var p = Mouse.prototype = new CAL.lang.IUpdateableObject();

	var s = Mouse;

	p.pause = function() {
		this._paused = true;
	}

	p.resume = function() {
		delete this._paused;
	}

	p.addEventListener = function(buttonCode, callback, scope) {
		var toPush = {callback: callback, scope: scope || callback};
		if (buttonCode === -1) {
			this._globalListeners.push(toPush);
			return;
		}
		var listeners = this._listeners;
		if (!listeners[buttonCode]) {
			listeners[buttonCode] = [toPush];
		} else {
			listeners[buttonCode].push(toPush);
		}
	}

	p.addPressListener = function(buttonCode, callback, scope) {
		var toPush = {callback: callback, scope: scope || callback};
		if (buttonCode === -1) {
			this._globalPressListeners.push(toPush);
			return;
		}
		var pressListeners = this._pressListeners;
		if (!pressListeners[buttonCode]) {
			pressListeners[buttonCode] = [toPush];
		} else {
			pressListeners[buttonCode].push(toPush);
		}
	}

	p.removeEventListener = function(buttonCode, callbackObj) {
		if (buttonCode === -1) {
			var l = this._globalListeners;
			for (var i = 0; i < l.length; ++i) {
				if (callbackObj === l[i]) {
					delete this._globalListeners[i];
				}
			}
		}
		var listeners = this._listeners;
		var arr = listeners[buttonCode];
		if (!arr) {
			return;
		}
		for (var i = 0; i < arr.length; ++i) {
			if (arr[i] === callbackObj) {
				delete arr[i];
				if (arr.length = 0) {
					delete this._listeners[buttonCode];
				}
				return;
			}
		}
	}

	p.removePressListener = function(buttonCode, callbackObj) {
		if (buttonCode === -1) {
			var l = this._globalPressListeners;
			for (var i = 0; i < l.length; ++i) {
				if (callbackObj === l[i]) {
					delete this._globalPressListeners[i];
				}
			}
		}
		var listeners = this._pressListeners;
		var arr = listeners[buttonCode];
		if (!arr) {
			return;
		}
		for (var i = 0; i < arr.length; ++i) {
			if (arr[i] === callbackObj) {
				delete arr[i];
				if (arr.length = 0) {
					delete this._pressListeners[buttonCode];
				}
				return;
			}
		}
	}

	p.update = function(params) {
		if (this._paused) {
			return;
		}
		var listeners = this._listeners;
		var down = this._down;
		for (var buttonCode in down) {
			var arr = listeners[buttonCode];
			if (!arr) {
				continue;
			}
			for (var i = 0; i < arr.length; ++i) {
				var c = arr[i];
				c.callback.call(c.scope, buttonCode);
			}
		}
	}

	p.isDown = function(buttonCodeOrName) {
		if (!(typeof buttonCodeOrName === "number")) {
			buttonCodeOrName = buttonNameToCode[buttonCodeOrName.trim()];
		}
		return typeof buttonCodeOrName === "undefined" ? false : (this._down[buttonCodeOrName] ? true : false);
	}

	p.getButtonName = s.getButtonName = function(buttonCode) {
		return buttonCodeToName[buttonCode];
	}

	p.getButtonCode = s.getButtonCode = function(name) {
		return buttonNameToCode[name.trim()];
	}

	CAL.lang.Mouse = Mouse;

})();<|endoftext|>


<commit_before>"use strict";

var sjs = require("scraperjs");
var fs = require("fs");
var scrapers = require("../scrapers/");
var async = require("async");

var BASE_URL = "https://en.wikipedia.org";

var _ = require("lodash");

var Ajv = require("ajv");
var ajv = Ajv();

var chalk = require("chalk");

function getRoutes(airline, callback) {
  var url = airline.url || BASE_URL + airline.destinationsLink;

  if (process.env.NODE_ENV !== "test") {
    console.log("Getting routes for %s from %s", airline.name, url); // eslint-disable-line no-console
  }
  sjs.StaticScraper.create(url)
    .catch(function (err, utils) {
      if (err) {
        if (process.env.NODE_ENV !== "test") {
          console.log(chalk.red("\nerror from %s is %s, %s \n"), airline.name, err, url); // eslint-disable-line no-console
        }
        callback(err, utils);
      }
    })
    .scrape(scrapers[airline.scraper] || scrapers["default"])
    .then(function (data) {
      airline.routes = data;
      writeJson(null, airline, callback);
    });
}

function getFilename(airline) {
  var defaultRoute = require("../schema/scraper.default.schema.json");
  var validateDefaultRoute = ajv.compile(defaultRoute);
  var validDefaultRoute = validateDefaultRoute(airline.routes);

  // todo: test this function
  if (validDefaultRoute) {
    airline.fileName = "./data/routes_" + airline.name + ".json";
  } else {
    airline.fileName = "./data/error_" + airline.name + ".json";
  }
  return airline;
}

var writeJson = function (err, airline, callback) {
  if (err) {
    throw err;
  }
  airline = getFilename(airline);
  var errorRegEx = /error/;

  fs.writeFile(airline.fileName,
    JSON.stringify(airline.routes, null, 2),
    function (err) {
      if (err) {
        throw err;
      }
      if (process.env.NODE_ENV !== "test") {
        if (errorRegEx.test(airline.fileName)) {
          console.log(chalk.red("Saved %s"), airline.fileName); // eslint-disable-line no-console
        } else {
          console.log(chalk.green("Saved %s"), airline.fileName); // eslint-disable-line no-console
        }
      }
      callback(null, airline);
    }
  );
};

function getAllRoutes(airlines, callback) {

  async.mapLimit(_.clone(airlines, true), 20, function (airline, callback) {
    async.retry(5, function (callback) {
      getRoutes(airline, callback);
    }, callback);

  }, function (err, airlines) {
    if (err) {
      console.log(chalk.red.bgWhite("\ngetAllRoutes found an error %s"), err);// eslint-disable-line no-console
    }
    callback(err, airlines);

  });
}

module.exports.getRoutes = getRoutes;
module.exports.getAllRoutes = getAllRoutes;

// getAllRoutes([{
//   "name": "Aegean Airlines",
//   "destinationsLink": "/wiki/Aegean_Airlines_destinations",
//   "scraper": "table"
// }, {
//   "name": "Aer Lingus",
//   "destinationsLink": "/wiki/Aer_Lingus_destinations",
//   "scraper": "table"
// }], function (err) {
//   if (err) {throw err;}
//   console.log("files saved");
// });

<commit_msg>added final log message with total routes and errors<commit_after>"use strict";

var sjs = require("scraperjs");
var fs = require("fs");
var scrapers = require("../scrapers/");
var async = require("async");

var BASE_URL = "https://en.wikipedia.org";

var _ = require("lodash");

var Ajv = require("ajv");
var ajv = Ajv();

var chalk = require("chalk");

function getRoutes(airline, callback) {
  var url = airline.url || BASE_URL + airline.destinationsLink;

  if (process.env.NODE_ENV !== "test") {
    console.log("Getting routes for %s from %s", airline.name, url); // eslint-disable-line no-console
  }
  sjs.StaticScraper.create(url)
    .catch(function (err, utils) {
      if (err) {
        if (process.env.NODE_ENV !== "test") {
          console.log(chalk.red("\nerror from %s is %s, %s \n"), airline.name, err, url); // eslint-disable-line no-console
        }
        callback(err, utils);
      }
    })
    .scrape(scrapers[airline.scraper] || scrapers["default"])
    .then(function (data) {
      airline.routes = data;
      writeJson(null, airline, callback);
    });
}
var errors = 0,
  routes = 0;

// todo: test this function
function getFilename(airline) {
  var defaultRoute = require("../schema/scraper.default.schema.json");
  var validateDefaultRoute = ajv.compile(defaultRoute);
  var validDefaultRoute = validateDefaultRoute(airline.routes);

  if (validDefaultRoute) {
    routes += 1;
    airline.fileName = "./data/routes_" + airline.name + ".json";
  } else {
    // console.log(validateDefaultRoute, _.get(validateDefaultRoute, "errors[0].message"));
    errors += 1;
    airline.fileName = "./data/error_" + airline.name + ".json";
  }
  return airline;
}

var writeJson = function (err, airline, callback) {
  if (err) {
    throw err;
  }
  airline = getFilename(airline);
  var errorRegEx = /error/;

  fs.writeFile(airline.fileName,
    JSON.stringify(airline.routes, null, 2),
    function (err) {
      if (err) {
        throw err;
      }
      if (process.env.NODE_ENV !== "test") {
        if (errorRegEx.test(airline.fileName)) {
          console.log(chalk.red("Saved %s"), airline.fileName); // eslint-disable-line no-console
        } else {
          console.log(chalk.green("Saved %s"), airline.fileName); // eslint-disable-line no-console
        }
      }
      callback(null, airline);
    }
  );
};

function getAllRoutes(airlines, callback) {

  async.mapLimit(_.clone(airlines, true), 20, function (airline, callback) {
    async.retry(5, function (callback) {
      getRoutes(airline, callback);
    }, callback);

  }, function (err, airlines) {
    if (err) {
      console.log(chalk.red.bgWhite("\ngetAllRoutes found an error %s"), err); // eslint-disable-line no-console
    }
    console.log("You got %s routes and %s errors", routes, errors);
    callback(err, airlines);

  });
}

module.exports.getRoutes = getRoutes;
module.exports.getAllRoutes = getAllRoutes;

// getAllRoutes([{
//   "name": "Aero California",
//   "destinationsLink": "/wiki/Aero_California_destinations",
//   "scraper": "default"
// }, {
//   "name": "Aer Lingus",
//   "destinationsLink": "/wiki/Aer_Lingus_destinations",
//   "scraper": "table"
// }], function (err) {
//   if (err) {
//     throw err;
//   }
//   console.log("files saved");
// });
<|endoftext|>


<commit_before>module.exports = AkeraApi;

var api_router = require('./api-router.js');

function AkeraApi(akeraWebInstance) {
    if (akeraWebInstance && akeraWebInstance.app) {
        this.akeraWebInstance = akeraWebInstance;
    } else {
        throw new Error('Invalid akera web application instance');
    }
}

AkeraApi.prototype.init = function(brokerName, route) {
    var app = this.akeraWebInstance.app;

    route = (route === '/' ? '/rest' : route) || '/rest';

    app.use(route + (brokerName ? '/' + brokerName : '/:broker'), new api_router(brokerName || null, this.akeraWebInstance));
    this.log('info', 'Akera API Service enabled for all brokers.');
};

AkeraApi.prototype.log = function(level, message) {
    try {
        this.akeraWebInstance.log(level, message);
    } catch (err) {}
};
<commit_msg>account for configurable rest services route<commit_after>module.exports = AkeraApi;

var api_router = require('./api-router.js');

function AkeraApi(akeraWebInstance) {
    if (akeraWebInstance && akeraWebInstance.app) {
        this.akeraWebInstance = akeraWebInstance;
    } else {
        throw new Error('Invalid akera web application instance');
    }
}

AkeraApi.prototype.init = function(brokerName, route) {
    var app = this.akeraWebInstance.app;

    route = (route === '/' ? '/rest' : route) || this.akeraWebInstance.akeraServices.restRoute || '/rest';

    app.use(route + (brokerName ? '/' + brokerName : '/:broker'), new api_router(brokerName || null, this.akeraWebInstance));
    this.log('info', 'Akera API Service enabled for all brokers.');
};

AkeraApi.prototype.log = function(level, message) {
    try {
        this.akeraWebInstance.log(level, message);
    } catch (err) {}
};
<|endoftext|>


<commit_before>var child_process = require('child_process'),
    spawn = child_process.spawn,
    repository = require('./repository'),
    logger = require('./logger'),
    utils = require('./utils'),
    path = require('path');

/**
 * Reports tar --version output
 */

exports.version = function (callback) {
    child_process.exec('tar --version', function (err, stdout, stderr) {
        if (err) {
            return callback(err);
        }
        if (stderr) {
            return callback(new Error('Error getting tar version\n' + stderr));
        }
        callback(null, stdout.toString());
    });
};

/**
 * Checks if using BSD tar
 */

exports.isBSD = function (callback) {
    exports.version(function (err, output) {
        if (err) {
            return callback(err);
        }
        callback(null, output.indexOf('bsdtar') !== -1);
    });
};

exports.create = function (outfile, dir, callback) {
    exports.isBSD(function (err, is_bsd) {
        if (err) {
            return callback(err);
        }
        var tmpfile = repository.TMP_DIR +
            path.basename(outfile) + '-' + new Date().getTime();

        var ignorefile = path.join(dir, '.kansoignore');
        path.exists(ignorefile, function (ignores) {
            var outpath = utils.abspath(tmpfile, process.cwd());
            var args = [
                '-czvf', outpath,
                '--transform', 's/^\./package/',
                '--exclude', '.kansorc',
                '--exclude', '.git',
                '--exclude', '.gitignore',
                '--exclude', '.gitmodules',
                '.'
            ];
            if (is_bsd) {
                // change --transform command to -s
                args[2] = '-s';
                args[3] = '/^\./package/';
            }
            if (ignores) {
                args = args.concat(['-X', ignorefile]);
            }
            tar = spawn('tar', args, {cwd: dir});

            var err_messages = '';

            tar.stdout.on('data', function (data) {
                data.toString().split('\n').forEach(function (p) {
                    p = p.replace(/^\.\//, '');
                    if (p) {
                        logger.info('packing', p);
                    }
                });
            });
            tar.stderr.on('data', function (data) {
                err_messages += data;
            });

            tar.on('exit', function (code) {
                if (code !== 0) {
                    return callback(new Error(err_messages));
                }
                utils.mv(tmpfile, outfile, callback);
            });
        });
    });
};

exports.extract = function (file, callback) {
    logger.info('extracting', path.basename(file));

    var tarfile = utils.abspath(file, process.cwd());
    tar = spawn('tar', ['-xzvf', tarfile], {cwd: path.dirname(tarfile)});

    var err_messages = '';

    tar.stdout.on('data', function (data) {
        data.toString().split('\n').forEach(function (p) {
            p = p.replace(/^\.\//, '');
            if (p) {
                logger.debug('extracting', p);
            }
        });
    });
    tar.stderr.on('data', function (data) {
        err_messages += data;
    });

    tar.on('exit', function (code) {
        if (code !== 0) {
            return callback(new Error(err_messages));
        }
        return callback();
    });
};
<commit_msg>fix transform options for GNU tar, so it doesn't break symlinks in handlebars package<commit_after>var child_process = require('child_process'),
    spawn = child_process.spawn,
    repository = require('./repository'),
    logger = require('./logger'),
    utils = require('./utils'),
    path = require('path');

/**
 * Reports tar --version output
 */

exports.version = function (callback) {
    child_process.exec('tar --version', function (err, stdout, stderr) {
        if (err) {
            return callback(err);
        }
        if (stderr) {
            return callback(new Error('Error getting tar version\n' + stderr));
        }
        callback(null, stdout.toString());
    });
};

/**
 * Checks if using BSD tar
 */

exports.isBSD = function (callback) {
    exports.version(function (err, output) {
        if (err) {
            return callback(err);
        }
        callback(null, output.indexOf('bsdtar') !== -1);
    });
};

exports.create = function (outfile, dir, callback) {
    exports.isBSD(function (err, is_bsd) {
        if (err) {
            return callback(err);
        }
        var tmpfile = repository.TMP_DIR +
            path.basename(outfile) + '-' + new Date().getTime();

        var ignorefile = path.join(dir, '.kansoignore');
        path.exists(ignorefile, function (ignores) {
            var outpath = utils.abspath(tmpfile, process.cwd());
            var args = [
                '-czvf', outpath,
                '--transform', 'flags=rSH;s/^\./package/',
                '--exclude', '.kansorc',
                '--exclude', '.git',
                '--exclude', '.gitignore',
                '--exclude', '.gitmodules',
                '.'
            ];
            if (is_bsd) {
                // change --transform command to -s
                args[2] = '-s';
                args[3] = '/^\./package/';
            }
            if (ignores) {
                args = args.concat(['-X', ignorefile]);
            }
            tar = spawn('tar', args, {cwd: dir});

            var err_messages = '';

            tar.stdout.on('data', function (data) {
                data.toString().split('\n').forEach(function (p) {
                    p = p.replace(/^\.\//, '');
                    if (p) {
                        logger.info('packing', p);
                    }
                });
            });
            tar.stderr.on('data', function (data) {
                err_messages += data;
            });

            tar.on('exit', function (code) {
                if (code !== 0) {
                    return callback(new Error(err_messages));
                }
                utils.mv(tmpfile, outfile, callback);
            });
        });
    });
};

exports.extract = function (file, callback) {
    logger.info('extracting', path.basename(file));

    var tarfile = utils.abspath(file, process.cwd());
    tar = spawn('tar', ['-xzvf', tarfile], {cwd: path.dirname(tarfile)});

    var err_messages = '';

    tar.stdout.on('data', function (data) {
        data.toString().split('\n').forEach(function (p) {
            p = p.replace(/^\.\//, '');
            if (p) {
                logger.debug('extracting', p);
            }
        });
    });
    tar.stderr.on('data', function (data) {
        err_messages += data;
    });

    tar.on('exit', function (code) {
        if (code !== 0) {
            return callback(new Error(err_messages));
        }
        return callback();
    });
};
<|endoftext|>


<commit_before>var LS = {
  // *** DATA ***
  /*
    decode / encode  data to URL hash

    hash is split into the following sections delimited by '/'
    1. axiom
      example: F[A]
      chars: [A-Z]\[\]
    2. rules
      example: F:F+[F-FF]F+
      chars: [A-Z]\[\]\:\+\-
    3. instructions - delimited by ';' then split into parameters: distance(d), angle(d), push(u)/pop(o)
      example: F,d10,a25,u;A,d5,a10
      chars: [0-9],\.up
    4. iterations - max number of iterations
      example: 3
      chars: [0-9]
    5. starting drawing values - delimited by ',' : x, y, angle, iteration to display
      example: x500,y300,a10
      chars: [0-9]xyamwh
  */
  decodeHash: function () {
    var dataStrings = window.location.hash.substr(1).split('/');
    var axiomString = dataStrings[0];
    var rulesString = dataStrings[1];
    var instructionsString = dataStrings[2];
    var iterations = dataStrings[3];
    var startString = dataStrings[4];
    return {
      axiom: axiomString.split(''),
      rules: this.decodeRules(rulesString),
      instructions: this.decodeInstructions(instructionsString),
      iterations: iterations,
      start: this.decodeStart(startString),
      needsReparse: true,
      needsRedraw: true
    };
  },
  decodeRules: function (rulesString) {
    var rulesList = rulesString.split(',');
    return rulesList.reduce(function (rules, ruleString) {
      var splitRule = ruleString.split(':');
      var predecessor = splitRule[0];
      var successor = splitRule[1].split('');
      rules[predecessor] = successor;

      return rules;
    }, {});
  },
  decodeInstructions: function (instructionsString) {
    var instructionsList = instructionsString.split(';');
    return instructionsList.reduce(function (instructions, instructionParamString) {
      var instructionParams = instructionParamString.split(',');
      var instructionName = instructionParams.shift();

      // decode instruction params
      instructions[instructionName] = instructionParams.reduce(function (params, paramString) {
        var keyChar = paramString[0];
        var keyLookup = {
          'd':'distance',
          'a':'angle',
          'o':'pop',
          'u':'push'
        };
        var key = keyLookup[keyChar];
        var value = parseFloat(paramString.substr(1));
        params[key] = value;
        return params;
      }, {});

      return instructions;
    }, {});
  },
  decodeStart: function (startString) {
    var startList = startString.split(',');
    return startList.reduce(function (params, paramString) {
      var keyChar = paramString[0];
      var keyLookup = {
        'x':'x',
        'y':'y',
        'a':'angle',
        'i':'iterations'
      };
      var key = keyLookup[keyChar];
      var value = parseFloat(paramString.substr(1));
      params[key] = value;
      return params;
    }, {});
  },
  encodeHash: function (data) {
    var axiom = data.axiom.join(',');
    var rules = this.encodeRules(data.rules);
    var instructions = this.encodeInstructions(data.instructions);
    var iterations = data.iterations;
    var start = this.encodeStart(data.start);
    return '#' +
        [axiom,
         rules,
         instructions,
         iterations,
         start].join('/');
  },
  encodeRules: function (rules) {
    var keys = Object.keys(rules);
    return keys.reduce(function(ruleString, rule) {
      return ruleString + rule + ':' + rules[rule].join('');
    }, '');
  },
  encodeInstructions: function(instructions) {
    var instructionKeys = Object.keys(instructions);
    var instructionList = instructionKeys.reduce(function(instructionList, instructionKey) {
      var instructionObj = instructions[instructionKey];
      var paramKeys = Object.keys(instructionObj);
      var paramLookup = {
          'distance':'d',
          'angle':'a',
          'pop':'o',
          'push':'u'
      }
      var paramString = paramKeys.reduce(function(paramString, paramKey) {
        return paramString + ',' + paramLookup[paramKey] + instructionObj[paramKey];
      }, '');
      instructionList.push(instructionKey + paramString);
      return instructionList;
    }, []);
    return instructionList.join(';');
  },
  // F/F:F+F-F-F+F/F,d4;+,a75;-,a-80/6/x500,y100,a20,i6
  encodeStart: function(start) {
    var startKeys = Object.keys(start);
    var keyLookup = {
      'angle':'a',
      'x':'x',
      'y':'y',
      'iterations':'i'
    }
    var startList = startKeys.reduce(function(startList, paramKey) {
      var startString = keyLookup[paramKey] + start[paramKey];
      startList.push(startString);
      return startList;
    }, []);
    return startList.join(',');
  },
  // *** PARSING ***
  parseRules: function (rules, axiom, max_iter) {
    var generatedOutput = [axiom];
    var input = axiom;
    for (var i = 0; i < max_iter; i++) {
      var generated = input.reduce(function(output, char) {
        result = (rules[char] !== undefined) ? rules[char] : char;
        return output.concat(result);
      }, []);
      generatedOutput.push(generated);
      input = generated.concat();
    }
    return generatedOutput;
  },

  // *** UI ***
  ui: function (data) {
    var inputCollection = document.getElementsByTagName('input');
    var inputs = [];
    var i = inputCollection.length;
    while(i--) {
      inputs.push(inputCollection[i]);
    }
    inputs.map(function(input) {
      var splitInput = input.id.split('-');
      var type = splitInput[0];
      var param = splitInput[1];
      switch (type) {
        case 'initial':
          input.value = data.start[param];
          break;
      }
      input.addEventListener("input", function(event) {
        switch(type) {
          case 'initial':
            data.start[param] = parseInt(event.currentTarget.value);
            data.needsRedraw = true;
            break;
        }
      });
    });
  },

  // *** DRAWING ***
  draw: function (canvas, start, rules, instructions) {
    var ctx = canvas.getContext('2d');
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    var x = start.x;
    var y = start.y;
    var angle = start.angle;
    var stack = [];
    var forward = 5;
    var radians = Math.PI/180;
    ctx.moveTo(x,y);
    ctx.beginPath();
    for (var i = 0, len = rules.length; i < len; i++) {
      var rule = rules[i];
      if (instructions.hasOwnProperty(rule)) {
        var instruction = instructions[rule];
        if (instruction.hasOwnProperty('angle')) {
          angle += instruction.angle;
        }
        if (instruction.hasOwnProperty('distance')) {
          forward = instruction.distance;
          x += Math.cos(angle * radians) * forward;
          y += Math.sin(angle * radians) * forward;
          ctx.lineTo(x, y);
        }
        if (instruction.hasOwnProperty('push')) {
          stack.push({angle: angle, x: x, y: y});
        }
        if (instruction.hasOwnProperty('pop')) {
          var settings = stack.pop();
          angle = settings.angle;
          x = settings.x;
          y = settings.x;
          ctx.moveTo(x, y);
        }
      }
    }
    ctx.stroke();
    ctx.closePath();
  }
};

var data = LS.decodeHash();
// console.log(data);
var rules = LS.parseRules(data.rules, data.axiom, data.iterations);
var canvas = document.getElementById('canvas');

// var stringRules = rules.map(function(item) {
//   return item.join('');
// });
// console.table(stringRules);

var update = function() {
  if (data.needsRedraw) {
    var iterations = Math.min(rules.length - 1, data.start.iterations);
    LS.draw(canvas, data.start, rules[iterations], data.instructions);
    data.needsRedraw = false;
    window.location.hash = LS.encodeHash(data);
  }
  requestAnimationFrame(update);
}

LS.ui(data);

requestAnimationFrame(update);
<commit_msg>refactor code into separate functions instead of single object<commit_after>// *** DATA ***
/*
  decode / encode  data to URL hash

  hash is split into the following sections delimited by '/'
  1. axiom
    example: F[A]
    chars: [A-Z]\[\]
  2. rules
    example: F:F+[F-FF]F+
    chars: [A-Z]\[\]\:\+\-
  3. instructions - delimited by ';' then split into parameters: distance(d), angle(d), push(u)/pop(o)
    example: F,d10,a25,u;A,d5,a10
    chars: [0-9],\.up
  4. iterations - max number of iterations
    example: 3
    chars: [0-9]
  5. starting drawing values - delimited by ',' : x, y, angle, iteration to display
    example: x500,y300,a10
    chars: [0-9]xyamwh
*/
var encoder = {
  decodeHash: function (data) {
    var hash = window.location.hash.substr(1);
    //hardcoded default for now if nothing is set
    if (hash === '') {
      hash = 'F/F:F+F-F-F+F/F,d3.5;+,a75;-,a-80/6/x347,y358,a70,i6';
    }
    var dataStrings = hash.split('/');
    var axiomString = dataStrings[0];
    var rulesString = dataStrings[1];
    var instructionsString = dataStrings[2];
    var iterations = dataStrings[3];
    var startString = dataStrings[4];

    data.axiom = axiomString.split('');
    data.rules = this.decodeRules(rulesString);
    data.instructions = this.decodeInstructions(instructionsString);
    data.iterations = iterations;
    data.start = this.decodeStart(startString);
    data.needsReparse = true;
    data.needsRedraw = true;
  },
  decodeRules: function (rulesString) {
    var rulesList = rulesString.split(',');
    return rulesList.reduce(function (rules, ruleString) {
      var splitRule = ruleString.split(':');
      var predecessor = splitRule[0];
      var successor = splitRule[1].split('');
      rules[predecessor] = successor;

      return rules;
    }, {});
  },
  decodeInstructions: function (instructionsString) {
    var instructionsList = instructionsString.split(';');
    return instructionsList.reduce(function (instructions, instructionParamString) {
      var instructionParams = instructionParamString.split(',');
      var instructionName = instructionParams.shift();

      // decode instruction params
      instructions[instructionName] = instructionParams.reduce(function (params, paramString) {
        var keyChar = paramString[0];
        var keyLookup = {
          'd':'distance',
          'a':'angle',
          'o':'pop',
          'u':'push'
        };
        var key = keyLookup[keyChar];
        var value = parseFloat(paramString.substr(1));
        params[key] = value;
        return params;
      }, {});

      return instructions;
    }, {});
  },
  decodeStart: function (startString) {
    var startList = startString.split(',');
    return startList.reduce(function (params, paramString) {
      var keyChar = paramString[0];
      var keyLookup = {
        'x':'x',
        'y':'y',
        'a':'angle',
        'i':'iterations'
      };
      var key = keyLookup[keyChar];
      var value = parseFloat(paramString.substr(1));
      params[key] = value;
      return params;
    }, {});
  },
  encodeHash: function (data) {
    var axiom = data.axiom.join('');
    var rules = this.encodeRules(data.rules);
    var instructions = this.encodeInstructions(data.instructions);
    var iterations = data.iterations;
    var start = this.encodeStart(data.start);
    return '#' +
        [axiom,
         rules,
         instructions,
         iterations,
         start].join('/');
  },
  encodeRules: function (rules) {
    var keys = Object.keys(rules);
    var ruleList = keys.reduce(function(ruleList, rule) {
      ruleList.push(rule + ':' + rules[rule].join(''));
      return ruleList;
    }, []);
    return ruleList.join(',');
  },
  encodeInstructions: function(instructions) {
    var instructionKeys = Object.keys(instructions);
    var instructionList = instructionKeys.reduce(function(instructionList, instructionKey) {
      var instructionObj = instructions[instructionKey];
      var paramKeys = Object.keys(instructionObj);
      var paramLookup = {
          'distance':'d',
          'angle':'a',
          'pop':'o',
          'push':'u'
      }
      var paramString = paramKeys.reduce(function(paramString, paramKey) {
        return paramString + ',' + paramLookup[paramKey] + instructionObj[paramKey];
      }, '');
      instructionList.push(instructionKey + paramString);
      return instructionList;
    }, []);
    return instructionList.join(';');
  },
  encodeStart: function(start) {
    var startKeys = Object.keys(start);
    var keyLookup = {
      'angle':'a',
      'x':'x',
      'y':'y',
      'iterations':'i'
    }
    var startList = startKeys.reduce(function(startList, paramKey) {
      var startString = keyLookup[paramKey] + start[paramKey];
      startList.push(startString);
      return startList;
    }, []);
    return startList.join(',');
  }
};

// *** PARSING ***
var parseRules = function (rules, axiom, max_iter) {
  var generatedOutput = [axiom];
  var input = axiom;
  for (var i = 0; i < max_iter; i++) {
    var generated = input.reduce(function(output, char) {
      result = (rules[char] !== undefined) ? rules[char] : char;
      return output.concat(result);
    }, []);
    generatedOutput.push(generated);
    input = generated.concat();
  }
  return generatedOutput;
};

// *** UI ***
var ui = {
  inputs: function (data) {
    var inputCollection = document.getElementsByTagName('input');
    var inputs = [];
    var i = inputCollection.length;
    while(i--) {
      inputs.push(inputCollection[i]);
    }
    inputs.map(function(input) {
      var splitInput = input.id.split('-');
      var type = splitInput[0];
      var param = splitInput[1];
      switch (type) {
        case 'initial':
          input.value = data.start[param];
          break;
      }
      input.addEventListener("input", function(event) {
        switch(type) {
          case 'initial':
            data.start[param] = parseInt(event.currentTarget.value);
            data.needsRedraw = true;
            break;
        }
      });
    });
  },
  examples: function(data, callback) {
    var exampleCollection = document.getElementsByClassName('example');
    var i = exampleCollection.length;
    var examples = [];
    while(i--) {
      exampleCollection[i].addEventListener("click", function(event) {
        window.location.hash = event.target.hash;
        callback();
      });
    }
  }
};

// *** RENDERING ***
var render = function (canvas, start, rules, instructions) {
  var ctx = canvas.getContext('2d');
  ctx.strokeStyle = 'black';
  ctx.lineWidth = 1;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  var x = start.x;
  var y = start.y;
  var angle = start.angle;
  var stack = [];
  var forward = 5;
  var radians = Math.PI/180;
  ctx.moveTo(x,y);
  ctx.beginPath();
  for (var i = 0, len = rules.length; i < len; i++) {
    var rule = rules[i];
    if (instructions.hasOwnProperty(rule)) {
      var instruction = instructions[rule];
      if (instruction.hasOwnProperty('angle')) {
        angle += instruction.angle;
      }
      if (instruction.hasOwnProperty('distance')) {
        forward = instruction.distance;
        x += Math.cos(angle * radians) * forward;
        y += Math.sin(angle * radians) * forward;
        ctx.lineTo(x, y);
      }
      if (instruction.hasOwnProperty('push')) {
        stack.push({angle: angle, x: x, y: y});
      }
      if (instruction.hasOwnProperty('pop')) {
        var settings = stack.pop();
        angle = settings.angle;
        x = settings.x;
        y = settings.x;
        ctx.moveTo(x, y);
      }
    }
  }
  ctx.stroke();
  ctx.closePath();
};

var data = {};

encoder.decodeHash(data);
// console.log(data);
var canvas = document.getElementById('canvas');

// var stringRules = rules.map(function(item) {
//   return item.join('');
// });
// console.table(stringRules);

var exampleCallback = function() {
  encoder.decodeHash(data);
};

ui.inputs(data);
ui.examples(data, exampleCallback);

var update = function() {
  if (data.needsReparse) {
    data.parsedRules = parseRules(data.rules, data.axiom, data.iterations);
  }
  if (data.needsRedraw) {
    var iterations = Math.min(data.parsedRules.length - 1, data.start.iterations);
    render(canvas, data.start, data.parsedRules[iterations], data.instructions);
    data.needsRedraw = false;
    window.location.hash = encoder.encodeHash(data);
  }
  requestAnimationFrame(update);
}

requestAnimationFrame(update);
<|endoftext|>