// ==================================================
// fancyBox v3.2.10
//
// Licensed GPLv3 for open source use
// or fancyBox Commercial License for commercial use
//
// http://fancyapps.com/fancybox/
// Copyright 2017 fancyApps
//
// ==================================================
; (function (window, document, $, any) {
    'use strict';

    // If there's no jQuery, fancyBox can't work
    // =========================================

    if (!$) {
        return;
    }

    // Check if fancyBox is already initialized
    // ========================================

    if ($.fn.fancybox) {

        if ('console' in window) {
            console.log('fancyBox already initialized');
        }

        return;
    }

    // Private default settings
    // ========================

    var defaults = {

        // Enable infinite gallery navigation
        loop: false,

        // Space around image, ignored if zoomed-in or viewport width is smaller than 800px
        margin: [44, 0],

        // Horizontal space between slides
        gutter: 50,

        // Enable keyboard navigation
        keyboard: true,

        // Should display navigation arrows at the screen edges
        arrows: true,

        // Should display infobar (counter and arrows at the top)
        infobar: true,

        // Should display toolbar (buttons at the top)
        toolbar: true,

        // What buttons should appear in the top right corner.
        // Buttons will be created using templates from `btnTpl` option
        // and they will be placed into toolbar (class="fancybox-toolbar"` element)
        buttons: [
            'slideShow',
            'fullScreen',
            'thumbs',
            'share',
            //'download',
            //'zoom',
            'close'
        ],

        // Detect "idle" time in seconds
        idleTime: 3,

        // Should display buttons at top right corner of the content
        // If 'auto' - they will be created for content having type 'html', 'inline' or 'ajax'
        // Use template from `btnTpl.smallBtn` for customization
        smallBtn: 'auto',

        // Disable right-click and use simple image protection for images
        protect: false,

        // Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc
        modal: false,

        image: {

            // Wait for images to load before displaying
            // Requires predefined image dimensions
            // If 'auto' - will zoom in thumbnail if 'width' and 'height' attributes are found
            preload: "auto"

        },

        ajax: {

            // Object containing settings for ajax request
            settings: {

                // This helps to indicate that request comes from the modal
                // Feel free to change naming
                data: {
                    fancybox: true
                }
            }

        },

        iframe: {

            // Iframe template
            tpl: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" src=""></iframe>',

            // Preload iframe before displaying it
            // This allows to calculate iframe content width and height
            // (note: Due to "Same Origin Policy", you can't get cross domain data).
            preload: true,

            // Custom CSS styling for iframe wrapping element
            // You can use this to set custom iframe dimensions
            css: {},

            // Iframe tag attributes
            attr: {
                scrolling: 'auto'
            }

        },

        // Default content type if cannot be detected automatically
        defaultType: 'image',

        // Open/close animation type
        // Possible values:
        //   false            - disable
        //   "zoom"           - zoom images from/to thumbnail
        //   "fade"
        //   "zoom-in-out"
        //
        animationEffect: "zoom",

        // Duration in ms for open/close animation
        animationDuration: 500,

        // Should image change opacity while zooming
        // If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios
        zoomOpacity: "auto",

        // Transition effect between slides
        //
        // Possible values:
        //   false            - disable
        //   "fade'
        //   "slide'
        //   "circular'
        //   "tube'
        //   "zoom-in-out'
        //   "rotate'
        //
        transitionEffect: "fade",

        // Duration in ms for transition animation
        transitionDuration: 366,

        // Custom CSS class for slide element
        slideClass: '',

        // Custom CSS class for layout
        baseClass: '',

        // Base template for layout
        baseTpl:
            '<div class="fancybox-container" role="dialog" tabindex="-1">' +
            '<div class="fancybox-bg"></div>' +
            '<div class="fancybox-inner">' +
            '<div class="fancybox-infobar">' +
            '<span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span>' +
            '</div>' +
            '<div class="fancybox-toolbar">{{buttons}}</div>' +
            '<div class="fancybox-navigation">{{arrows}}</div>' +
            '<div class="fancybox-stage"></div>' +
            '<div class="fancybox-caption-wrap"><div class="fancybox-caption"></div></div>' +
            '</div>' +
            '</div>',

        // Loading indicator template
        spinnerTpl: '<div class="fancybox-loading"></div>',

        // Error message template
        errorTpl: '<div class="fancybox-error"><p>{{ERROR}}<p></div>',

        btnTpl: {

            download: '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M20,23 L20,8 L20,23 L13,16 L20,23 L27,16 L20,23 M26,28 L13,28 L27,28 L14,28" />' +
                '</svg>' +
                '</a>',

            zoom: '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M 18,17 m-8,0 a 8,8 0 1,0 16,0 a 8,8 0 1,0 -16,0 M25,23 L31,29 L25,23" />' +
                '</svg>' +
                '</button>',

            close: '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M10,10 L30,30 M30,10 L10,30" />' +
                '</svg>' +
                '</button>',

            // This small close button will be appended to your html/inline/ajax content by default,
            // if "smallBtn" option is not set to false
            smallBtn: '<button data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"></button>',

            // Arrows
            arrowLeft: '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M10,20 L30,20 L10,20 L18,28 L10,20 L18,12 L10,20"></path>' +
                '</svg>' +
                '</button>',

            arrowRight: '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M30,20 L10,20 L30,20 L22,28 L30,20 L22,12 L30,20"></path>' +
                '</svg>' +
                '</button>'
        },

        // Container is injected into this element
        parentEl: 'body',


        // Focus handling
        // ==============

        // Try to focus on the first focusable element after opening
        autoFocus: false,

        // Put focus back to active element after closing
        backFocus: true,

        // Do not let user to focus on element outside modal content
        trapFocus: true,


        // Module specific options
        // =======================

        fullScreen: {
            autoStart: false,
        },

        // Set `touch: false` to disable dragging/swiping
        touch: {
            vertical: true,  // Allow to drag content vertically
            momentum: true   // Continue movement after releasing mouse/touch when panning
        },

        // Hash value when initializing manually,
        // set `false` to disable hash change
        hash: null,

        // Customize or add new media types
        // Example:
        /*
        media : {
            youtube : {
                params : {
                    autoplay : 0
                }
            }
        }
        */
        media: {},

        slideShow: {
            autoStart: false,
            speed: 4000
        },

        thumbs: {
            autoStart: false,                  // Display thumbnails on opening
            hideOnClose: true,                   // Hide thumbnail grid when closing animation starts
            parentEl: '.fancybox-container',  // Container is injected into this element
            axis: 'y'                     // Vertical (y) or horizontal (x) scrolling
        },

        // Use mousewheel to navigate gallery
        // If 'auto' - enabled for images only
        wheel: 'auto',

        // Callbacks
        //==========

        // See Documentation/API/Events for more information
        // Example:
        /*
            afterShow: function( instance, current ) {
                 console.info( 'Clicked element:' );
                 console.info( current.opts.$orig );
            }
        */

        onInit: $.noop,  // When instance has been initialized

        beforeLoad: $.noop,  // Before the content of a slide is being loaded
        afterLoad: $.noop,  // When the content of a slide is done loading

        beforeShow: $.noop,  // Before open animation starts
        afterShow: $.noop,  // When content is done loading and animating

        beforeClose: $.noop,  // Before the instance attempts to close. Return false to cancel the close.
        afterClose: $.noop,  // After instance has been closed

        onActivate: $.noop,  // When instance is brought to front
        onDeactivate: $.noop,  // When other instance has been activated


        // Interaction
        // ===========

        // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,
        // each option can be string or method that returns value.
        //
        // Possible values:
        //   "close"           - close instance
        //   "next"            - move to next gallery item
        //   "nextOrClose"     - move to next gallery item or close if gallery has only one item
        //   "toggleControls"  - show/hide controls
        //   "zoom"            - zoom image (if loaded)
        //   false             - do nothing

        // Clicked on the content
        clickContent: function (current, event) {
            return current.type === 'image' ? 'zoom' : false;
        },

        // Clicked on the slide
        clickSlide: 'close',

        // Clicked on the background (backdrop) element
        clickOutside: 'close',

        // Same as previous two, but for double click
        dblclickContent: false,
        dblclickSlide: false,
        dblclickOutside: false,


        // Custom options when mobile device is detected
        // =============================================

        mobile: {
            idleTime: false,
            margin: 0,

            clickContent: function (current, event) {
                return current.type === 'image' ? 'toggleControls' : false;
            },
            clickSlide: function (current, event) {
                return current.type === 'image' ? 'toggleControls' : 'close';
            },
            dblclickContent: function (current, event) {
                return current.type === 'image' ? 'zoom' : false;
            },
            dblclickSlide: function (current, event) {
                return current.type === 'image' ? 'zoom' : false;
            }
        },


        // Internationalization
        // ============

        lang: 'en',
        i18n: {
            'en': {
                CLOSE: 'Close',
                NEXT: 'Next',
                PREV: 'Previous',
                ERROR: 'The requested content cannot be loaded. <br/> Please try again later.',
                PLAY_START: 'Start slideshow',
                PLAY_STOP: 'Pause slideshow',
                FULL_SCREEN: 'Full screen',
                THUMBS: 'Thumbnails',
                DOWNLOAD: 'Download',
                SHARE: 'Share',
                ZOOM: 'Zoom'
            },
            'de': {
                CLOSE: 'Schliessen',
                NEXT: 'Weiter',
                PREV: 'Zurück',
                ERROR: 'Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.',
                PLAY_START: 'Diaschau starten',
                PLAY_STOP: 'Diaschau beenden',
                FULL_SCREEN: 'Vollbild',
                THUMBS: 'Vorschaubilder',
                DOWNLOAD: 'Herunterladen',
                SHARE: 'Teilen',
                ZOOM: 'Maßstab'
            }
        }

    };

    // Few useful variables and methods
    // ================================

    var $W = $(window);
    var $D = $(document);

    var called = 0;


    // Check if an object is a jQuery object and not a native JavaScript object
    // ========================================================================

    var isQuery = function (obj) {
        return obj && obj.hasOwnProperty && obj instanceof $;
    };


    // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame"
    // ===============================================================================

    var requestAFrame = (function () {
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            // if all else fails, use setTimeout
            function (callback) {
                return window.setTimeout(callback, 1000 / 60);
            };
    })();


    // Detect the supported transition-end event property name
    // =======================================================

    var transitionEnd = (function () {
        var t, el = document.createElement("fakeelement");

        var transitions = {
            "transition": "transitionend",
            "OTransition": "oTransitionEnd",
            "MozTransition": "transitionend",
            "WebkitTransition": "webkitTransitionEnd"
        };

        for (t in transitions) {
            if (el.style[t] !== undefined) {
                return transitions[t];
            }
        }

        return 'transitionend';
    })();


    // Force redraw on an element.
    // This helps in cases where the browser doesn't redraw an updated element properly.
    // =================================================================================

    var forceRedraw = function ($el) {
        return ($el && $el.length && $el[0].offsetHeight);
    };


    // Class definition
    // ================

    var FancyBox = function (content, opts, index) {
        var self = this;

        self.opts = $.extend(true, { index: index }, $.fancybox.defaults, opts || {});

        if ($.fancybox.isMobile) {
            self.opts = $.extend(true, {}, self.opts, self.opts.mobile);
        }

        // Exclude buttons option from deep merging
        if (opts && $.isArray(opts.buttons)) {
            self.opts.buttons = opts.buttons;
        }

        self.id = self.opts.id || ++called;
        self.group = [];

        self.currIndex = parseInt(self.opts.index, 10) || 0;
        self.prevIndex = null;

        self.prevPos = null;
        self.currPos = 0;

        self.firstRun = null;

        // Create group elements from original item collection
        self.createGroup(content);

        if (!self.group.length) {
            return;
        }

        // Save last active element and current scroll position
        self.$lastFocus = $(document.activeElement).blur();

        // Collection of gallery objects
        self.slides = {};

        self.init();
    };

    $.extend(FancyBox.prototype, {

        // Create DOM structure
        // ====================

        init: function () {
            var self = this,
                firstItem = self.group[self.currIndex],
                firstItemOpts = firstItem.opts,
                scrollbarWidth = $.fancybox.scrollbarWidth,
                $scrollDiv,
                $container,
                buttonStr;

            self.scrollTop = $D.scrollTop();
            self.scrollLeft = $D.scrollLeft();


            // Hide scrollbars
            // ===============

            if (!$.fancybox.getInstance()) {

                $('body').addClass('fancybox-active');

                // iOS hack
                if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {

                    // iOS has problems for input elements inside fixed containers,
                    // the workaround is to apply `position: fixed` to `<body>` element,
                    // unfortunately, this makes it lose the scrollbars and forces address bar to appear.

                    if (firstItem.type !== 'image') {
                        $('body').css('top', $('body').scrollTop() * -1).addClass('fancybox-iosfix');
                    }

                } else if (!$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight) {

                    if (scrollbarWidth === undefined) {
                        $scrollDiv = $('<div style="width:50px;height:50px;overflow:scroll;" />').appendTo('body');

                        scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;

                        $scrollDiv.remove();
                    }

                    $('head').append('<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar { margin-right: ' + scrollbarWidth + 'px; }</style>');
                    $('body').addClass('compensate-for-scrollbar');
                }
            }


            // Build html markup and set references
            // ====================================

            // Build html code for buttons and insert into main template
            buttonStr = '';

            $.each(firstItemOpts.buttons, function (index, value) {
                buttonStr += (firstItemOpts.btnTpl[value] || '');
            });

            // Create markup from base template, it will be initially hidden to
            // avoid unnecessary work like painting while initializing is not complete
            $container = $(
                self.translate(self,
                    firstItemOpts.baseTpl
                        .replace('buttons', buttonStr)
                        .replace('arrows', firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight)
                )
            )
                .attr('id', 'fancybox-container-' + self.id)
                .addClass('fancybox-is-hidden')
                .addClass(firstItemOpts.baseClass)
                .data('FancyBox', self)
                .appendTo(firstItemOpts.parentEl);

            // Create object holding references to jQuery wrapped nodes
            self.$refs = {
                container: $container
            };

            ['bg', 'inner', 'infobar', 'toolbar', 'stage', 'caption', 'navigation'].forEach(function (item) {
                self.$refs[item] = $container.find('.fancybox-' + item);
            });

            self.trigger('onInit');

            // Enable events, deactive previous instances
            self.activate();

            // Build slides, load and reveal content
            self.jumpTo(self.currIndex);
        },


        // Simple i18n support - replaces object keys found in template
        // with corresponding values
        // ============================================================

        translate: function (obj, str) {
            var arr = obj.opts.i18n[obj.opts.lang];

            return str.replace(/\{\{(\w+)\}\}/g, function (match, n) {
                var value = arr[n];

                if (value === undefined) {
                    return match;
                }

                return value;
            });
        },

        // Create array of gally item objects
        // Check if each object has valid type and content
        // ===============================================

        createGroup: function (content) {
            var self = this;
            var items = $.makeArray(content);

            $.each(items, function (i, item) {
                var obj = {},
                    opts = {},
                    $item,
                    type,
                    found,
                    src,
                    srcParts;

                // Step 1 - Make sure we have an object
                // ====================================

                if ($.isPlainObject(item)) {

                    // We probably have manual usage here, something like
                    // $.fancybox.open( [ { src : "image.jpg", type : "image" } ] )

                    obj = item;
                    opts = item.opts || item;

                } else if ($.type(item) === 'object' && $(item).length) {

                    // Here we probably have jQuery collection returned by some selector
                    $item = $(item);

                    opts = $item.data();
                    opts = $.extend({}, opts, opts.options || {});

                    // Here we store clicked element
                    opts.$orig = $item;

                    obj.src = opts.src || $item.attr('href');

                    // Assume that simple syntax is used, for example:
                    //   `$.fancybox.open( $("#test"), {} );`
                    if (!obj.type && !obj.src) {
                        obj.type = 'inline';
                        obj.src = item;
                    }

                } else {

                    // Assume we have a simple html code, for example:
                    //   $.fancybox.open( '<div><h1>Hi!</h1></div>' );

                    obj = {
                        type: 'html',
                        src: item + ''
                    };

                }

                // Each gallery object has full collection of options
                obj.opts = $.extend(true, {}, self.opts, opts);

                // Do not merge buttons array
                if ($.isArray(opts.buttons)) {
                    obj.opts.buttons = opts.buttons;
                }


                // Step 2 - Make sure we have content type, if not - try to guess
                // ==============================================================

                type = obj.type || obj.opts.type;
                src = obj.src || '';

                if (!type && src) {
                    if (src.match(/(^data:image\/[a-z0-9+=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)) {
                        type = 'image';

                    } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) {
                        type = 'pdf';

                    } else if (found === src.match(/\.(mp4|mov|ogv)((\?|#).*)?$/i)) {
                        type = 'video';

                        if (!obj.opts.videoFormat) {
                            obj.opts.videoFormat = 'video/' + (found[1] === 'ogv' ? 'ogg' : found[1]);
                        }

                    } else if (src.charAt(0) === '#') {
                        type = 'inline';
                    }
                }

                if (type) {
                    obj.type = type;

                } else {
                    self.trigger('objectNeedsType', obj);
                }


                // Step 3 - Some adjustments
                // =========================

                obj.index = self.group.length;

                // Check if $orig and $thumb objects exist
                if (obj.opts.$orig && !obj.opts.$orig.length) {
                    delete obj.opts.$orig;
                }

                if (!obj.opts.$thumb && obj.opts.$orig) {
                    obj.opts.$thumb = obj.opts.$orig.find('img:first');
                }

                if (obj.opts.$thumb && !obj.opts.$thumb.length) {
                    delete obj.opts.$thumb;
                }

                // "caption" is a "special" option, it can be used to customize caption per gallery item ..
                if ($.type(obj.opts.caption) === 'function') {
                    obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);
                }

                if ($.type(self.opts.caption) === 'function') {
                    obj.opts.caption = self.opts.caption.apply(item, [self, obj]);
                }

                // Make sure we have caption as a string or jQuery object
                if (!(obj.opts.caption instanceof $)) {
                    obj.opts.caption = obj.opts.caption === undefined ? '' : obj.opts.caption + '';
                }

                // Check if url contains "filter" used to filter the content
                // Example: "ajax.html #something"
                if (type === 'ajax') {
                    srcParts = src.split(/\s+/, 2);

                    if (srcParts.length > 1) {
                        obj.src = srcParts.shift();

                        obj.opts.filter = srcParts.shift();
                    }
                }

                if (obj.opts.smallBtn === 'auto') {

                    if ($.inArray(type, ['html', 'inline', 'ajax']) > -1) {
                        obj.opts.toolbar = false;
                        obj.opts.smallBtn = true;

                    } else {
                        obj.opts.smallBtn = false;
                    }

                }

                // If the type is "pdf", then simply load file into iframe
                if (type === 'pdf') {
                    obj.type = 'iframe';

                    obj.opts.iframe.preload = false;
                }

                // Hide all buttons and disable interactivity for modal items
                if (obj.opts.modal) {

                    obj.opts = $.extend(true, obj.opts, {
                        // Remove buttons
                        infobar: 0,
                        toolbar: 0,

                        smallBtn: 0,

                        // Disable keyboard navigation
                        keyboard: 0,

                        // Disable some modules
                        slideShow: 0,
                        fullScreen: 0,
                        thumbs: 0,
                        touch: 0,

                        // Disable click event handlers
                        clickContent: false,
                        clickSlide: false,
                        clickOutside: false,
                        dblclickContent: false,
                        dblclickSlide: false,
                        dblclickOutside: false
                    });

                }

                // Step 4 - Add processed object to group
                // ======================================

                self.group.push(obj);

            });

        },


        // Attach an event handler functions for:
        //   - navigation buttons
        //   - browser scrolling, resizing;
        //   - focusing
        //   - keyboard
        //   - detect idle
        // ======================================

        addEvents: function () {
            var self = this;

            self.removeEvents();

            // Make navigation elements clickable
            self.$refs.container.on('click.fb-close', '[data-fancybox-close]', function (e) {
                e.stopPropagation();
                e.preventDefault();

                self.close(e);

            }).on('click.fb-prev touchend.fb-prev', '[data-fancybox-prev]', function (e) {
                e.stopPropagation();
                e.preventDefault();

                self.previous();

            }).on('click.fb-next touchend.fb-next', '[data-fancybox-next]', function (e) {
                e.stopPropagation();
                e.preventDefault();

                self.next();

            }).on('click.fb', '[data-fancybox-zoom]', function (e) {
                // Click handler for zoom button
                self[self.isScaledDown() ? 'scaleToActual' : 'scaleToFit']();
            });


            // Handle page scrolling and browser resizing
            $W.on('orientationchange.fb resize.fb', function (e) {

                if (e && e.originalEvent && e.originalEvent.type === "resize") {

                    requestAFrame(function () {
                        self.update();
                    });

                } else {

                    self.$refs.stage.hide();

                    setTimeout(function () {
                        self.$refs.stage.show();

                        self.update();
                    }, 600);

                }

            });

            // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal
            // (a.k.a. "escaping the modal")
            $D.on('focusin.fb', function (e) {
                var instance = $.fancybox ? $.fancybox.getInstance() : null;

                if (instance.isClosing || !instance.current || !instance.current.opts.trapFocus || $(e.target).hasClass('fancybox-container') || $(e.target).is(document)) {
                    return;
                }

                if (instance && $(e.target).css('position') !== 'fixed' && !instance.$refs.container.has(e.target).length) {
                    e.stopPropagation();

                    instance.focus();

                    // Sometimes page gets scrolled, set it back
                    $W.scrollTop(self.scrollTop).scrollLeft(self.scrollLeft);
                }
            });


            // Enable keyboard navigation
            $D.on('keydown.fb', function (e) {
                var current = self.current,
                    keycode = e.keyCode || e.which;

                if (!current || !current.opts.keyboard) {
                    return;
                }

                if ($(e.target).is('input') || $(e.target).is('textarea')) {
                    return;
                }

                // Backspace and Esc keys
                if (keycode === 8 || keycode === 27) {
                    e.preventDefault();

                    self.close(e);

                    return;
                }

                // Left arrow and Up arrow
                if (keycode === 37 || keycode === 38) {
                    e.preventDefault();

                    self.previous();

                    return;
                }

                // Righ arrow and Down arrow
                if (keycode === 39 || keycode === 40) {
                    e.preventDefault();

                    self.next();

                    return;
                }

                self.trigger('afterKeydown', e, keycode);
            });


            // Hide controls after some inactivity period
            if (self.group[self.currIndex].opts.idleTime) {
                self.idleSecondsCounter = 0;

                $D.on('mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle', function (e) {
                    self.idleSecondsCounter = 0;

                    if (self.isIdle) {
                        self.showControls();
                    }

                    self.isIdle = false;
                });

                self.idleInterval = window.setInterval(function () {
                    self.idleSecondsCounter++;

                    if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) {
                        self.isIdle = true;
                        self.idleSecondsCounter = 0;

                        self.hideControls();
                    }

                }, 1000);
            }

        },


        // Remove events added by the core
        // ===============================

        removeEvents: function () {
            var self = this;

            $W.off('orientationchange.fb resize.fb');
            $D.off('focusin.fb keydown.fb .fb-idle');

            this.$refs.container.off('.fb-close .fb-prev .fb-next');

            if (self.idleInterval) {
                window.clearInterval(self.idleInterval);

                self.idleInterval = null;
            }
        },


        // Change to previous gallery item
        // ===============================

        previous: function (duration) {
            return this.jumpTo(this.currPos - 1, duration);
        },


        // Change to next gallery item
        // ===========================

        next: function (duration) {
            return this.jumpTo(this.currPos + 1, duration);
        },


        // Switch to selected gallery item
        // ===============================

        jumpTo: function (pos, duration, slide) {
            var self = this,
                firstRun,
                loop,
                current,
                previous,
                canvasWidth,
                currentPos,
                transitionProps;

            var groupLen = self.group.length;

            if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {
                return;
            }

            pos = parseInt(pos, 10);
            loop = self.current ? self.current.opts.loop : self.opts.loop;

            if (!loop && (pos < 0 || pos >= groupLen)) {
                return false;
            }

            firstRun = self.firstRun = (self.firstRun === null);

            if (groupLen < 2 && !firstRun && !!self.isDragging) {
                return;
            }

            previous = self.current;

            self.prevIndex = self.currIndex;
            self.prevPos = self.currPos;

            // Create slides
            current = self.createSlide(pos);

            if (groupLen > 1) {
                if (loop || current.index > 0) {
                    self.createSlide(pos - 1);
                }

                if (loop || current.index < groupLen - 1) {
                    self.createSlide(pos + 1);
                }
            }

            self.current = current;
            self.currIndex = current.index;
            self.currPos = current.pos;

            self.trigger('beforeShow', firstRun);

            self.updateControls();

            currentPos = $.fancybox.getTranslate(current.$slide);

            current.isMoved = (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass('fancybox-animated');
            current.forcedDuration = undefined;

            if ($.isNumeric(duration)) {
                current.forcedDuration = duration;
            } else {
                duration = current.opts[firstRun ? 'animationDuration' : 'transitionDuration'];
            }

            duration = parseInt(duration, 10);

            // Fresh start - reveal container, current slide and start loading content
            if (firstRun) {

                if (current.opts.animationEffect && duration) {
                    self.$refs.container.css('transition-duration', duration + 'ms');
                }

                self.$refs.container.removeClass('fancybox-is-hidden');

                forceRedraw(self.$refs.container);

                self.$refs.container.addClass('fancybox-is-open');

                // Make first slide visible (to display loading icon, if needed)
                current.$slide.addClass('fancybox-slide--current');

                self.loadSlide(current);

                self.preload('image');

                return;
            }

            // Clean up
            $.each(self.slides, function (index, slide) {
                $.fancybox.stop(slide.$slide);
            });

            // Make current that slide is visible even if content is still loading
            current.$slide.removeClass('fancybox-slide--next fancybox-slide--previous').addClass('fancybox-slide--current');

            // If slides have been dragged, animate them to correct position
            if (current.isMoved) {
                canvasWidth = Math.round(current.$slide.width());

                $.each(self.slides, function (index, slide) {
                    var pos = slide.pos - current.pos;

                    $.fancybox.animate(slide.$slide, {
                        top: 0,
                        left: (pos * canvasWidth) + (pos * slide.opts.gutter)
                    }, duration, function () {

                        slide.$slide.removeAttr('style').removeClass('fancybox-slide--next fancybox-slide--previous');

                        if (slide.pos === self.currPos) {
                            current.isMoved = false;

                            self.complete();
                        }
                    });
                });

            } else {
                self.$refs.stage.children().removeAttr('style');
            }

            // Start transition that reveals current content
            // or wait when it will be loaded

            if (current.isLoaded) {
                self.revealContent(current);

            } else {
                self.loadSlide(current);
            }

            self.preload('image');

            if (previous.pos === current.pos) {
                return;
            }

            // Handle previous slide
            // =====================

            transitionProps = 'fancybox-slide--' + (previous.pos > current.pos ? 'next' : 'previous');

            previous.$slide.removeClass('fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous');

            previous.isComplete = false;

            if (!duration || (!current.isMoved && !current.opts.transitionEffect)) {
                return;
            }

            if (current.isMoved) {
                previous.$slide.addClass(transitionProps);

            } else {

                transitionProps = 'fancybox-animated ' + transitionProps + ' fancybox-fx-' + current.opts.transitionEffect;

                $.fancybox.animate(previous.$slide, transitionProps, duration, function () {
                    previous.$slide.removeClass(transitionProps).removeAttr('style');
                });

            }

        },


        // Create new "slide" element
        // These are gallery items  that are actually added to DOM
        // =======================================================

        createSlide: function (pos) {

            var self = this;
            var $slide;
            var index;

            index = pos % self.group.length;
            index = index < 0 ? self.group.length + index : index;

            if (!self.slides[pos] && self.group[index]) {
                $slide = $('<div class="fancybox-slide"></div>').appendTo(self.$refs.stage);

                self.slides[pos] = $.extend(true, {}, self.group[index], {
                    pos: pos,
                    $slide: $slide,
                    isLoaded: false,
                });

                self.updateSlide(self.slides[pos]);
            }

            return self.slides[pos];
        },


        // Scale image to the actual size of the image
        // ===========================================

        scaleToActual: function (x, y, duration) {

            var self = this;

            var current = self.current;
            var $what = current.$content;

            var imgPos, posX, posY, scaleX, scaleY;

            var canvasWidth = parseInt(current.$slide.width(), 10);
            var canvasHeight = parseInt(current.$slide.height(), 10);

            var newImgWidth = current.width;
            var newImgHeight = current.height;

            if (!(current.type === 'image' && !current.hasError) || !$what || self.isAnimating) {
                return;
            }

            $.fancybox.stop($what);

            self.isAnimating = true;

            x = x === undefined ? canvasWidth * 0.5 : x;
            y = y === undefined ? canvasHeight * 0.5 : y;

            imgPos = $.fancybox.getTranslate($what);

            scaleX = newImgWidth / imgPos.width;
            scaleY = newImgHeight / imgPos.height;

            // Get center position for original image
            posX = (canvasWidth * 0.5 - newImgWidth * 0.5);
            posY = (canvasHeight * 0.5 - newImgHeight * 0.5);

            // Make sure image does not move away from edges
            if (newImgWidth > canvasWidth) {
                posX = imgPos.left * scaleX - ((x * scaleX) - x);

                if (posX > 0) {
                    posX = 0;
                }

                if (posX < canvasWidth - newImgWidth) {
                    posX = canvasWidth - newImgWidth;
                }
            }

            if (newImgHeight > canvasHeight) {
                posY = imgPos.top * scaleY - ((y * scaleY) - y);

                if (posY > 0) {
                    posY = 0;
                }

                if (posY < canvasHeight - newImgHeight) {
                    posY = canvasHeight - newImgHeight;
                }
            }

            self.updateCursor(newImgWidth, newImgHeight);

            $.fancybox.animate($what, {
                top: posY,
                left: posX,
                scaleX: scaleX,
                scaleY: scaleY
            }, duration || 330, function () {
                self.isAnimating = false;
            });

            // Stop slideshow
            if (self.SlideShow && self.SlideShow.isActive) {
                self.SlideShow.stop();
            }
        },


        // Scale image to fit inside parent element
        // ========================================

        scaleToFit: function (duration) {

            var self = this;

            var current = self.current;
            var $what = current.$content;
            var end;

            if (!(current.type === 'image' && !current.hasError) || !$what || self.isAnimating) {
                return;
            }

            $.fancybox.stop($what);

            self.isAnimating = true;

            end = self.getFitPos(current);

            self.updateCursor(end.width, end.height);

            $.fancybox.animate($what, {
                top: end.top,
                left: end.left,
                scaleX: end.width / $what.width(),
                scaleY: end.height / $what.height()
            }, duration || 330, function () {
                self.isAnimating = false;
            });

        },

        // Calculate image size to fit inside viewport
        // ===========================================

        getFitPos: function (slide) {
            var self = this;
            var $what = slide.$content;

            var imgWidth = slide.width;
            var imgHeight = slide.height;

            var margin = slide.opts.margin;

            var canvasWidth, canvasHeight, minRatio, width, height;

            if (!$what || !$what.length || (!imgWidth && !imgHeight)) {
                return false;
            }

            // Convert "margin to CSS style: [ top, right, bottom, left ]
            if ($.type(margin) === "number") {
                margin = [margin, margin];
            }

            if (margin.length === 2) {
                margin = [margin[0], margin[1], margin[0], margin[1]];
            }

            // We can not use $slide width here, because it can have different diemensions while in transiton
            canvasWidth = parseInt(self.$refs.stage.width(), 10) - (margin[1] + margin[3]);
            canvasHeight = parseInt(self.$refs.stage.height(), 10) - (margin[0] + margin[2]);

            minRatio = Math.min(1, canvasWidth / imgWidth, canvasHeight / imgHeight);

            width = Math.floor(minRatio * imgWidth);
            height = Math.floor(minRatio * imgHeight);

            // Use floor rounding to make sure it really fits
            return {
                top: Math.floor((canvasHeight - height) * 0.5) + margin[0],
                left: Math.floor((canvasWidth - width) * 0.5) + margin[3],
                width: width,
                height: height
            };

        },


        // Update content size and position for all slides
        // ==============================================

        update: function () {
            var self = this;

            $.each(self.slides, function (key, slide) {
                self.updateSlide(slide);
            });
        },


        // Update slide content position and size
        // ======================================

        updateSlide: function (slide, duration) {
            var self = this,
                $what = slide && slide.$content;

            if ($what && (slide.width || slide.height)) {
                self.isAnimating = false;

                $.fancybox.stop($what);

                $.fancybox.setTranslate($what, self.getFitPos(slide));

                if (slide.pos === self.currPos) {
                    self.updateCursor();
                }
            }

            slide.$slide.trigger('refresh');

            self.trigger('onUpdate', slide);

        },


        // Horizontally center slide
        // =========================

        centerSlide: function (slide, duration) {
            var self = this, canvasWidth, pos;

            if (self.current) {
                canvasWidth = Math.round(slide.$slide.width());
                pos = slide.pos - self.current.pos;

                $.fancybox.animate(slide.$slide, {
                    top: 0,
                    left: (pos * canvasWidth) + (pos * slide.opts.gutter),
                    opacity: 1
                }, duration === undefined ? 0 : duration, null, false);
            }
        },


        // Update cursor style depending if content can be zoomed
        // ======================================================

        updateCursor: function (nextWidth, nextHeight) {

            var self = this;
            var isScaledDown;

            var $container = self.$refs.container.removeClass('fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut');

            if (!self.current || self.isClosing) {
                return;
            }

            if (self.isZoomable()) {

                $container.addClass('fancybox-is-zoomable');

                if (nextWidth !== undefined && nextHeight !== undefined) {
                    isScaledDown = nextWidth < self.current.width && nextHeight < self.current.height;

                } else {
                    isScaledDown = self.isScaledDown();
                }

                if (isScaledDown) {

                    // If image is scaled down, then, obviously, it can be zoomed to full size
                    $container.addClass('fancybox-can-zoomIn');

                } else {

                    if (self.current.opts.touch) {

                        // If image size ir largen than available available and touch module is not disable,
                        // then user can do panning
                        $container.addClass('fancybox-can-drag');

                    } else {
                        $container.addClass('fancybox-can-zoomOut');
                    }

                }

            } else if (self.current.opts.touch) {
                $container.addClass('fancybox-can-drag');
            }

        },


        // Check if current slide is zoomable
        // ==================================

        isZoomable: function () {

            var self = this;

            var current = self.current;
            var fitPos;

            if (!current || self.isClosing) {
                return;
            }

            // Assume that slide is zoomable if
            //   - image is loaded successfuly
            //   - click action is "zoom"
            //   - actual size of the image is smaller than available area
            if (current.type === 'image' && current.isLoaded && !current.hasError &&
                (current.opts.clickContent === 'zoom' || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) === "zoom"))
            ) {

                fitPos = self.getFitPos(current);

                if (current.width > fitPos.width || current.height > fitPos.height) {
                    return true;
                }

            }

            return false;

        },


        // Check if current image dimensions are smaller than actual
        // =========================================================

        isScaledDown: function () {

            var self = this;

            var current = self.current;
            var $what = current.$content;

            var rez = false;

            if ($what) {
                rez = $.fancybox.getTranslate($what);
                rez = rez.width < current.width || rez.height < current.height;
            }

            return rez;

        },


        // Check if image dimensions exceed parent element
        // ===============================================

        canPan: function () {

            var self = this;

            var current = self.current;
            var $what = current.$content;

            var rez = false;

            if ($what) {
                rez = self.getFitPos(current);
                rez = Math.abs($what.width() - rez.width) > 1 || Math.abs($what.height() - rez.height) > 1;
            }

            return rez;

        },


        // Load content into the slide
        // ===========================

        loadSlide: function (slide) {

            var self = this, type, $slide;
            var ajaxLoad;

            if (slide.isLoading) {
                return;
            }

            if (slide.isLoaded) {
                return;
            }

            slide.isLoading = true;

            self.trigger('beforeLoad', slide);

            type = slide.type;
            $slide = slide.$slide;

            $slide
                .off('refresh')
                .trigger('onReset')
                .addClass('fancybox-slide--' + (type || 'unknown'))
                .addClass(slide.opts.slideClass);

            // Create content depending on the type

            switch (type) {

                case 'image':

                    self.setImage(slide);

                    break;

                case 'iframe':

                    self.setIframe(slide);

                    break;

                case 'html':

                    self.setContent(slide, slide.src || slide.content);

                    break;

                case 'inline':

                    if ($(slide.src).length) {
                        self.setContent(slide, $(slide.src));

                    } else {
                        self.setError(slide);
                    }

                    break;

                case 'ajax':

                    self.showLoading(slide);

                    ajaxLoad = $.ajax($.extend({}, slide.opts.ajax.settings, {
                        url: slide.src,
                        success: function (data, textStatus) {

                            if (textStatus === 'success') {
                                self.setContent(slide, data);
                            }

                        },
                        error: function (jqXHR, textStatus) {

                            if (jqXHR && textStatus !== 'abort') {
                                self.setError(slide);
                            }

                        }
                    }));

                    $slide.one('onReset', function () {
                        ajaxLoad.abort();
                    });

                    break;

                case 'video':

                    self.setContent(slide,
                        '<video controls>' +
                        '<source src="' + slide.src + '" type="' + slide.opts.videoFormat + '">' +
                        'Your browser doesn\'t support HTML5 video' +
                        '</video>'
                    );

                    break;

                default:

                    self.setError(slide);

                    break;

            }

            return true;

        },


        // Use thumbnail image, if possible
        // ================================

        setImage: function (slide) {

            var self = this;
            var srcset = slide.opts.srcset || slide.opts.image.srcset;

            var found, temp, pxRatio, windowWidth;

            // If we have "srcset", then we need to find matching "src" value.
            // This is necessary, because when you set an src attribute, the browser will preload the image
            // before any javascript or even CSS is applied.
            if (srcset) {
                pxRatio = window.devicePixelRatio || 1;
                windowWidth = window.innerWidth * pxRatio;

                temp = srcset.split(',').map(function (el) {
                    var ret = {};

                    el.trim().split(/\s+/).forEach(function (el, i) {
                        var value = parseInt(el.substring(0, el.length - 1), 10);

                        if (i === 0) {
                            return (ret.url = el);
                        }

                        if (value) {
                            ret.value = value;
                            ret.postfix = el[el.length - 1];
                        }

                    });

                    return ret;
                });

                // Sort by value
                temp.sort(function (a, b) {
                    return a.value - b.value;
                });

                // Ok, now we have an array of all srcset values
                for (var j = 0; j < temp.length; j++) {
                    var el = temp[j];

                    if ((el.postfix === 'w' && el.value >= windowWidth) || (el.postfix === 'x' && el.value >= pxRatio)) {
                        found = el;
                        break;
                    }
                }

                // If not found, take the last one
                if (!found && temp.length) {
                    found = temp[temp.length - 1];
                }

                if (found) {
                    slide.src = found.url;

                    // If we have default width/height values, we can calculate height for matching source
                    if (slide.width && slide.height && found.postfix === 'w') {
                        slide.height = (slide.width / slide.height) * found.value;
                        slide.width = found.value;
                    }
                }
            }

            // This will be wrapper containing both ghost and actual image
            slide.$content = $('<div class="fancybox-image-wrap"></div>')
                .addClass('fancybox-is-hidden')
                .appendTo(slide.$slide);


            // If we have a thumbnail, we can display it while actual image is loading
            // Users will not stare at black screen and actual image will appear gradually
            if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && (slide.opts.thumb || slide.opts.$thumb)) {

                slide.width = slide.opts.width;
                slide.height = slide.opts.height;

                slide.$ghost = $('<img />')
                    .one('error', function () {

                        $(this).remove();

                        slide.$ghost = null;

                        self.setBigImage(slide);

                    })
                    .one('load', function () {

                        self.afterLoad(slide);

                        self.setBigImage(slide);

                    })
                    .addClass('fancybox-image')
                    .appendTo(slide.$content)
                    .attr('src', slide.opts.thumb || slide.opts.$thumb.attr('src'));

            } else {

                self.setBigImage(slide);

            }

        },


        // Create full-size image
        // ======================

        setBigImage: function (slide) {
            var self = this;
            var $img = $('<img />');

            slide.$image = $img
                .one('error', function () {

                    self.setError(slide);

                })
                .one('load', function () {

                    // Clear timeout that checks if loading icon needs to be displayed
                    clearTimeout(slide.timouts);

                    slide.timouts = null;

                    if (self.isClosing) {
                        return;
                    }

                    slide.width = slide.opts.width || this.naturalWidth;
                    slide.height = slide.opts.height || this.naturalHeight;

                    if (slide.opts.image.srcset) {
                        $img.attr('sizes', '100vw').attr('srcset', slide.opts.image.srcset);
                    }

                    self.hideLoading(slide);

                    if (slide.$ghost) {

                        slide.timouts = setTimeout(function () {
                            slide.timouts = null;

                            slide.$ghost.hide();

                        }, Math.min(300, Math.max(1000, slide.height / 1600)));

                    } else {
                        self.afterLoad(slide);
                    }

                })
                .addClass('fancybox-image')
                .attr('src', slide.src)
                .appendTo(slide.$content);

            if (($img[0].complete || $img[0].readyState === "complete") && $img[0].naturalWidth && $img[0].naturalHeight) {
                $img.trigger('load');

            } else if ($img[0].error) {
                $img.trigger('error');

            } else {

                slide.timouts = setTimeout(function () {
                    if (!$img[0].complete && !slide.hasError) {
                        self.showLoading(slide);
                    }

                }, 100);

            }

        },


        // Create iframe wrapper, iframe and bindings
        // ==========================================

        setIframe: function (slide) {
            var self = this,
                opts = slide.opts.iframe,
                $slide = slide.$slide,
                $iframe;

            slide.$content = $('<div class="fancybox-content' + (opts.preload ? ' fancybox-is-hidden' : '') + '"></div>')
                .css(opts.css)
                .appendTo($slide);

            $iframe = $(opts.tpl.replace(/\{rnd\}/g, new Date().getTime()))
                .attr(opts.attr)
                .appendTo(slide.$content);

            if (opts.preload) {

                self.showLoading(slide);

                // Unfortunately, it is not always possible to determine if iframe is successfully loaded
                // (due to browser security policy)

                $iframe.on('load.fb error.fb', function (e) {
                    this.isReady = 1;

                    slide.$slide.trigger('refresh');

                    self.afterLoad(slide);
                });

                // Recalculate iframe content size
                // ===============================

                $slide.on('refresh.fb', function () {
                    var $wrap = slide.$content,
                        frameWidth = opts.css.width,
                        frameHeight = opts.css.height,
                        scrollWidth,
                        $contents,
                        $body;

                    if ($iframe[0].isReady !== 1) {
                        return;
                    }

                    // Check if content is accessible,
                    // it will fail if frame is not with the same origin

                    try {
                        $contents = $iframe.contents();
                        $body = $contents.find('body');

                    } catch (ignore) { "allowEmptyCatch" === true }

                    // Calculate dimensions for the wrapper
                    if ($body && $body.length) {

                        if (frameWidth === undefined) {
                            scrollWidth = $iframe[0].contentWindow.document.documentElement.scrollWidth;

                            frameWidth = Math.ceil($body.outerWidth(true) + ($wrap.width() - scrollWidth));
                            frameWidth += $wrap.outerWidth() - $wrap.innerWidth();
                        }

                        if (frameHeight === undefined) {
                            frameHeight = Math.ceil($body.outerHeight(true));
                            frameHeight += $wrap.outerHeight() - $wrap.innerHeight();
                        }

                        // Resize wrapper to fit iframe content
                        if (frameWidth) {
                            $wrap.width(frameWidth);
                        }

                        if (frameHeight) {
                            $wrap.height(frameHeight);
                        }
                    }

                    $wrap.removeClass('fancybox-is-hidden');

                });

            } else {

                this.afterLoad(slide);

            }

            $iframe.attr('src', slide.src);

            if (slide.opts.smallBtn === true) {
                slide.$content.prepend(self.translate(slide, slide.opts.btnTpl.smallBtn));
            }

            // Remove iframe if closing or changing gallery item
            $slide.one('onReset', function () {

                // This helps IE not to throw errors when closing
                try {

                    $(this).find('iframe').hide().attr('src', '//about:blank');

                } catch (ignore) { "allowEmptyCatch" === true }

                $(this).empty();

                slide.isLoaded = false;

            });

        },


        // Wrap and append content to the slide
        // ======================================

        setContent: function (slide, content) {

            var self = this;

            if (self.isClosing) {
                return;
            }

            self.hideLoading(slide);

            slide.$slide.empty();

            if (isQuery(content) && content.parent().length) {

                // If content is a jQuery object, then it will be moved to the slide.
                // The placeholder is created so we will know where to put it back.
                // If user is navigating gallery fast, then the content might be already inside fancyBox
                // =====================================================================================

                // Make sure content is not already moved to fancyBox
                content.parent('.fancybox-slide--inline').trigger('onReset');

                // Create temporary element marking original place of the content
                slide.$placeholder = $('<div></div>').hide().insertAfter(content);

                // Make sure content is visible
                content.css('display', 'inline-block');

            } else if (!slide.hasError) {

                // If content is just a plain text, try to convert it to html
                if ($.type(content) === 'string') {
                    content = $('<div>').append($.trim(content)).contents();

                    // If we have text node, then add wrapping element to make vertical alignment work
                    if (content[0].nodeType === 3) {
                        content = $('<div>').html(content);
                    }
                }

                // If "filter" option is provided, then filter content
                if (slide.opts.filter) {
                    content = $('<div>').html(content).find(slide.opts.filter);
                }

            }

            slide.$slide.one('onReset', function () {

                // Pause all html5 video/audio
                $(this).find('video,audio').trigger('pause');

                // Put content back
                if (slide.$placeholder) {
                    slide.$placeholder.after(content.hide()).remove();

                    slide.$placeholder = null;
                }

                // Remove custom close button
                if (slide.$smallBtn) {
                    slide.$smallBtn.remove();

                    slide.$smallBtn = null;
                }

                // Remove content and mark slide as not loaded
                if (!slide.hasError) {
                    $(this).empty();

                    slide.isLoaded = false;
                }

            });

            slide.$content = $(content).appendTo(slide.$slide);

            this.afterLoad(slide);
        },

        // Display error message
        // =====================

        setError: function (slide) {

            slide.hasError = true;

            slide.$slide.removeClass('fancybox-slide--' + slide.type);

            this.setContent(slide, this.translate(slide, slide.opts.errorTpl));

        },


        // Show loading icon inside the slide
        // ==================================

        showLoading: function (slide) {

            var self = this;

            slide = slide || self.current;

            if (slide && !slide.$spinner) {
                slide.$spinner = $(self.opts.spinnerTpl).appendTo(slide.$slide);
            }

        },

        // Remove loading icon from the slide
        // ==================================

        hideLoading: function (slide) {

            var self = this;

            slide = slide || self.current;

            if (slide && slide.$spinner) {
                slide.$spinner.remove();

                delete slide.$spinner;
            }

        },


        // Adjustments after slide content has been loaded
        // ===============================================

        afterLoad: function (slide) {

            var self = this;

            if (self.isClosing) {
                return;
            }

            slide.isLoading = false;
            slide.isLoaded = true;

            self.trigger('afterLoad', slide);

            self.hideLoading(slide);

            if (slide.opts.smallBtn && !slide.$smallBtn) {
                slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content.filter('div,form').first());
            }

            if (slide.opts.protect && slide.$content && !slide.hasError) {

                // Disable right click
                slide.$content.on('contextmenu.fb', function (e) {
                    if (e.button === 2) {
                        e.preventDefault();
                    }

                    return true;
                });

                // Add fake element on top of the image
                // This makes a bit harder for user to select image
                if (slide.type === 'image') {
                    $('<div class="fancybox-spaceball"></div>').appendTo(slide.$content);
                }

            }

            self.revealContent(slide);

        },


        // Make content visible
        // This method is called right after content has been loaded or
        // user navigates gallery and transition should start
        // ============================================================

        revealContent: function (slide) {

            var self = this;
            var $slide = slide.$slide;

            var effect, effectClassName, duration, opacity, end, start = false;

            effect = slide.opts[self.firstRun ? 'animationEffect' : 'transitionEffect'];
            duration = slide.opts[self.firstRun ? 'animationDuration' : 'transitionDuration'];

            duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);

            if (slide.isMoved || slide.pos !== self.currPos || !duration) {
                effect = false;
            }

            // Check if can zoom
            if (effect === 'zoom' && !(slide.pos === self.currPos && duration && slide.type === 'image' && !slide.hasError && (start = self.getThumbPos(slide)))) {
                effect = 'fade';
            }

            // Zoom animation
            // ==============

            if (effect === 'zoom') {
                end = self.getFitPos(slide);

                end.scaleX = end.width / start.width;
                end.scaleY = end.height / start.height;

                delete end.width;
                delete end.height;

                // Check if we need to animate opacity
                opacity = slide.opts.zoomOpacity;

                if (opacity === 'auto') {
                    opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1;
                }

                if (opacity) {
                    start.opacity = 0.1;
                    end.opacity = 1;
                }

                // Draw image at start position
                $.fancybox.setTranslate(slide.$content.removeClass('fancybox-is-hidden'), start);

                forceRedraw(slide.$content);

                // Start animation
                $.fancybox.animate(slide.$content, end, duration, function () {
                    self.complete();
                });

                return;
            }

            self.updateSlide(slide);


            // Simply show content
            // ===================

            if (!effect) {
                forceRedraw($slide);

                slide.$content.removeClass('fancybox-is-hidden');

                if (slide.pos === self.currPos) {
                    self.complete();
                }

                return;
            }

            $.fancybox.stop($slide);

            effectClassName = 'fancybox-animated fancybox-slide--' + (slide.pos >= self.prevPos ? 'next' : 'previous') + ' fancybox-fx-' + effect;

            $slide.removeAttr('style').removeClass('fancybox-slide--current fancybox-slide--next fancybox-slide--previous').addClass(effectClassName);

            slide.$content.removeClass('fancybox-is-hidden');

            //Force reflow for CSS3 transitions
            forceRedraw($slide);

            $.fancybox.animate($slide, 'fancybox-slide--current', duration, function (e) {
                $slide.removeClass(effectClassName).removeAttr('style');

                if (slide.pos === self.currPos) {
                    self.complete();
                }

            }, true);

        },


        // Check if we can and have to zoom from thumbnail
        //================================================

        getThumbPos: function (slide) {

            var self = this;
            var rez = false;

            // Check if element is inside the viewport by at least 1 pixel
            var isElementVisible = function ($el) {
                var element = $el[0];

                var elementRect = element.getBoundingClientRect();
                var parentRects = [];

                var visibleInAllParents;

                while (element.parentElement !== null) {
                    if ($(element.parentElement).css('overflow') === 'hidden' || $(element.parentElement).css('overflow') === 'auto') {
                        parentRects.push(element.parentElement.getBoundingClientRect());
                    }

                    element = element.parentElement;
                }

                visibleInAllParents = parentRects.every(function (parentRect) {
                    var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
                    var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);

                    return visiblePixelX > 0 && visiblePixelY > 0;
                });

                return visibleInAllParents &&
                    elementRect.bottom > 0 && elementRect.right > 0 &&
                    elementRect.left < $(window).width() && elementRect.top < $(window).height();
            };

            var $thumb = slide.opts.$thumb;
            var thumbPos = $thumb ? $thumb.offset() : 0;
            var slidePos;

            if (thumbPos && $thumb[0].ownerDocument === document && isElementVisible($thumb)) {
                slidePos = self.$refs.stage.offset();

                rez = {
                    top: thumbPos.top - slidePos.top + parseFloat($thumb.css("border-top-width") || 0),
                    left: thumbPos.left - slidePos.left + parseFloat($thumb.css("border-left-width") || 0),
                    width: $thumb.width(),
                    height: $thumb.height(),
                    scaleX: 1,
                    scaleY: 1
                };
            }

            return rez;
        },


        // Final adjustments after current gallery item is moved to position
        // and it`s content is loaded
        // ==================================================================

        complete: function () {
            var self = this,
                current = self.current,
                slides = {},
                promise;

            if (current.isMoved || !current.isLoaded || current.isComplete) {
                return;
            }

            current.isComplete = true;

            current.$slide.siblings().trigger('onReset');

            self.preload('inline');

            // Trigger any CSS3 transiton inside the slide
            forceRedraw(current.$slide);

            current.$slide.addClass('fancybox-slide--complete');

            // Remove unnecessary slides
            $.each(self.slides, function (key, slide) {
                if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {
                    slides[slide.pos] = slide;

                } else if (slide) {
                    $.fancybox.stop(slide.$slide);

                    slide.$slide.off().remove();
                }
            });

            self.slides = slides;

            self.updateCursor();

            self.trigger('afterShow');

            // Play first html5 video/audio
            current.$slide.find('video,audio').first().trigger('play');

            // Try to focus on the first focusable element
            if ($(document.activeElement).is('[disabled]') || (current.opts.autoFocus && !(current.type === 'image' || current.type === 'iframe'))) {
                self.focus();
            }

        },


        // Preload next and previous slides
        // ================================

        preload: function (type) {
            var self = this,
                next = self.slides[self.currPos + 1],
                prev = self.slides[self.currPos - 1];

            if (next && next.type === type) {
                self.loadSlide(next);
            }

            if (prev && prev.type === type) {
                self.loadSlide(prev);
            }
        },


        // Try to find and focus on the first focusable element
        // ====================================================

        focus: function () {
            var current = this.current;
            var $el;

            if (this.isClosing) {
                return;
            }

            if (current && current.isComplete) {

                // Look for first input with autofocus attribute
                $el = current.$slide.find('input[autofocus]:enabled:visible:first');

                if (!$el.length) {
                    $el = current.$slide.find('button,:input,[tabindex],a').filter(':enabled:visible:first');
                }
            }

            $el = $el && $el.length ? $el : this.$refs.container;

            $el.focus();
        },


        // Activates current instance - brings container to the front and enables keyboard,
        // notifies other instances about deactivating
        // =================================================================================

        activate: function () {
            var self = this;

            // Deactivate all instances
            $('.fancybox-container').each(function () {
                var instance = $(this).data('FancyBox');

                // Skip self and closing instances
                if (instance && instance.id !== self.id && !instance.isClosing) {
                    instance.trigger('onDeactivate');

                    instance.removeEvents();

                    instance.isVisible = false;
                }

            });

            self.isVisible = true;

            if (self.current || self.isIdle) {
                self.update();

                self.updateControls();
            }

            self.trigger('onActivate');

            self.addEvents();
        },


        // Start closing procedure
        // This will start "zoom-out" animation if needed and clean everything up afterwards
        // =================================================================================

        close: function (e, d) {

            var self = this;
            var current = self.current;

            var effect, duration;
            var $what, opacity, start, end;

            var done = function () {
                self.cleanUp(e);
            };

            if (self.isClosing) {
                return false;
            }

            self.isClosing = true;

            // If beforeClose callback prevents closing, make sure content is centered
            if (self.trigger('beforeClose', e) === false) {
                self.isClosing = false;

                requestAFrame(function () {
                    self.update();
                });

                return false;
            }

            // Remove all events
            // If there are multiple instances, they will be set again by "activate" method
            self.removeEvents();

            if (current.timouts) {
                clearTimeout(current.timouts);
            }

            $what = current.$content;
            effect = current.opts.animationEffect;
            duration = $.isNumeric(d) ? d : (effect ? current.opts.animationDuration : 0);

            // Remove other slides
            current.$slide.off(transitionEnd).removeClass('fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated');

            current.$slide.siblings().trigger('onReset').remove();

            // Trigger animations
            if (duration) {
                self.$refs.container.removeClass('fancybox-is-open').addClass('fancybox-is-closing');
            }

            // Clean up
            self.hideLoading(current);

            self.hideControls();

            self.updateCursor();

            // Check if possible to zoom-out
            if (effect === 'zoom' && !(e !== true && $what && duration && current.type === 'image' && !current.hasError && (end = self.getThumbPos(current)))) {
                effect = 'fade';
            }

            if (effect === 'zoom') {
                $.fancybox.stop($what);

                start = $.fancybox.getTranslate($what);

                start.width = start.width * start.scaleX;
                start.height = start.height * start.scaleY;

                // Check if we need to animate opacity
                opacity = current.opts.zoomOpacity;

                if (opacity === 'auto') {
                    opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1;
                }

                if (opacity) {
                    end.opacity = 0;
                }

                start.scaleX = start.width / end.width;
                start.scaleY = start.height / end.height;

                start.width = end.width;
                start.height = end.height;

                $.fancybox.setTranslate(current.$content, start);

                forceRedraw(current.$content);

                $.fancybox.animate(current.$content, end, duration, done);

                return true;
            }

            if (effect && duration) {

                // If skip animation
                if (e === true) {
                    setTimeout(done, duration);

                } else {
                    $.fancybox.animate(current.$slide.removeClass('fancybox-slide--current'), 'fancybox-animated fancybox-slide--previous fancybox-fx-' + effect, duration, done);
                }

            } else {
                done();
            }

            return true;
        },


        // Final adjustments after removing the instance
        // =============================================

        cleanUp: function (e) {
            var self = this,
                $body = $('body'),
                instance,
                offset;

            self.current.$slide.trigger('onReset');

            self.$refs.container.empty().remove();

            self.trigger('afterClose', e);

            // Place back focus
            if (self.$lastFocus && !!self.current.opts.backFocus) {
                self.$lastFocus.focus();
            }

            self.current = null;

            // Check if there are other instances
            instance = $.fancybox.getInstance();

            if (instance) {
                instance.activate();

            } else {

                $W.scrollTop(self.scrollTop).scrollLeft(self.scrollLeft);

                $body.removeClass('fancybox-active compensate-for-scrollbar');

                if ($body.hasClass('fancybox-iosfix')) {
                    offset = parseInt(document.body.style.top, 10);

                    $body.removeClass('fancybox-iosfix').css('top', '').scrollTop(offset * -1);
                }

                $('#fancybox-style-noscroll').remove();

            }

        },


        // Call callback and trigger an event
        // ==================================

        trigger: function (name, slide) {
            var args = Array.prototype.slice.call(arguments, 1),
                self = this,
                obj = slide && slide.opts ? slide : self.current,
                rez;

            if (obj) {
                args.unshift(obj);

            } else {
                obj = self;
            }

            args.unshift(self);

            if ($.isFunction(obj.opts[name])) {
                rez = obj.opts[name].apply(obj, args);
            }

            if (rez === false) {
                return rez;
            }

            if (name === 'afterClose' || !self.$refs) {
                $D.trigger(name + '.fb', args);

            } else {
                self.$refs.container.trigger(name + '.fb', args);
            }

        },


        // Update infobar values, navigation button states and reveal caption
        // ==================================================================

        updateControls: function (force) {

            var self = this;

            var current = self.current,
                index = current.index,
                caption = current.opts.caption,
                $container = self.$refs.container,
                $caption = self.$refs.caption;

            // Recalculate content dimensions
            current.$slide.trigger('refresh');

            self.$caption = caption && caption.length ? $caption.html(caption) : null;

            if (!self.isHiddenControls && !self.isIdle) {
                self.showControls();
            }

            // Update info and navigation elements
            $container.find('[data-fancybox-count]').html(self.group.length);
            $container.find('[data-fancybox-index]').html(index + 1);

            $container.find('[data-fancybox-prev]').prop('disabled', (!current.opts.loop && index <= 0));
            $container.find('[data-fancybox-next]').prop('disabled', (!current.opts.loop && index >= self.group.length - 1));

            if (current.type === 'image') {

                // Update download button source
                $container.find('[data-fancybox-download]').attr('href', current.opts.image.src || current.src).show();

            } else {
                $container.find('[data-fancybox-download],[data-fancybox-zoom]').hide();
            }
        },

        // Hide toolbar and caption
        // ========================

        hideControls: function () {

            this.isHiddenControls = true;

            this.$refs.container.removeClass('fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav');

        },

        showControls: function () {
            var self = this;
            var opts = self.current ? self.current.opts : self.opts;
            var $container = self.$refs.container;

            self.isHiddenControls = false;
            self.idleSecondsCounter = 0;

            $container
                .toggleClass('fancybox-show-toolbar', !!(opts.toolbar && opts.buttons))
                .toggleClass('fancybox-show-infobar', !!(opts.infobar && self.group.length > 1))
                .toggleClass('fancybox-show-nav', !!(opts.arrows && self.group.length > 1))
                .toggleClass('fancybox-is-modal', !!opts.modal);

            if (self.$caption) {
                $container.addClass('fancybox-show-caption ');

            } else {
                $container.removeClass('fancybox-show-caption');
            }

        },


        // Toggle toolbar and caption
        // ==========================

        toggleControls: function () {
            if (this.isHiddenControls) {
                this.showControls();

            } else {
                this.hideControls();
            }

        },


    });


    $.fancybox = {

        version: "3.2.10",
        defaults: defaults,


        // Get current instance and execute a command.
        //
        // Examples of usage:
        //
        //   $instance = $.fancybox.getInstance();
        //   $.fancybox.getInstance().jumpTo( 1 );
        //   $.fancybox.getInstance( 'jumpTo', 1 );
        //   $.fancybox.getInstance( function() {
        //       console.info( this.currIndex );
        //   });
        // ======================================================

        getInstance: function (command) {
            var instance = $('.fancybox-container:not(".fancybox-is-closing"):last').data('FancyBox');
            var args = Array.prototype.slice.call(arguments, 1);

            if (instance instanceof FancyBox) {

                if ($.type(command) === 'string') {
                    instance[command].apply(instance, args);

                } else if ($.type(command) === 'function') {
                    command.apply(instance, args);
                }

                return instance;
            }

            return false;

        },


        // Create new instance
        // ===================

        open: function (items, opts, index) {
            return new FancyBox(items, opts, index);
        },


        // Close current or all instances
        // ==============================

        close: function (all) {
            var instance = this.getInstance();

            if (instance) {
                instance.close();

                // Try to find and close next instance

                if (all === true) {
                    this.close();
                }
            }

        },

        // Close instances and unbind all events
        // ==============================

        destroy: function () {

            this.close(true);

            $D.off('click.fb-start');

        },


        // Try to detect mobile devices
        // ============================

        isMobile: document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),


        // Detect if 'translate3d' support is available
        // ============================================

        use3d: (function () {
            var div = document.createElement('div');

            return window.getComputedStyle && window.getComputedStyle(div).getPropertyValue('transform') && !(document.documentMode && document.documentMode < 11);
        }()),

        // Helper function to get current visual state of an element
        // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]
        // =====================================================================

        getTranslate: function ($el) {
            var matrix;

            if (!$el || !$el.length) {
                return false;
            }

            matrix = $el.eq(0).css('transform');

            if (matrix && matrix.indexOf('matrix') !== -1) {
                matrix = matrix.split('(')[1];
                matrix = matrix.split(')')[0];
                matrix = matrix.split(',');
            } else {
                matrix = [];
            }

            if (matrix.length) {

                // If IE
                if (matrix.length > 10) {
                    matrix = [matrix[13], matrix[12], matrix[0], matrix[5]];

                } else {
                    matrix = [matrix[5], matrix[4], matrix[0], matrix[3]];
                }

                matrix = matrix.map(parseFloat);

            } else {
                matrix = [0, 0, 1, 1];

                var transRegex = /\.*translate\((.*)px,(.*)px\)/i;
                var transRez = transRegex.exec($el.eq(0).attr('style'));

                if (transRez) {
                    matrix[0] = parseFloat(transRez[2]);
                    matrix[1] = parseFloat(transRez[1]);
                }
            }

            return {
                top: matrix[0],
                left: matrix[1],
                scaleX: matrix[2],
                scaleY: matrix[3],
                opacity: parseFloat($el.css('opacity')),
                width: $el.width(),
                height: $el.height()
            };

        },


        // Shortcut for setting "translate3d" properties for element
        // Can set be used to set opacity, too
        // ========================================================

        setTranslate: function ($el, props) {
            var str = '';
            var css = {};

            if (!$el || !props) {
                return;
            }

            if (props.left !== undefined || props.top !== undefined) {
                str = (props.left === undefined ? $el.position().left : props.left) + 'px, ' + (props.top === undefined ? $el.position().top : props.top) + 'px';

                if (this.use3d) {
                    str = 'translate3d(' + str + ', 0px)';

                } else {
                    str = 'translate(' + str + ')';
                }
            }

            if (props.scaleX !== undefined && props.scaleY !== undefined) {
                str = (str.length ? str + ' ' : '') + 'scale(' + props.scaleX + ', ' + props.scaleY + ')';
            }

            if (str.length) {
                css.transform = str;
            }

            if (props.opacity !== undefined) {
                css.opacity = props.opacity;
            }

            if (props.width !== undefined) {
                css.width = props.width;
            }

            if (props.height !== undefined) {
                css.height = props.height;
            }

            return $el.css(css);
        },


        // Simple CSS transition handler
        // =============================

        animate: function ($el, to, duration, callback, leaveAnimationName) {
            if ($.isFunction(duration)) {
                callback = duration;
                duration = null;
            }

            if (!$.isPlainObject(to)) {
                $el.removeAttr('style');
            }

            $el.on(transitionEnd, function (e) {

                // Skip events from child elements and z-index change
                if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName === 'z-index')) {
                    return;
                }

                $.fancybox.stop($el);

                if ($.isPlainObject(to)) {

                    if (to.scaleX !== undefined && to.scaleY !== undefined) {
                        $el.css('transition-duration', '');

                        to.width = Math.round($el.width() * to.scaleX);
                        to.height = Math.round($el.height() * to.scaleY);

                        to.scaleX = 1;
                        to.scaleY = 1;

                        $.fancybox.setTranslate($el, to);
                    }

                    if (leaveAnimationName === false) {
                        $el.removeAttr('style');
                    }

                } else if (leaveAnimationName !== true) {
                    $el.removeClass(to);
                }

                if ($.isFunction(callback)) {
                    callback(e);
                }

            });

            if ($.isNumeric(duration)) {
                $el.css('transition-duration', duration + 'ms');
            }

            if ($.isPlainObject(to)) {
                $.fancybox.setTranslate($el, to);

            } else {
                $el.addClass(to);
            }

            if (to.scaleX && $el.hasClass('fancybox-image-wrap')) {
                $el.parent().addClass('fancybox-is-scaling');
            }

            // Make sure that `transitionend` callback gets fired
            $el.data("timer", setTimeout(function () {
                $el.trigger('transitionend');
            }, duration + 16));

        },

        stop: function ($el) {
            clearTimeout($el.data("timer"));

            $el.off('transitionend').css('transition-duration', '');

            if ($el.hasClass('fancybox-image-wrap')) {
                $el.parent().removeClass('fancybox-is-scaling');
            }
        }

    };


    // Default click handler for "fancyboxed" links
    // ============================================

    function _run(e) {
        var $target = $(e.currentTarget),
            opts = e.data ? e.data.options : {},
            value = $target.attr('data-fancybox') || '',
            index = 0,
            items = [];

        // Avoid opening multiple times
        if (e.isDefaultPrevented()) {
            return;
        }

        e.preventDefault();

        // Get all related items and find index for clicked one
        if (value) {
            items = opts.selector ? $(opts.selector) : (e.data ? e.data.items : []);
            items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]');

            index = items.index($target);

            // Sometimes current item can not be found
            // (for example, when slider clones items)
            if (index < 0) {
                index = 0;
            }

        } else {
            items = [$target];
        }

        $.fancybox.open(items, opts, index);
    }


    // Create a jQuery plugin
    // ======================

    $.fn.fancybox = function (options) {
        var selector;

        options = options || {};
        selector = options.selector || false;

        if (selector) {

            $('body').off('click.fb-start', selector).on('click.fb-start', selector, {
                options: options
            }, _run);

        } else {

            this.off('click.fb-start').on('click.fb-start', {
                items: this,
                options: options
            }, _run);

        }

        return this;
    };


    // Self initializing plugin
    // ========================

    $D.on('click.fb-start', '[data-fancybox]', _run);

}(window, document, window.jQuery || jQuery));

// ==========================================================================
//
// Media
// Adds additional media type support
//
// ==========================================================================
; (function ($) {

    'use strict';

    // Formats matching url to final form

    var format = function (url, rez, params) {
        if (!url) {
            return;
        }

        params = params || '';

        if ($.type(params) === "object") {
            params = $.param(params, true);
        }

        $.each(rez, function (key, value) {
            url = url.replace('$' + key, value || '');
        });

        if (params.length) {
            url += (url.indexOf('?') > 0 ? '&' : '?') + params;
        }

        return url;
    };

    // Object containing properties for each media type

    var defaults = {
        youtube: {
            matcher: /(youtube\.com|youtu\.be|youtubenocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,
            params: {
                autoplay: 1,
                autohide: 1,
                fs: 1,
                rel: 0,
                hd: 1,
                wmode: 'transparent',
                enablejsapi: 1,
                html5: 1
            },
            paramPlace: 8,
            type: 'iframe',
            url: '//www.youtube.com/embed/$4',
            thumb: '//img.youtube.com/vi/$4/hqdefault.jpg'
        },

        vimeo: {
            matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,
            params: {
                autoplay: 1,
                hd: 1,
                show_title: 1,
                show_byline: 1,
                show_portrait: 0,
                fullscreen: 1,
                api: 1
            },
            paramPlace: 3,
            type: 'iframe',
            url: '//player.vimeo.com/video/$2'
        },

        metacafe: {
            matcher: /metacafe.com\/watch\/(\d+)\/(.*)?/,
            type: 'iframe',
            url: '//www.metacafe.com/embed/$1/?ap=1'
        },

        dailymotion: {
            matcher: /dailymotion.com\/video\/(.*)\/?(.*)/,
            params: {
                additionalInfos: 0,
                autoStart: 1
            },
            type: 'iframe',
            url: '//www.dailymotion.com/embed/video/$1'
        },

        vine: {
            matcher: /vine.co\/v\/([a-zA-Z0-9]+)/,
            type: 'iframe',
            url: '//vine.co/v/$1/embed/simple'
        },

        instagram: {
            matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_]+)\/?/i,
            type: 'image',
            url: '//$1/p/$2/media/?size=l'
        },

        // Examples:
        // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
        // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z
        // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
        gmap_place: {
            matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,
            type: 'iframe',
            url: function (rez) {
                return '//maps.google.' + rez[2] + '/?ll=' + (rez[9] ? rez[9] + '&z=' + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\//, "&") : '') : rez[12]) + '&output=' + (rez[12] && rez[12].indexOf('layer=c') > 0 ? 'svembed' : 'embed');
            }
        },

        // Examples:
        // https://www.google.com/maps/search/Empire+State+Building/
        // https://www.google.com/maps/search/?api=1&query=centurylink+field
        // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393
        gmap_search: {
            matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,
            type: 'iframe',
            url: function (rez) {
                return '//maps.google.' + rez[2] + '/maps?q=' + rez[5].replace('query=', 'q=').replace('api=1', '') + '&output=embed';
            }
        }
    };

    $(document).on('objectNeedsType.fb', function (e, instance, item) {

        var url = item.src || '',
            type = false,
            media,
            thumb,
            rez,
            params,
            urlParams,
            paramObj,
            provider;

        media = $.extend(true, {}, defaults, item.opts.media);

        // Look for any matching media type
        $.each(media, function (providerName, providerOpts) {
            rez = url.match(providerOpts.matcher);

            if (!rez) {
                return;
            }

            type = providerOpts.type;
            paramObj = {};

            if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {
                urlParams = rez[providerOpts.paramPlace];

                if (urlParams[0] === '?') {
                    urlParams = urlParams.substring(1);
                }

                urlParams = urlParams.split('&');

                for (var m = 0; m < urlParams.length; ++m) {
                    var p = urlParams[m].split('=', 2);

                    if (p.length === 2) {
                        paramObj[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
                    }
                }
            }

            params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj);

            url = $.type(providerOpts.url) === "function" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params);
            thumb = $.type(providerOpts.thumb) === "function" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez);

            if (providerName === 'vimeo') {
                url = url.replace('&%23', '#');
            }

            return false;
        });

        // If it is found, then change content type and update the url

        if (type) {
            item.src = url;
            item.type = type;

            if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {
                item.opts.thumb = thumb;
            }

            if (type === 'iframe') {
                $.extend(true, item.opts, {
                    iframe: {
                        preload: false,
                        attr: {
                            scrolling: "no"
                        }
                    }
                });

                item.contentProvider = provider;

                item.opts.slideClass += ' fancybox-slide--' + (provider === 'gmap_place' || provider === 'gmap_search' ? 'map' : 'video');
            }

        } else if (url) {
            item.type = item.opts.defaultType;
        }

    });

}(window.jQuery || jQuery));

// ==========================================================================
//
// Guestures
// Adds touch guestures, handles click and tap events
//
// ==========================================================================
; (function (window, document, $) {
    'use strict';

    var requestAFrame = (function () {
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            // if all else fails, use setTimeout
            function (callback) {
                return window.setTimeout(callback, 1000 / 60);
            };
    })();

    var cancelAFrame = (function () {
        return window.cancelAnimationFrame ||
            window.webkitCancelAnimationFrame ||
            window.mozCancelAnimationFrame ||
            window.oCancelAnimationFrame ||
            function (id) {
                window.clearTimeout(id);
            };
    })();

    var pointers = function (e) {
        var result = [];

        e = e.originalEvent || e || window.e;
        e = e.touches && e.touches.length ? e.touches : (e.changedTouches && e.changedTouches.length ? e.changedTouches : [e]);

        for (var key in e) {

            if (e[key].pageX) {
                result.push({ x: e[key].pageX, y: e[key].pageY });

            } else if (e[key].clientX) {
                result.push({ x: e[key].clientX, y: e[key].clientY });
            }
        }

        return result;
    };

    var distance = function (point2, point1, what) {
        if (!point1 || !point2) {
            return 0;
        }

        if (what === 'x') {
            return point2.x - point1.x;

        } else if (what === 'y') {
            return point2.y - point1.y;
        }

        return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
    };

    var isClickable = function ($el) {
        if ($el.is('a,area,button,[role="button"],input,label,select,summary,textarea') || $.isFunction($el.get(0).onclick) || $el.data('selectable')) {
            return true;
        }

        // Check for attributes like data-fancybox-next or data-fancybox-close
        for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
            if (atts[i].nodeName.substr(0, 14) === 'data-fancybox-') {
                return true;
            }
        }

        return false;
    };

    var hasScrollbars = function (el) {
        var overflowY = window.getComputedStyle(el)['overflow-y'];
        var overflowX = window.getComputedStyle(el)['overflow-x'];

        var vertical = (overflowY === 'scroll' || overflowY === 'auto') && el.scrollHeight > el.clientHeight;
        var horizontal = (overflowX === 'scroll' || overflowX === 'auto') && el.scrollWidth > el.clientWidth;

        return vertical || horizontal;
    };

    var isScrollable = function ($el) {
        var rez = false;

        while (typeof x === "undefined") {
            rez = hasScrollbars($el.get(0));

            if (rez) {
                break;
            }

            $el = $el.parent();

            if (!$el.length || $el.hasClass('fancybox-stage') || $el.is('body')) {
                break;
            }
        }

        return rez;
    };


    var Guestures = function (instance) {
        var self = this;

        self.instance = instance;

        self.$bg = instance.$refs.bg;
        self.$stage = instance.$refs.stage;
        self.$container = instance.$refs.container;

        self.destroy();

        self.$container.on('touchstart.fb.touch mousedown.fb.touch', $.proxy(self, 'ontouchstart'));
    };

    Guestures.prototype.destroy = function () {
        this.$container.off('.fb.touch');
    };

    Guestures.prototype.ontouchstart = function (e) {
        var self = this;

        var $target = $(e.target);
        var instance = self.instance;
        var current = instance.current;
        var $content = current.$content;

        var isTouchDevice = (e.type === 'touchstart');

        // Do not respond to both (touch and mouse) events
        if (isTouchDevice) {
            self.$container.off('mousedown.fb.touch');
        }

        // Ignore right click
        if (e.originalEvent && e.originalEvent.button === 2) {
            return;
        }

        // Ignore taping on links, buttons, input elements
        if (!$target.length || isClickable($target) || isClickable($target.parent())) {
            return;
        }

        // Ignore clicks on the scrollbar
        if (!$target.is('img') && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {
            return;
        }

        // Ignore clicks while zooming or closing
        if (!current || self.instance.isAnimating || self.instance.isClosing) {
            e.stopPropagation();
            e.preventDefault();

            return;
        }

        self.realPoints = self.startPoints = pointers(e);

        if (!self.startPoints) {
            return;
        }

        e.stopPropagation();

        self.startEvent = e;

        self.canTap = true;
        self.$target = $target;
        self.$content = $content;
        self.opts = current.opts.touch;

        self.isPanning = false;
        self.isSwiping = false;
        self.isZooming = false;
        self.isScrolling = false;

        self.sliderStartPos = self.sliderLastPos || { top: 0, left: 0 };
        self.contentStartPos = $.fancybox.getTranslate(self.$content);
        self.contentLastPos = null;

        self.startTime = new Date().getTime();
        self.distanceX = self.distanceY = self.distance = 0;

        self.canvasWidth = Math.round(current.$slide[0].clientWidth);
        self.canvasHeight = Math.round(current.$slide[0].clientHeight);

        $(document)
            .off('.fb.touch')
            .on(isTouchDevice ? 'touchend.fb.touch touchcancel.fb.touch' : 'mouseup.fb.touch mouseleave.fb.touch', $.proxy(self, "ontouchend"))
            .on(isTouchDevice ? 'touchmove.fb.touch' : 'mousemove.fb.touch', $.proxy(self, "ontouchmove"));

        if ($.fancybox.isMobile) {
            document.addEventListener('scroll', self.onscroll, true);
        }

        if (!(self.opts || instance.canPan()) || !($target.is(self.$stage) || self.$stage.find($target).length)) {

            // Prevent image ghosting while dragging
            if ($target.is('img')) {
                e.preventDefault();
            }

            return;
        }

        if (!($.fancybox.isMobile && (isScrollable($target) || isScrollable($target.parent())))) {
            e.preventDefault();
        }

        if (self.startPoints.length === 1) {
            if (current.type === 'image' && (self.contentStartPos.width > self.canvasWidth + 1 || self.contentStartPos.height > self.canvasHeight + 1)) {
                $.fancybox.stop(self.$content);

                self.$content.css('transition-duration', '');

                self.isPanning = true;

            } else {
                self.isSwiping = true;
            }

            self.$container.addClass('fancybox-controls--isGrabbing');
        }

        if (self.startPoints.length === 2 && !instance.isAnimating && !current.hasError && current.type === 'image' && (current.isLoaded || current.$ghost)) {
            self.canTap = false;
            self.isSwiping = false;
            self.isPanning = false;

            self.isZooming = true;

            $.fancybox.stop(self.$content);

            self.$content.css('transition-duration', '');

            self.centerPointStartX = ((self.startPoints[0].x + self.startPoints[1].x) * 0.5) - $(window).scrollLeft();
            self.centerPointStartY = ((self.startPoints[0].y + self.startPoints[1].y) * 0.5) - $(window).scrollTop();

            self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;
            self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;

            self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);
        }

    };

    Guestures.prototype.onscroll = function (e) {
        self.isScrolling = true;
    };

    Guestures.prototype.ontouchmove = function (e) {
        var self = this,
            $target = $(e.target);

        if (self.isScrolling || !($target.is(self.$stage) || self.$stage.find($target).length)) {
            self.canTap = false;

            return;
        }

        self.newPoints = pointers(e);

        if (!(self.opts || self.instance.canPan()) || !self.newPoints || !self.newPoints.length) {
            return;
        }

        if (!(self.isSwiping && self.isSwiping === true)) {
            e.preventDefault();
        }

        self.distanceX = distance(self.newPoints[0], self.startPoints[0], 'x');
        self.distanceY = distance(self.newPoints[0], self.startPoints[0], 'y');

        self.distance = distance(self.newPoints[0], self.startPoints[0])

        // Skip false ontouchmove events (Chrome)
        if (self.distance > 0) {
            if (self.isSwiping) {
                self.onSwipe(e);

            } else if (self.isPanning) {
                self.onPan();

            } else if (self.isZooming) {
                self.onZoom();
            }
        }

    };

    Guestures.prototype.onSwipe = function (e) {
        var self = this,
            swiping = self.isSwiping,
            left = self.sliderStartPos.left || 0,
            angle;

        // If direction is not yet determined
        if (swiping === true) {

            // We need at least 10px distance to correctly calculate an angle
            if (Math.abs(self.distance) > 10) {
                self.canTap = false;

                if (self.instance.group.length < 2 && self.opts.vertical) {
                    self.isSwiping = 'y';

                } else if (self.instance.isDragging || self.opts.vertical === false || (self.opts.vertical === 'auto' && $(window).width() > 800)) {
                    self.isSwiping = 'x';

                } else {
                    angle = Math.abs(Math.atan2(self.distanceY, self.distanceX) * 180 / Math.PI);

                    self.isSwiping = (angle > 45 && angle < 135) ? 'y' : 'x';
                }

                self.canTap = false;

                if (self.isSwiping === 'y' && $.fancybox.isMobile && (isScrollable(self.$target) || isScrollable(self.$target.parent()))) {
                    self.isScrolling = true;

                    return;
                }

                self.instance.isDragging = self.isSwiping;

                // Reset points to avoid jumping, because we dropped first swipes to calculate the angle
                self.startPoints = self.newPoints;

                $.each(self.instance.slides, function (index, slide) {
                    $.fancybox.stop(slide.$slide);

                    slide.$slide.css('transition-duration', '');

                    slide.inTransition = false;

                    if (slide.pos === self.instance.current.pos) {
                        self.sliderStartPos.left = $.fancybox.getTranslate(slide.$slide).left;
                    }
                });

                // Stop slideshow
                if (self.instance.SlideShow && self.instance.SlideShow.isActive) {
                    self.instance.SlideShow.stop();
                }
            }

            return;
        }

        // Sticky edges
        if (swiping === 'x') {
            if (self.distanceX > 0 && (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))) {
                left = left + Math.pow(self.distanceX, 0.8);

            } else if (self.distanceX < 0 && (self.instance.group.length < 2 || (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))) {
                left = left - Math.pow(-self.distanceX, 0.8);

            } else {
                left = left + self.distanceX;
            }
        }

        self.sliderLastPos = {
            top: swiping === 'x' ? 0 : self.sliderStartPos.top + self.distanceY,
            left: left
        };

        if (self.requestId) {
            cancelAFrame(self.requestId);

            self.requestId = null;
        }

        self.requestId = requestAFrame(function () {

            if (self.sliderLastPos) {
                $.each(self.instance.slides, function (index, slide) {
                    var pos = slide.pos - self.instance.currPos;

                    $.fancybox.setTranslate(slide.$slide, {
                        top: self.sliderLastPos.top,
                        left: self.sliderLastPos.left + (pos * self.canvasWidth) + (pos * slide.opts.gutter)
                    });
                });

                self.$container.addClass('fancybox-is-sliding');
            }

        });

    };

    Guestures.prototype.onPan = function () {
        var self = this;

        // Sometimes, when tapping causally, image can move a bit and that breaks double tapping
        if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {
            self.startPoints = self.newPoints;
            return;
        }

        self.canTap = false;

        self.contentLastPos = self.limitMovement();

        if (self.requestId) {
            cancelAFrame(self.requestId);

            self.requestId = null;
        }

        self.requestId = requestAFrame(function () {
            $.fancybox.setTranslate(self.$content, self.contentLastPos);
        });
    };

    // Make panning sticky to the edges
    Guestures.prototype.limitMovement = function () {
        var self = this;

        var canvasWidth = self.canvasWidth;
        var canvasHeight = self.canvasHeight;

        var distanceX = self.distanceX;
        var distanceY = self.distanceY;

        var contentStartPos = self.contentStartPos;

        var currentOffsetX = contentStartPos.left;
        var currentOffsetY = contentStartPos.top;

        var currentWidth = contentStartPos.width;
        var currentHeight = contentStartPos.height;

        var minTranslateX, minTranslateY,
            maxTranslateX, maxTranslateY,
            newOffsetX, newOffsetY;

        if (currentWidth > canvasWidth) {
            newOffsetX = currentOffsetX + distanceX;

        } else {
            newOffsetX = currentOffsetX;
        }

        newOffsetY = currentOffsetY + distanceY;

        // Slow down proportionally to traveled distance
        minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
        minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);

        maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);
        maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);

        if (currentWidth > canvasWidth) {

            //   ->
            if (distanceX > 0 && newOffsetX > minTranslateX) {
                newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
            }

            //    <-
            if (distanceX < 0 && newOffsetX < maxTranslateX) {
                newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
            }

        }

        if (currentHeight > canvasHeight) {

            //   \/
            if (distanceY > 0 && newOffsetY > minTranslateY) {
                newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
            }

            //   /\
            if (distanceY < 0 && newOffsetY < maxTranslateY) {
                newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
            }

        }

        return {
            top: newOffsetY,
            left: newOffsetX,
            scaleX: contentStartPos.scaleX,
            scaleY: contentStartPos.scaleY
        };

    };

    Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) {
        var self = this;

        var canvasWidth = self.canvasWidth;
        var canvasHeight = self.canvasHeight;

        if (newWidth > canvasWidth) {
            newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
            newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;

        } else {

            // Center horizontally
            newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);

        }

        if (newHeight > canvasHeight) {
            newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
            newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;

        } else {

            // Center vertically
            newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);

        }

        return {
            top: newOffsetY,
            left: newOffsetX
        };

    };

    Guestures.prototype.onZoom = function () {
        var self = this;

        // Calculate current distance between points to get pinch ratio and new width and height

        var currentWidth = self.contentStartPos.width;
        var currentHeight = self.contentStartPos.height;

        var currentOffsetX = self.contentStartPos.left;
        var currentOffsetY = self.contentStartPos.top;

        var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);

        var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;

        var newWidth = Math.floor(currentWidth * pinchRatio);
        var newHeight = Math.floor(currentHeight * pinchRatio);

        // This is the translation due to pinch-zooming
        var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
        var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;

        //Point between the two touches

        var centerPointEndX = ((self.newPoints[0].x + self.newPoints[1].x) / 2) - $(window).scrollLeft();
        var centerPointEndY = ((self.newPoints[0].y + self.newPoints[1].y) / 2) - $(window).scrollTop();

        // And this is the translation due to translation of the centerpoint
        // between the two fingers

        var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
        var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;

        // The new offset is the old/current one plus the total translation

        var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
        var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);

        var newPos = {
            top: newOffsetY,
            left: newOffsetX,
            scaleX: self.contentStartPos.scaleX * pinchRatio,
            scaleY: self.contentStartPos.scaleY * pinchRatio
        };

        self.canTap = false;

        self.newWidth = newWidth;
        self.newHeight = newHeight;

        self.contentLastPos = newPos;

        if (self.requestId) {
            cancelAFrame(self.requestId);

            self.requestId = null;
        }

        self.requestId = requestAFrame(function () {
            $.fancybox.setTranslate(self.$content, self.contentLastPos);
        });

    };

    Guestures.prototype.ontouchend = function (e) {
        var self = this;
        var dMs = Math.max((new Date().getTime()) - self.startTime, 1);

        var swiping = self.isSwiping;
        var panning = self.isPanning;
        var zooming = self.isZooming;
        var scrolling = self.isScrolling;

        self.endPoints = pointers(e);

        self.$container.removeClass('fancybox-controls--isGrabbing');

        $(document).off('.fb.touch');

        document.removeEventListener('scroll', self.onscroll, true);

        if (self.requestId) {
            cancelAFrame(self.requestId);

            self.requestId = null;
        }

        self.isSwiping = false;
        self.isPanning = false;
        self.isZooming = false;
        self.isScrolling = false;

        self.instance.isDragging = false;

        if (self.canTap) {
            return self.onTap(e);
        }

        self.speed = 366;

        // Speed in px/ms
        self.velocityX = self.distanceX / dMs * 0.5;
        self.velocityY = self.distanceY / dMs * 0.5;

        self.speedX = Math.max(self.speed * 0.5, Math.min(self.speed * 1.5, (1 / Math.abs(self.velocityX)) * self.speed));

        if (panning) {
            self.endPanning();

        } else if (zooming) {
            self.endZooming();

        } else {
            self.endSwiping(swiping, scrolling);
        }

        return;
    };

    Guestures.prototype.endSwiping = function (swiping, scrolling) {
        var self = this,
            ret = false,
            len = self.instance.group.length;

        self.sliderLastPos = null;

        // Close if swiped vertically / navigate if horizontally
        if (swiping === 'y' && !scrolling && Math.abs(self.distanceY) > 50) {

            // Continue vertical movement
            $.fancybox.animate(self.instance.current.$slide, {
                top: self.sliderStartPos.top + self.distanceY + (self.velocityY * 150),
                opacity: 0
            }, 150);

            ret = self.instance.close(true, 300);

        } else if (swiping === 'x' && self.distanceX > 50 && len > 1) {
            ret = self.instance.previous(self.speedX);

        } else if (swiping === 'x' && self.distanceX < -50 && len > 1) {
            ret = self.instance.next(self.speedX);
        }

        if (ret === false && (swiping === 'x' || swiping === 'y')) {
            if (scrolling || len < 2) {
                self.instance.centerSlide(self.instance.current, 150);
            } else {
                self.instance.jumpTo(self.instance.current.index);
            }
        }

        self.$container.removeClass('fancybox-is-sliding');

    };

    // Limit panning from edges
    // ========================

    Guestures.prototype.endPanning = function () {

        var self = this;
        var newOffsetX, newOffsetY, newPos;

        if (!self.contentLastPos) {
            return;
        }

        if (self.opts.momentum === false) {
            newOffsetX = self.contentLastPos.left;
            newOffsetY = self.contentLastPos.top;

        } else {

            // Continue movement
            newOffsetX = self.contentLastPos.left + (self.velocityX * self.speed);
            newOffsetY = self.contentLastPos.top + (self.velocityY * self.speed);
        }

        newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);

        newPos.width = self.contentStartPos.width;
        newPos.height = self.contentStartPos.height;

        $.fancybox.animate(self.$content, newPos, 330);
    };


    Guestures.prototype.endZooming = function () {
        var self = this;

        var current = self.instance.current;

        var newOffsetX, newOffsetY, newPos, reset;

        var newWidth = self.newWidth;
        var newHeight = self.newHeight;

        if (!self.contentLastPos) {
            return;
        }

        newOffsetX = self.contentLastPos.left;
        newOffsetY = self.contentLastPos.top;

        reset = {
            top: newOffsetY,
            left: newOffsetX,
            width: newWidth,
            height: newHeight,
            scaleX: 1,
            scaleY: 1
        };

        // Reset scalex/scaleY values; this helps for perfomance and does not break animation
        $.fancybox.setTranslate(self.$content, reset);

        if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
            self.instance.scaleToFit(150);

        } else if (newWidth > current.width || newHeight > current.height) {
            self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);

        } else {

            newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);

            // Switch from scale() to width/height or animation will not work correctly
            $.fancybox.setTranslate(self.content, $.fancybox.getTranslate(self.$content));

            $.fancybox.animate(self.$content, newPos, 150);
        }

    };

    Guestures.prototype.onTap = function (e) {
        var self = this;
        var $target = $(e.target);

        var instance = self.instance;
        var current = instance.current;

        var endPoints = (e && pointers(e)) || self.startPoints;

        var tapX = endPoints[0] ? endPoints[0].x - self.$stage.offset().left : 0;
        var tapY = endPoints[0] ? endPoints[0].y - self.$stage.offset().top : 0;

        var where;

        var process = function (prefix) {

            var action = current.opts[prefix];

            if ($.isFunction(action)) {
                action = action.apply(instance, [current, e]);
            }

            if (!action) {
                return;
            }

            switch (action) {

                case "close":

                    instance.close(self.startEvent);

                    break;

                case "toggleControls":

                    instance.toggleControls(true);

                    break;

                case "next":

                    instance.next();

                    break;

                case "nextOrClose":

                    if (instance.group.length > 1) {
                        instance.next();

                    } else {
                        instance.close(self.startEvent);
                    }

                    break;

                case "zoom":

                    if (current.type === 'image' && (current.isLoaded || current.$ghost)) {

                        if (instance.canPan()) {
                            instance.scaleToFit();

                        } else if (instance.isScaledDown()) {
                            instance.scaleToActual(tapX, tapY);

                        } else if (instance.group.length < 2) {
                            instance.close(self.startEvent);
                        }
                    }

                    break;
            }

        };

        // Ignore right click
        if (e.originalEvent && e.originalEvent.button === 2) {
            return;
        }

        // Skip if clicked on the scrollbar
        if (!$target.is('img') && tapX > $target[0].clientWidth + $target.offset().left) {
            return;
        }

        // Check where is clicked
        if ($target.is('.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container')) {
            where = 'Outside';

        } else if ($target.is('.fancybox-slide')) {
            where = 'Slide';

        } else if (instance.current.$content && instance.current.$content.find($target).addBack().filter($target).length) {
            where = 'Content';

        } else {
            return;
        }

        // Check if this is a double tap
        if (self.tapped) {

            // Stop previously created single tap
            clearTimeout(self.tapped);
            self.tapped = null;

            // Skip if distance between taps is too big
            if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
                return this;
            }

            // OK, now we assume that this is a double-tap
            process('dblclick' + where);

        } else {

            // Single tap will be processed if user has not clicked second time within 300ms
            // or there is no need to wait for double-tap
            self.tapX = tapX;
            self.tapY = tapY;

            if (current.opts['dblclick' + where] && current.opts['dblclick' + where] !== current.opts['click' + where]) {

                self.tapped = setTimeout(function () {
                    self.tapped = null;

                    process('click' + where);

                }, 500);

            } else {
                process('click' + where);
            }

        }

        return this;
    };

    $(document).on('onActivate.fb', function (e, instance) {
        if (instance && !instance.Guestures) {
            instance.Guestures = new Guestures(instance);
        }
    });

}(window, document, window.jQuery || jQuery));

// ==========================================================================
//
// SlideShow
// Enables slideshow functionality
//
// Example of usage:
// $.fancybox.getInstance().SlideShow.start()
//
// ==========================================================================
; (function (document, $) {
    'use strict';

    $.extend(true, $.fancybox.defaults, {
        btnTpl: {
            slideShow:
                '<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M13,12 L27,20 L13,27 Z" />' +
                '<path d="M15,10 v19 M23,10 v19" />' +
                '</svg>' +
                '</button>'
        },
        slideShow: {
            autoStart: false,
            speed: 3000
        }
    });

    var SlideShow = function (instance) {
        this.instance = instance;
        this.init();
    };

    $.extend(SlideShow.prototype, {
        timer: null,
        isActive: false,
        $button: null,

        init: function () {
            var self = this;

            self.$button = self.instance.$refs.toolbar.find('[data-fancybox-play]').on('click', function () {
                self.toggle();
            });

            if (self.instance.group.length < 2 || !self.instance.group[self.instance.currIndex].opts.slideShow) {
                self.$button.hide();
            }
        },

        set: function (force) {
            var self = this;

            // Check if reached last element
            if (self.instance && self.instance.current && (force === true || self.instance.current.opts.loop || self.instance.currIndex < self.instance.group.length - 1)) {
                self.timer = setTimeout(function () {
                    if (self.isActive) {
                        self.instance.jumpTo((self.instance.currIndex + 1) % self.instance.group.length);
                    }

                }, self.instance.current.opts.slideShow.speed);

            } else {
                self.stop();
                self.instance.idleSecondsCounter = 0;
                self.instance.showControls();
            }
        },

        clear: function () {
            var self = this;

            clearTimeout(self.timer);

            self.timer = null;
        },

        start: function () {
            var self = this;
            var current = self.instance.current;

            if (current) {
                self.isActive = true;

                self.$button
                    .attr('title', current.opts.i18n[current.opts.lang].PLAY_STOP)
                    .removeClass('fancybox-button--play')
                    .addClass('fancybox-button--pause');

                self.set(true);
            }
        },

        stop: function () {
            var self = this;
            var current = self.instance.current;

            self.clear();

            self.$button
                .attr('title', current.opts.i18n[current.opts.lang].PLAY_START)
                .removeClass('fancybox-button--pause')
                .addClass('fancybox-button--play');

            self.isActive = false;
        },

        toggle: function () {
            var self = this;

            if (self.isActive) {
                self.stop();

            } else {
                self.start();
            }
        }

    });

    $(document).on({
        'onInit.fb': function (e, instance) {
            if (instance && !instance.SlideShow) {
                instance.SlideShow = new SlideShow(instance);
            }
        },

        'beforeShow.fb': function (e, instance, current, firstRun) {
            var SlideShow = instance && instance.SlideShow;

            if (firstRun) {

                if (SlideShow && current.opts.slideShow.autoStart) {
                    SlideShow.start();
                }

            } else if (SlideShow && SlideShow.isActive) {
                SlideShow.clear();
            }
        },

        'afterShow.fb': function (e, instance, current) {
            var SlideShow = instance && instance.SlideShow;

            if (SlideShow && SlideShow.isActive) {
                SlideShow.set();
            }
        },

        'afterKeydown.fb': function (e, instance, current, keypress, keycode) {
            var SlideShow = instance && instance.SlideShow;

            // "P" or Spacebar
            if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is('button,a,input')) {
                keypress.preventDefault();

                SlideShow.toggle();
            }
        },

        'beforeClose.fb onDeactivate.fb': function (e, instance) {
            var SlideShow = instance && instance.SlideShow;

            if (SlideShow) {
                SlideShow.stop();
            }
        }
    });

    // Page Visibility API to pause slideshow when window is not active
    $(document).on("visibilitychange", function () {
        var instance = $.fancybox.getInstance();
        var SlideShow = instance && instance.SlideShow;

        if (SlideShow && SlideShow.isActive) {
            if (document.hidden) {
                SlideShow.clear();

            } else {
                SlideShow.set();
            }
        }
    });

}(document, window.jQuery || jQuery));

// ==========================================================================
//
// FullScreen
// Adds fullscreen functionality
//
// ==========================================================================
; (function (document, $) {
    'use strict';

    // Collection of methods supported by user browser
    var fn = (function () {

        var fnMap = [
            [
                'requestFullscreen',
                'exitFullscreen',
                'fullscreenElement',
                'fullscreenEnabled',
                'fullscreenchange',
                'fullscreenerror'
            ],
            // new WebKit
            [
                'webkitRequestFullscreen',
                'webkitExitFullscreen',
                'webkitFullscreenElement',
                'webkitFullscreenEnabled',
                'webkitfullscreenchange',
                'webkitfullscreenerror'

            ],
            // old WebKit (Safari 5.1)
            [
                'webkitRequestFullScreen',
                'webkitCancelFullScreen',
                'webkitCurrentFullScreenElement',
                'webkitCancelFullScreen',
                'webkitfullscreenchange',
                'webkitfullscreenerror'

            ],
            [
                'mozRequestFullScreen',
                'mozCancelFullScreen',
                'mozFullScreenElement',
                'mozFullScreenEnabled',
                'mozfullscreenchange',
                'mozfullscreenerror'
            ],
            [
                'msRequestFullscreen',
                'msExitFullscreen',
                'msFullscreenElement',
                'msFullscreenEnabled',
                'MSFullscreenChange',
                'MSFullscreenError'
            ]
        ];

        var val;
        var ret = {};
        var i, j;

        for (i = 0; i < fnMap.length; i++) {
            val = fnMap[i];

            if (val && val[1] in document) {
                for (j = 0; j < val.length; j++) {
                    ret[fnMap[0][j]] = val[j];
                }

                return ret;
            }
        }

        return false;
    })();

    // If browser does not have Full Screen API, then simply unset default button template and stop
    if (!fn) {

        if ($ && $.fancybox) {
            $.fancybox.defaults.btnTpl.fullScreen = false;
        }

        return;
    }

    var FullScreen = {

        request: function (elem) {

            elem = elem || document.documentElement;

            elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);

        },
        exit: function () {

            document[fn.exitFullscreen]();

        },
        toggle: function (elem) {

            elem = elem || document.documentElement;

            if (this.isFullscreen()) {
                this.exit();

            } else {
                this.request(elem);
            }

        },
        isFullscreen: function () {

            return Boolean(document[fn.fullscreenElement]);

        },
        enabled: function () {

            return Boolean(document[fn.fullscreenEnabled]);

        }
    };

    $.extend(true, $.fancybox.defaults, {
        btnTpl: {
            fullScreen:
                '<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fullscreen" title="{{FULL_SCREEN}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M9,12 h22 v16 h-22 v-16 v16 h22 v-16 Z" />' +
                '</svg>' +
                '</button>'
        },
        fullScreen: {
            autoStart: false
        }
    });

    $(document).on({
        'onInit.fb': function (e, instance) {
            var $container;

            if (instance && instance.group[instance.currIndex].opts.fullScreen) {
                $container = instance.$refs.container;

                $container.on('click.fb-fullscreen', '[data-fancybox-fullscreen]', function (e) {

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

                    FullScreen.toggle($container[0]);

                });

                if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) {
                    FullScreen.request($container[0]);
                }

                // Expose API
                instance.FullScreen = FullScreen;

            } else if (instance) {
                instance.$refs.toolbar.find('[data-fancybox-fullscreen]').hide();
            }

        },

        'afterKeydown.fb': function (e, instance, current, keypress, keycode) {

            // "P" or Spacebar
            if (instance && instance.FullScreen && keycode === 70) {
                keypress.preventDefault();

                instance.FullScreen.toggle(instance.$refs.container[0]);
            }

        },

        'beforeClose.fb': function (instance) {
            if (instance && instance.FullScreen) {
                FullScreen.exit();
            }
        }
    });

    $(document).on(fn.fullscreenchange, function () {
        var isFullscreen = FullScreen.isFullscreen(),
            instance = $.fancybox.getInstance();

        if (instance) {

            // If image is zooming, then force to stop and reposition properly
            if (instance.current && instance.current.type === 'image' && instance.isAnimating) {
                instance.current.$content.css('transition', 'none');

                instance.isAnimating = false;

                instance.update(true, true, 0);
            }

            instance.trigger('onFullscreenChange', isFullscreen);

            instance.$refs.container.toggleClass('fancybox-is-fullscreen', isFullscreen);
        }

    });

}(document, window.jQuery || jQuery));

// ==========================================================================
//
// Thumbs
// Displays thumbnails in a grid
//
// ==========================================================================
; (function (document, $) {
    'use strict';

    // Make sure there are default values
    $.fancybox.defaults = $.extend(true, {
        btnTpl: {
            thumbs:
                '<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}">' +
                '<svg viewBox="0 0 120 120">' +
                '<path d="M30,30 h14 v14 h-14 Z M50,30 h14 v14 h-14 Z M70,30 h14 v14 h-14 Z M30,50 h14 v14 h-14 Z M50,50 h14 v14 h-14 Z M70,50 h14 v14 h-14 Z M30,70 h14 v14 h-14 Z M50,70 h14 v14 h-14 Z M70,70 h14 v14 h-14 Z" />' +
                '</svg>' +
                '</button>'
        },
        thumbs: {
            autoStart: false,                  // Display thumbnails on opening
            hideOnClose: true,                   // Hide thumbnail grid when closing animation starts
            parentEl: '.fancybox-container',  // Container is injected into this element
            axis: 'y'                     // Vertical (y) or horizontal (x) scrolling
        }
    }, $.fancybox.defaults);

    var FancyThumbs = function (instance) {
        this.init(instance);
    };

    $.extend(FancyThumbs.prototype, {

        $button: null,
        $grid: null,
        $list: null,
        isVisible: false,
        isActive: false,

        init: function (instance) {
            var self = this;

            self.instance = instance;

            instance.Thumbs = self;

            // Enable thumbs if at least two group items have thumbnails
            var first = instance.group[0],
                second = instance.group[1];

            self.opts = instance.group[instance.currIndex].opts.thumbs;

            self.$button = instance.$refs.toolbar.find('[data-fancybox-thumbs]');

            if (self.opts && first && second && (
                (first.type === 'image' || first.opts.thumb || first.opts.$thumb) &&
                (second.type === 'image' || second.opts.thumb || second.opts.$thumb)
            )) {

                self.$button.show().on('click', function () {
                    self.toggle();
                });

                self.isActive = true;

            } else {
                self.$button.hide();
            }
        },

        create: function () {
            var self = this,
                instance = self.instance,
                parentEl = self.opts.parentEl,
                list,
                src;

            self.$grid = $('<div class="fancybox-thumbs fancybox-thumbs-' + self.opts.axis + '"></div>').appendTo(instance.$refs.container.find(parentEl).addBack().filter(parentEl));

            // Build list HTML
            list = '<ul>';

            $.each(instance.group, function (i, item) {
                src = item.opts.thumb || (item.opts.$thumb ? item.opts.$thumb.attr('src') : null);

                if (!src && item.type === 'image') {
                    src = item.src;
                }

                if (src && src.length) {
                    list += '<li data-index="' + i + '"  tabindex="0" class="fancybox-thumbs-loading"><img data-src="' + src + '" /></li>';
                }
            });

            list += '</ul>';

            self.$list = $(list).appendTo(self.$grid).on('click', 'li', function () {
                instance.jumpTo($(this).data('index'));
            });

            self.$list.find('img').hide().one('load', function () {
                var $parent = $(this).parent().removeClass('fancybox-thumbs-loading'),
                    thumbWidth = $parent.outerWidth(),
                    thumbHeight = $parent.outerHeight(),
                    width,
                    height,
                    widthRatio,
                    heightRatio;

                width = this.naturalWidth || this.width;
                height = this.naturalHeight || this.height;

                // Calculate thumbnail dimensions; center vertically and horizontally
                widthRatio = width / thumbWidth;
                heightRatio = height / thumbHeight;

                if (widthRatio >= 1 && heightRatio >= 1) {
                    if (widthRatio > heightRatio) {
                        width = width / heightRatio;
                        height = thumbHeight;

                    } else {
                        width = thumbWidth;
                        height = height / widthRatio;
                    }
                }

                $(this).css({
                    width: Math.floor(width),
                    height: Math.floor(height),
                    'margin-top': height > thumbHeight ? (Math.floor(thumbHeight * 0.3 - height * 0.3)) : Math.floor(thumbHeight * 0.5 - height * 0.5),
                    'margin-left': Math.floor(thumbWidth * 0.5 - width * 0.5)
                }).show();

            })
                .each(function () {
                    this.src = $(this).data('src');
                });

            if (self.opts.axis === 'x') {
                self.$list.width(parseInt(self.$grid.css("padding-right")) + (instance.group.length * self.$list.children().eq(0).outerWidth(true)) + 'px');
            }
        },

        focus: function (duration) {
            var self = this,
                $list = self.$list,
                thumb,
                thumbPos;

            if (self.instance.current) {
                thumb = $list.children()
                    .removeClass('fancybox-thumbs-active')
                    .filter('[data-index="' + self.instance.current.index + '"]')
                    .addClass('fancybox-thumbs-active');

                thumbPos = thumb.position();

                // Check if need to scroll to make current thumb visible
                if (self.opts.axis === 'y' && (thumbPos.top < 0 || thumbPos.top > ($list.height() - thumb.outerHeight()))) {
                    $list.stop().animate({ 'scrollTop': $list.scrollTop() + thumbPos.top }, duration);

                } else if (self.opts.axis === 'x' && (
                    thumbPos.left < $list.parent().scrollLeft() ||
                    thumbPos.left > ($list.parent().scrollLeft() + ($list.parent().width() - thumb.outerWidth()))
                )
                ) {
                    $list.parent().stop().animate({ 'scrollLeft': thumbPos.left }, duration);
                }
            }
        },

        update: function () {
            this.instance.$refs.container.toggleClass('fancybox-show-thumbs', this.isVisible);

            if (this.isVisible) {
                if (!this.$grid) {
                    this.create();
                }

                this.instance.trigger('onThumbsShow');

                this.focus(0);

            } else if (this.$grid) {
                this.instance.trigger('onThumbsHide');
            }

            // Update content position
            this.instance.update();
        },

        hide: function () {
            this.isVisible = false;
            this.update();
        },

        show: function () {
            this.isVisible = true;
            this.update();
        },

        toggle: function () {
            this.isVisible = !this.isVisible;
            this.update();
        }
    });

    $(document).on({

        'onInit.fb': function (e, instance) {
            var Thumbs;

            if (instance && !instance.Thumbs) {
                Thumbs = new FancyThumbs(instance);

                if (Thumbs.isActive && Thumbs.opts.autoStart === true) {
                    Thumbs.show();
                }
            }
        },

        'beforeShow.fb': function (e, instance, item, firstRun) {
            var Thumbs = instance && instance.Thumbs;

            if (Thumbs && Thumbs.isVisible) {
                Thumbs.focus(firstRun ? 0 : 250);
            }
        },

        'afterKeydown.fb': function (e, instance, current, keypress, keycode) {
            var Thumbs = instance && instance.Thumbs;

            // "G"
            if (Thumbs && Thumbs.isActive && keycode === 71) {
                keypress.preventDefault();

                Thumbs.toggle();
            }
        },

        'beforeClose.fb': function (e, instance) {
            var Thumbs = instance && instance.Thumbs;

            if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {
                Thumbs.$grid.hide();
            }
        }

    });

}(document, window.jQuery));

//// ==========================================================================
//
// Share
// Displays simple form for sharing current url
//
// ==========================================================================
; (function (document, $) {
    'use strict';

    $.extend(true, $.fancybox.defaults, {
        btnTpl: {
            share:
                '<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}">' +
                '<svg viewBox="0 0 40 40">' +
                '<path d="M6,30 C8,18 19,16 23,16 L23,16 L23,10 L33,20 L23,29 L23,24 C19,24 8,27 6,30 Z">' +
                '</svg>' +
                '</button>'
        },
        share: {
            tpl:
                '<div class="fancybox-share">' +
                '<h1>{{SHARE}}</h1>' +
                '<p class="fancybox-share__links">' +
                '<a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}">' +
                '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196" /></svg>' +
                '<span>Facebook</span>' +
                '</a>' +
                '<a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}">' +
                '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z" fill="#fff"/></svg>' +
                '<span>Pinterest</span>' +
                '</a>' +
                '<a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}">' +
                '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z" /></svg>' +
                '<span>Twitter</span>' +
                '</a>' +
                '</p>' +
                '<p><input class="fancybox-share__input" type="text" value="{{url_raw}}" /></p>' +
                '</div>'
        }
    });

    function escapeHtml(string) {
        var entityMap = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#39;',
            '/': '&#x2F;',
            '`': '&#x60;',
            '=': '&#x3D;'
        };

        return String(string).replace(/[&<>"'`=]/g, function (s) {
            return entityMap[s];
        });
    }

    $(document).on('click', '[data-fancybox-share]', function () {
        var f = $.fancybox.getInstance(),
            url,
            tpl;

        if (f) {
            url = f.current.opts.hash === false ? f.current.src : window.location;
            tpl = f.current.opts.share.tpl
                .replace(/\{\{media\}\}/g, f.current.type === 'image' ? encodeURIComponent(f.current.src) : '')
                .replace(/\{\{url\}\}/g, encodeURIComponent(url))
                .replace(/\{\{url_raw\}\}/g, escapeHtml(url))
                .replace(/\{\{descr\}\}/g, f.$caption ? encodeURIComponent(f.$caption.text()) : '');

            $.fancybox.open({
                src: f.translate(f, tpl),
                type: 'html',
                opts: {
                    animationEffect: "fade",
                    animationDuration: 250,
                    afterLoad: function (instance, current) {
                        // Opening links in a popup window
                        current.$content.find('.fancybox-share__links a').click(function () {
                            window.open(this.href, "Share", "width=550, height=450");
                            return false;
                        });
                    }
                }
            });
        }

    });

}(document, window.jQuery || jQuery));

// ==========================================================================
//
// Hash
// Enables linking to each modal
//
// ==========================================================================
; (function (document, window, $) {
    'use strict';

    // Simple $.escapeSelector polyfill (for jQuery prior v3)
    if (!$.escapeSelector) {
        $.escapeSelector = function (sel) {
            var rcssescape = /([\0-\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
            var fcssescape = function (ch, asCodePoint) {
                if (asCodePoint) {
                    // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
                    if (ch === "\0") {
                        return "\uFFFD";
                    }

                    // Control characters and (dependent upon position) numbers get escaped as code points
                    return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
                }

                // Other potentially-special ASCII characters get backslash-escaped
                return "\\" + ch;
            };

            return (sel + "").replace(rcssescape, fcssescape);
        };
    }

    // Create new history entry only once
    var shouldCreateHistory = true;

    // Variable containing last hash value set by fancyBox
    // It will be used to determine if fancyBox needs to close after hash change is detected
    var currentHash = null;

    // Throttling the history change
    var timerID = null;

    // Get info about gallery name and current index from url
    function parseUrl() {
        var hash = window.location.hash.substr(1);
        var rez = hash.split('-');
        var index = rez.length > 1 && /^\+?\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1;
        var gallery = rez.join('-');

        // Index is starting from 1
        if (index < 1) {
            index = 1;
        }

        return {
            hash: hash,
            index: index,
            gallery: gallery
        };
    }

    // Trigger click evnt on links to open new fancyBox instance
    function triggerFromUrl(url) {
        var $el;

        if (url.gallery !== '') {

            // If we can find element matching 'data-fancybox' atribute, then trigger click event for that ..
            $el = $("[data-fancybox='" + $.escapeSelector(url.gallery) + "']").eq(url.index - 1);

            if (!$el.length) {
                // .. if not, try finding element by ID
                $el = $("#" + $.escapeSelector(url.gallery) + "");
            }

            if ($el.length) {
                shouldCreateHistory = false;

                $el.trigger('click');
            }

        }
    }

    // Get gallery name from current instance
    function getGalleryID(instance) {
        var opts;

        if (!instance) {
            return false;
        }

        opts = instance.current ? instance.current.opts : instance.opts;

        return opts.hash || (opts.$orig ? opts.$orig.data('fancybox') : '');
    }

    // Start when DOM becomes ready
    $(function () {

        // Check if user has disabled this module
        if ($.fancybox.defaults.hash === false) {
            return;
        }

        // Update hash when opening/closing fancyBox
        $(document).on({
            'onInit.fb': function (e, instance) {
                var url, gallery;

                if (instance.group[instance.currIndex].opts.hash === false) {
                    return;
                }

                url = parseUrl();
                gallery = getGalleryID(instance);

                // Make sure gallery start index matches index from hash
                if (gallery && url.gallery && gallery === url.gallery) {
                    instance.currIndex = url.index - 1;
                }
            },

            'beforeShow.fb': function (e, instance, current) {
                var gallery;

                if (!current || current.opts.hash === false) {
                    return;
                }

                gallery = getGalleryID(instance);

                // Update window hash
                if (gallery && gallery !== '') {

                    if (window.location.hash.indexOf(gallery) < 0) {
                        instance.opts.origHash = window.location.hash;
                    }

                    currentHash = gallery + (instance.group.length > 1 ? '-' + (current.index + 1) : '');

                    if ('replaceState' in window.history) {
                        if (timerID) {
                            clearTimeout(timerID);
                        }

                        timerID = setTimeout(function () {
                            window.history[shouldCreateHistory ? 'pushState' : 'replaceState']({}, document.title, window.location.pathname + window.location.search + '#' + currentHash);

                            timerID = null;

                            shouldCreateHistory = false;

                        }, 300);

                    } else {
                        window.location.hash = currentHash;
                    }

                }

            },

            'beforeClose.fb': function (e, instance, current) {
                var gallery, origHash;

                if (timerID) {
                    clearTimeout(timerID);
                }

                if (current.opts.hash === false) {
                    return;
                }

                gallery = getGalleryID(instance);
                origHash = instance && instance.opts.origHash ? instance.opts.origHash : '';

                // Remove hash from location bar
                if (gallery && gallery !== '') {

                    if ('replaceState' in history) {
                        window.history.replaceState({}, document.title, window.location.pathname + window.location.search + origHash);

                    } else {
                        window.location.hash = origHash;

                        // Keep original scroll position
                        $(window).scrollTop(instance.scrollTop).scrollLeft(instance.scrollLeft);
                    }
                }

                currentHash = null;
            }
        });

        // Check if need to close after url has changed
        $(window).on('hashchange.fb', function () {
            var url = parseUrl();

            if ($.fancybox.getInstance()) {
                if (currentHash && currentHash !== url.gallery + '-' + url.index && !(url.index === 1 && currentHash === url.gallery)) {
                    currentHash = null;

                    $.fancybox.close();
                }

            } else if (url.gallery !== '') {
                triggerFromUrl(url);
            }
        });

        // Check current hash and trigger click event on matching element to start fancyBox, if needed
        setTimeout(function () {
            triggerFromUrl(parseUrl());
        }, 50);
    });

}(document, window, window.jQuery || jQuery));

; (function (document, $) {
    'use strict';

    var prevTime = new Date().getTime();

    $(document).on({
        'onInit.fb': function (e, instance, current) {
            instance.$refs.stage.on('mousewheel DOMMouseScroll wheel MozMousePixelScroll', function (e) {
                var current = instance.current,
                    currTime = new Date().getTime();

                if (instance.group.length < 1 || current.opts.wheel === false || (current.opts.wheel === 'auto' && current.type !== 'image')) {
                    return;
                }

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

                if (current.$slide.hasClass('fancybox-animated')) {
                    return;
                }

                e = e.originalEvent || e;

                if (currTime - prevTime < 250) {
                    return;
                }

                prevTime = currTime;

                instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? 'next' : 'previous']();

            });
        }
    });

}(document, window.jQuery || jQuery));
