/* Minification failed. Returning unminified contents.
(9388,57-58): run-time error JS1195: Expected expression: )
(9388,60-61): run-time error JS1195: Expected expression: >
(9392,10-11): run-time error JS1195: Expected expression: )
(9428,1-2): run-time error JS1002: Syntax error: }
(9435,47-48): run-time error JS1004: Expected ';': {
(9728,2-3): run-time error JS1195: Expected expression: )
 */
/*!
 * mustache.js - Logic-less {{mustache}} templates with JavaScript
 * http://github.com/janl/mustache.js
 */

/*global define: false Mustache: true*/

(function defineMustache (global, factory) {
  if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') {
    factory(exports); // CommonJS
  } else if (typeof define === 'function' && define.amd) {
    define(['exports'], factory); // AMD
  } else {
    global.Mustache = {};
    factory(global.Mustache); // script, wsh, asp
  }
}(this, function mustacheFactory (mustache) {

  var objectToString = Object.prototype.toString;
  var isArray = Array.isArray || function isArrayPolyfill (object) {
    return objectToString.call(object) === '[object Array]';
  };

  function isFunction (object) {
    return typeof object === 'function';
  }

  /**
   * More correct typeof string handling array
   * which normally returns typeof 'object'
   */
  function typeStr (obj) {
    return isArray(obj) ? 'array' : typeof obj;
  }

  function escapeRegExp (string) {
    return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
  }

  /**
   * Null safe way of checking whether or not an object,
   * including its prototype, has a given property
   */
  function hasProperty (obj, propName) {
    return obj != null && typeof obj === 'object' && (propName in obj);
  }

  // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
  // See https://github.com/janl/mustache.js/issues/189
  var regExpTest = RegExp.prototype.test;
  function testRegExp (re, string) {
    return regExpTest.call(re, string);
  }

  var nonSpaceRe = /\S/;
  function isWhitespace (string) {
    return !testRegExp(nonSpaceRe, string);
  }

  var entityMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '/': '&#x2F;',
    '`': '&#x60;',
    '=': '&#x3D;'
  };

  function escapeHtml (string) {
    return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
      return entityMap[s];
    });
  }

  var whiteRe = /\s*/;
  var spaceRe = /\s+/;
  var equalsRe = /\s*=/;
  var curlyRe = /\s*\}/;
  var tagRe = /#|\^|\/|>|\{|&|=|!/;

  /**
   * Breaks up the given `template` string into a tree of tokens. If the `tags`
   * argument is given here it must be an array with two string values: the
   * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
   * course, the default is to use mustaches (i.e. mustache.tags).
   *
   * A token is an array with at least 4 elements. The first element is the
   * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
   * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
   * all text that appears outside a symbol this element is "text".
   *
   * The second element of a token is its "value". For mustache tags this is
   * whatever else was inside the tag besides the opening symbol. For text tokens
   * this is the text itself.
   *
   * The third and fourth elements of the token are the start and end indices,
   * respectively, of the token in the original template.
   *
   * Tokens that are the root node of a subtree contain two more elements: 1) an
   * array of tokens in the subtree and 2) the index in the original template at
   * which the closing tag for that section begins.
   */
  function parseTemplate (template, tags) {
    if (!template)
      return [];

    var sections = [];     // Stack to hold section tokens
    var tokens = [];       // Buffer to hold the tokens
    var spaces = [];       // Indices of whitespace tokens on the current line
    var hasTag = false;    // Is there a {{tag}} on the current line?
    var nonSpace = false;  // Is there a non-space char on the current line?

    // Strips all whitespace tokens array for the current line
    // if there was a {{#tag}} on it and otherwise only space.
    function stripSpace () {
      if (hasTag && !nonSpace) {
        while (spaces.length)
          delete tokens[spaces.pop()];
      } else {
        spaces = [];
      }

      hasTag = false;
      nonSpace = false;
    }

    var openingTagRe, closingTagRe, closingCurlyRe;
    function compileTags (tagsToCompile) {
      if (typeof tagsToCompile === 'string')
        tagsToCompile = tagsToCompile.split(spaceRe, 2);

      if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
        throw new Error('Invalid tags: ' + tagsToCompile);

      openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
      closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
      closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
    }

    compileTags(tags || mustache.tags);

    var scanner = new Scanner(template);

    var start, type, value, chr, token, openSection;
    while (!scanner.eos()) {
      start = scanner.pos;

      // Match any text between tags.
      value = scanner.scanUntil(openingTagRe);

      if (value) {
        for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
          chr = value.charAt(i);

          if (isWhitespace(chr)) {
            spaces.push(tokens.length);
          } else {
            nonSpace = true;
          }

          tokens.push([ 'text', chr, start, start + 1 ]);
          start += 1;

          // Check for whitespace on the current line.
          if (chr === '\n')
            stripSpace();
        }
      }

      // Match the opening tag.
      if (!scanner.scan(openingTagRe))
        break;

      hasTag = true;

      // Get the tag type.
      type = scanner.scan(tagRe) || 'name';
      scanner.scan(whiteRe);

      // Get the tag value.
      if (type === '=') {
        value = scanner.scanUntil(equalsRe);
        scanner.scan(equalsRe);
        scanner.scanUntil(closingTagRe);
      } else if (type === '{') {
        value = scanner.scanUntil(closingCurlyRe);
        scanner.scan(curlyRe);
        scanner.scanUntil(closingTagRe);
        type = '&';
      } else {
        value = scanner.scanUntil(closingTagRe);
      }

      // Match the closing tag.
      if (!scanner.scan(closingTagRe))
        throw new Error('Unclosed tag at ' + scanner.pos);

      token = [ type, value, start, scanner.pos ];
      tokens.push(token);

      if (type === '#' || type === '^') {
        sections.push(token);
      } else if (type === '/') {
        // Check section nesting.
        openSection = sections.pop();

        if (!openSection)
          throw new Error('Unopened section "' + value + '" at ' + start);

        if (openSection[1] !== value)
          throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
      } else if (type === 'name' || type === '{' || type === '&') {
        nonSpace = true;
      } else if (type === '=') {
        // Set the tags for the next time around.
        compileTags(value);
      }
    }

    // Make sure there are no open sections when we're done.
    openSection = sections.pop();

    if (openSection)
      throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);

    return nestTokens(squashTokens(tokens));
  }

  /**
   * Combines the values of consecutive text tokens in the given `tokens` array
   * to a single token.
   */
  function squashTokens (tokens) {
    var squashedTokens = [];

    var token, lastToken;
    for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
      token = tokens[i];

      if (token) {
        if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
          lastToken[1] += token[1];
          lastToken[3] = token[3];
        } else {
          squashedTokens.push(token);
          lastToken = token;
        }
      }
    }

    return squashedTokens;
  }

  /**
   * Forms the given array of `tokens` into a nested tree structure where
   * tokens that represent a section have two additional items: 1) an array of
   * all tokens that appear in that section and 2) the index in the original
   * template that represents the end of that section.
   */
  function nestTokens (tokens) {
    var nestedTokens = [];
    var collector = nestedTokens;
    var sections = [];

    var token, section;
    for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
      token = tokens[i];

      switch (token[0]) {
        case '#':
        case '^':
          collector.push(token);
          sections.push(token);
          collector = token[4] = [];
          break;
        case '/':
          section = sections.pop();
          section[5] = token[2];
          collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
          break;
        default:
          collector.push(token);
      }
    }

    return nestedTokens;
  }

  /**
   * A simple string scanner that is used by the template parser to find
   * tokens in template strings.
   */
  function Scanner (string) {
    this.string = string;
    this.tail = string;
    this.pos = 0;
  }

  /**
   * Returns `true` if the tail is empty (end of string).
   */
  Scanner.prototype.eos = function eos () {
    return this.tail === '';
  };

  /**
   * Tries to match the given regular expression at the current position.
   * Returns the matched text if it can match, the empty string otherwise.
   */
  Scanner.prototype.scan = function scan (re) {
    var match = this.tail.match(re);

    if (!match || match.index !== 0)
      return '';

    var string = match[0];

    this.tail = this.tail.substring(string.length);
    this.pos += string.length;

    return string;
  };

  /**
   * Skips all text until the given regular expression can be matched. Returns
   * the skipped string, which is the entire tail if no match can be made.
   */
  Scanner.prototype.scanUntil = function scanUntil (re) {
    var index = this.tail.search(re), match;

    switch (index) {
      case -1:
        match = this.tail;
        this.tail = '';
        break;
      case 0:
        match = '';
        break;
      default:
        match = this.tail.substring(0, index);
        this.tail = this.tail.substring(index);
    }

    this.pos += match.length;

    return match;
  };

  /**
   * Represents a rendering context by wrapping a view object and
   * maintaining a reference to the parent context.
   */
  function Context (view, parentContext) {
    this.view = view;
    this.cache = { '.': this.view };
    this.parent = parentContext;
  }

  /**
   * Creates a new context using the given view with this context
   * as the parent.
   */
  Context.prototype.push = function push (view) {
    return new Context(view, this);
  };

  /**
   * Returns the value of the given name in this context, traversing
   * up the context hierarchy if the value is absent in this context's view.
   */
  Context.prototype.lookup = function lookup (name) {
    var cache = this.cache;

    var value;
    if (cache.hasOwnProperty(name)) {
      value = cache[name];
    } else {
      var context = this, names, index, lookupHit = false;

      while (context) {
        if (name.indexOf('.') > 0) {
          value = context.view;
          names = name.split('.');
          index = 0;

          /**
           * Using the dot notion path in `name`, we descend through the
           * nested objects.
           *
           * To be certain that the lookup has been successful, we have to
           * check if the last object in the path actually has the property
           * we are looking for. We store the result in `lookupHit`.
           *
           * This is specially necessary for when the value has been set to
           * `undefined` and we want to avoid looking up parent contexts.
           **/
          while (value != null && index < names.length) {
            if (index === names.length - 1)
              lookupHit = hasProperty(value, names[index]);

            value = value[names[index++]];
          }
        } else {
          value = context.view[name];
          lookupHit = hasProperty(context.view, name);
        }

        if (lookupHit)
          break;

        context = context.parent;
      }

      cache[name] = value;
    }

    if (isFunction(value))
      value = value.call(this.view);

    return value;
  };

  /**
   * A Writer knows how to take a stream of tokens and render them to a
   * string, given a context. It also maintains a cache of templates to
   * avoid the need to parse the same template twice.
   */
  function Writer () {
    this.cache = {};
  }

  /**
   * Clears all cached templates in this writer.
   */
  Writer.prototype.clearCache = function clearCache () {
    this.cache = {};
  };

  /**
   * Parses and caches the given `template` and returns the array of tokens
   * that is generated from the parse.
   */
  Writer.prototype.parse = function parse (template, tags) {
    var cache = this.cache;
    var tokens = cache[template];

    if (tokens == null)
      tokens = cache[template] = parseTemplate(template, tags);

    return tokens;
  };

  /**
   * High-level method that is used to render the given `template` with
   * the given `view`.
   *
   * The optional `partials` argument may be an object that contains the
   * names and templates of partials that are used in the template. It may
   * also be a function that is used to load partial templates on the fly
   * that takes a single argument: the name of the partial.
   */
  Writer.prototype.render = function render (template, view, partials) {
    var tokens = this.parse(template);
    var context = (view instanceof Context) ? view : new Context(view);
    return this.renderTokens(tokens, context, partials, template);
  };

  /**
   * Low-level method that renders the given array of `tokens` using
   * the given `context` and `partials`.
   *
   * Note: The `originalTemplate` is only ever used to extract the portion
   * of the original template that was contained in a higher-order section.
   * If the template doesn't use higher-order sections, this argument may
   * be omitted.
   */
  Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate) {
    var buffer = '';

    var token, symbol, value;
    for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
      value = undefined;
      token = tokens[i];
      symbol = token[0];

      if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
      else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
      else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);
      else if (symbol === '&') value = this.unescapedValue(token, context);
      else if (symbol === 'name') value = this.escapedValue(token, context);
      else if (symbol === 'text') value = this.rawValue(token);

      if (value !== undefined)
        buffer += value;
    }

    return buffer;
  };

  Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) {
    var self = this;
    var buffer = '';
    var value = context.lookup(token[1]);

    // This function is used to render an arbitrary template
    // in the current context by higher-order sections.
    function subRender (template) {
      return self.render(template, context, partials);
    }

    if (!value) return;

    if (isArray(value)) {
      for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
        buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
      }
    } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
      buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
    } else if (isFunction(value)) {
      if (typeof originalTemplate !== 'string')
        throw new Error('Cannot use higher-order sections without the original template');

      // Extract the portion of the original template that the section contains.
      value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);

      if (value != null)
        buffer += value;
    } else {
      buffer += this.renderTokens(token[4], context, partials, originalTemplate);
    }
    return buffer;
  };

  Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) {
    var value = context.lookup(token[1]);

    // Use JavaScript's definition of falsy. Include empty arrays.
    // See https://github.com/janl/mustache.js/issues/186
    if (!value || (isArray(value) && value.length === 0))
      return this.renderTokens(token[4], context, partials, originalTemplate);
  };

  Writer.prototype.renderPartial = function renderPartial (token, context, partials) {
    if (!partials) return;

    var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
    if (value != null)
      return this.renderTokens(this.parse(value), context, partials, value);
  };

  Writer.prototype.unescapedValue = function unescapedValue (token, context) {
    var value = context.lookup(token[1]);
    if (value != null)
      return value;
  };

  Writer.prototype.escapedValue = function escapedValue (token, context) {
    var value = context.lookup(token[1]);
    if (value != null)
      return mustache.escape(value);
  };

  Writer.prototype.rawValue = function rawValue (token) {
    return token[1];
  };

  mustache.name = 'mustache.js';
  mustache.version = '2.2.1';
  mustache.tags = [ '{{', '}}' ];

  // All high-level mustache.* functions use this writer.
  var defaultWriter = new Writer();

  /**
   * Clears all cached templates in the default writer.
   */
  mustache.clearCache = function clearCache () {
    return defaultWriter.clearCache();
  };

  /**
   * Parses and caches the given template in the default writer and returns the
   * array of tokens it contains. Doing this ahead of time avoids the need to
   * parse templates on the fly as they are rendered.
   */
  mustache.parse = function parse (template, tags) {
    return defaultWriter.parse(template, tags);
  };

  /**
   * Renders the `template` with the given `view` and `partials` using the
   * default writer.
   */
  mustache.render = function render (template, view, partials) {
    if (typeof template !== 'string') {
      throw new TypeError('Invalid template! Template should be a "string" ' +
                          'but "' + typeStr(template) + '" was given as the first ' +
                          'argument for mustache#render(template, view, partials)');
    }

    return defaultWriter.render(template, view, partials);
  };

  // This is here for backwards compatibility with 0.4.x.,
  /*eslint-disable */ // eslint wants camel cased function name
  mustache.to_html = function to_html (template, view, partials, send) {
    /*eslint-enable*/

    var result = mustache.render(template, view, partials);

    if (isFunction(send)) {
      send(result);
    } else {
      return result;
    }
  };

  // Export the escaping function so that the user may override it.
  // See https://github.com/janl/mustache.js/issues/244
  mustache.escape = escapeHtml;

  // Export these mainly for testing, but also for advanced usage.
  mustache.Scanner = Scanner;
  mustache.Context = Context;
  mustache.Writer = Writer;

}));;
/*global jQuery */
/*jshint browser:true */
/*!
* FitVids 1.1
*
* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
* Released under the WTFPL license - http://sam.zoy.org/wtfpl/
*
*/

(function ($) {

    "use strict";

    $.fn.fitVids = function (options) {
        var settings = {
            customSelector: null,
            ignore: null,
        };

        if (!document.getElementById('fit-vids-style')) {
            // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
            var head = document.head || document.getElementsByTagName('head')[0];
            var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
            var div = document.createElement('div');
            div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
            head.appendChild(div.childNodes[1]);
        }

        if (options) {
            $.extend(settings, options);
        }

        return this.each(function () {
            var selectors = [
              "iframe[src*='player.vimeo.com']",
              "iframe[src*='youtube.com']",
              "iframe[src*='youtube-nocookie.com']",
              "iframe[src*='kickstarter.com'][src*='video.html']",
              "iframe[src^='http://fast.wistia.com']",
              "object",
              "embed"
            ];

            if (settings.customSelector) {
                selectors.push(settings.customSelector);
            }

            var ignoreList = '.fitvidsignore';

            if (settings.ignore) {
                ignoreList = ignoreList + ', ' + settings.ignore;
            }

            var $allVideos = $(this).find(selectors.join(','));
            $allVideos = $allVideos.not("object object"); // SwfObj conflict patch
            $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.

            $allVideos.each(function () {
                var $this = $(this);
                if ($this.parents(ignoreList).length > 0) {
                    return; // Disable FitVids on this video.
                }
                if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
                if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width')))) {
                    $this.attr('height', 9);
                    $this.attr('width', 16);
                }
                var height = (this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10)))) ? parseInt($this.attr('height'), 10) : $this.height(),
                    width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
                    aspectRatio = height / width;
                if (!$this.attr('id')) {
                    var videoID = 'fitvid' + Math.floor(Math.random() * 999999);
                    $this.attr('id', videoID);
                }
                $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100) + "%");
                $this.removeAttr('height').removeAttr('width');
            });
        });
    };
    // Works with either jQuery or Zepto
})(window.jQuery || window.Zepto);;
/*!
 * Datepicker for Bootstrap v1.8.0 (https://github.com/uxsolutions/bootstrap-datepicker)
 *
 * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}(function ($, undefined) {
    function UTCDate() {
        return new Date(Date.UTC.apply(Date, arguments));
    }
    function UTCToday() {
        var today = new Date();
        return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
    }
    function isUTCEquals(date1, date2) {
        return (
            date1.getUTCFullYear() === date2.getUTCFullYear() &&
            date1.getUTCMonth() === date2.getUTCMonth() &&
            date1.getUTCDate() === date2.getUTCDate()
        );
    }
    function alias(method, deprecationMsg) {
        return function () {
            if (deprecationMsg !== undefined) {
                $.fn.datepicker.deprecated(deprecationMsg);
            }

            return this[method].apply(this, arguments);
        };
    }
    function isValidDate(d) {
        return d && !isNaN(d.getTime());
    }

    var DateArray = (function () {
        var extras = {
            get: function (i) {
                return this.slice(i)[0];
            },
            contains: function (d) {
                // Array.indexOf is not cross-browser;
                // $.inArray doesn't work with Dates
                var val = d && d.valueOf();
                for (var i = 0, l = this.length; i < l; i++)
                    // Use date arithmetic to allow dates with different times to match
                    if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000 * 60 * 60 * 24)
                        return i;
                return -1;
            },
            remove: function (i) {
                this.splice(i, 1);
            },
            replace: function (new_array) {
                if (!new_array)
                    return;
                if (!$.isArray(new_array))
                    new_array = [new_array];
                this.clear();
                this.push.apply(this, new_array);
            },
            clear: function () {
                this.length = 0;
            },
            copy: function () {
                var a = new DateArray();
                a.replace(this);
                return a;
            }
        };

        return function () {
            var a = [];
            a.push.apply(a, arguments);
            $.extend(a, extras);
            return a;
        };
    })();


    // Picker object

    var Datepicker = function (element, options) {
        $.data(element, 'datepicker', this);
        this._process_options(options);

        this.dates = new DateArray();
        this.viewDate = this.o.defaultViewDate;
        this.focusDate = null;

        this.element = $(element);
        this.isInput = this.element.is('input');
        this.inputField = this.isInput ? this.element : this.element.find('input');
        this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
        if (this.component && this.component.length === 0)
            this.component = false;
        this.isInline = !this.component && this.element.is('div');

        this.picker = $(DPGlobal.template);

        // Checking templates and inserting
        if (this._check_template(this.o.templates.leftArrow)) {
            this.picker.find('.prev').html(this.o.templates.leftArrow);
        }

        if (this._check_template(this.o.templates.rightArrow)) {
            this.picker.find('.next').html(this.o.templates.rightArrow);
        }

        this._buildEvents();
        this._attachEvents();

        if (this.isInline) {
            this.picker.addClass('datepicker-inline').appendTo(this.element);
        }
        else {
            this.picker.addClass('datepicker-dropdown dropdown-menu');
        }

        if (this.o.rtl) {
            this.picker.addClass('datepicker-rtl');
        }

        if (this.o.calendarWeeks) {
            this.picker.find('.datepicker-days .switch, thead .datepicker-title, tfoot .today, tfoot .clear')
                .attr('colspan', function (i, val) {
                    return Number(val) + 1;
                });
        }

        this._process_options({
            startDate: this._o.startDate,
            endDate: this._o.endDate,
            daysOfWeekDisabled: this.o.daysOfWeekDisabled,
            daysOfWeekHighlighted: this.o.daysOfWeekHighlighted,
            datesDisabled: this.o.datesDisabled
        });

        this._allow_update = false;
        this.setViewMode(this.o.startView);
        this._allow_update = true;

        this.fillDow();
        this.fillMonths();

        this.update();

        if (this.isInline) {
            this.show();
        }
    };

    Datepicker.prototype = {
        constructor: Datepicker,

        _resolveViewName: function (view) {
            $.each(DPGlobal.viewModes, function (i, viewMode) {
                if (view === i || $.inArray(view, viewMode.names) !== -1) {
                    view = i;
                    return false;
                }
            });

            return view;
        },

        _resolveDaysOfWeek: function (daysOfWeek) {
            if (!$.isArray(daysOfWeek))
                daysOfWeek = daysOfWeek.split(/[,\s]*/);
            return $.map(daysOfWeek, Number);
        },

        _check_template: function (tmp) {
            try {
                // If empty
                if (tmp === undefined || tmp === "") {
                    return false;
                }
                // If no html, everything ok
                if ((tmp.match(/[<>]/g) || []).length <= 0) {
                    return true;
                }
                // Checking if html is fine
                var jDom = $(tmp);
                return jDom.length > 0;
            }
            catch (ex) {
                return false;
            }
        },

        _process_options: function (opts) {
            // Store raw options for reference
            this._o = $.extend({}, this._o, opts);
            // Processed options
            var o = this.o = $.extend({}, this._o);

            // Check if "de-DE" style date is available, if not language should
            // fallback to 2 letter code eg "de"
            var lang = o.language;
            if (!dates[lang]) {
                lang = lang.split('-')[0];
                if (!dates[lang])
                    lang = defaults.language;
            }
            o.language = lang;

            // Retrieve view index from any aliases
            o.startView = this._resolveViewName(o.startView);
            o.minViewMode = this._resolveViewName(o.minViewMode);
            o.maxViewMode = this._resolveViewName(o.maxViewMode);

            // Check view is between min and max
            o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));

            // true, false, or Number > 0
            if (o.multidate !== true) {
                o.multidate = Number(o.multidate) || false;
                if (o.multidate !== false)
                    o.multidate = Math.max(0, o.multidate);
            }
            o.multidateSeparator = String(o.multidateSeparator);

            o.weekStart %= 7;
            o.weekEnd = (o.weekStart + 6) % 7;

            var format = DPGlobal.parseFormat(o.format);
            if (o.startDate !== -Infinity) {
                if (!!o.startDate) {
                    if (o.startDate instanceof Date)
                        o.startDate = this._local_to_utc(this._zero_time(o.startDate));
                    else
                        o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
                }
                else {
                    o.startDate = -Infinity;
                }
            }
            if (o.endDate !== Infinity) {
                if (!!o.endDate) {
                    if (o.endDate instanceof Date)
                        o.endDate = this._local_to_utc(this._zero_time(o.endDate));
                    else
                        o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
                }
                else {
                    o.endDate = Infinity;
                }
            }

            o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled || []);
            o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted || []);

            o.datesDisabled = o.datesDisabled || [];
            if (!$.isArray(o.datesDisabled)) {
                o.datesDisabled = o.datesDisabled.split(',');
            }
            o.datesDisabled = $.map(o.datesDisabled, function (d) {
                return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
            });

            var plc = String(o.orientation).toLowerCase().split(/\s+/g),
                _plc = o.orientation.toLowerCase();
            plc = $.grep(plc, function (word) {
                return /^auto|left|right|top|bottom$/.test(word);
            });
            o.orientation = { x: 'auto', y: 'auto' };
            if (!_plc || _plc === 'auto')
                ; // no action
            else if (plc.length === 1) {
                switch (plc[0]) {
                    case 'top':
                    case 'bottom':
                        o.orientation.y = plc[0];
                        break;
                    case 'left':
                    case 'right':
                        o.orientation.x = plc[0];
                        break;
                }
            }
            else {
                _plc = $.grep(plc, function (word) {
                    return /^left|right$/.test(word);
                });
                o.orientation.x = _plc[0] || 'auto';

                _plc = $.grep(plc, function (word) {
                    return /^top|bottom$/.test(word);
                });
                o.orientation.y = _plc[0] || 'auto';
            }
            if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {
                o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);
            } else if (o.defaultViewDate) {
                var year = o.defaultViewDate.year || new Date().getFullYear();
                var month = o.defaultViewDate.month || 0;
                var day = o.defaultViewDate.day || 1;
                o.defaultViewDate = UTCDate(year, month, day);
            } else {
                o.defaultViewDate = UTCToday();
            }
        },
        _events: [],
        _secondaryEvents: [],
        _applyEvents: function (evs) {
            for (var i = 0, el, ch, ev; i < evs.length; i++) {
                el = evs[i][0];
                if (evs[i].length === 2) {
                    ch = undefined;
                    ev = evs[i][1];
                } else if (evs[i].length === 3) {
                    ch = evs[i][1];
                    ev = evs[i][2];
                }
                el.on(ev, ch);
            }
        },
        _unapplyEvents: function (evs) {
            for (var i = 0, el, ev, ch; i < evs.length; i++) {
                el = evs[i][0];
                if (evs[i].length === 2) {
                    ch = undefined;
                    ev = evs[i][1];
                } else if (evs[i].length === 3) {
                    ch = evs[i][1];
                    ev = evs[i][2];
                }
                el.off(ev, ch);
            }
        },
        _buildEvents: function () {
            var events = {
                keyup: $.proxy(function (e) {
                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                        this.update();
                }, this),
                keydown: $.proxy(this.keydown, this),
                paste: $.proxy(this.paste, this)
            };

            if (this.o.showOnFocus === true) {
                events.focus = $.proxy(this.show, this);
            }

            if (this.isInput) { // single input
                this._events = [
                    [this.element, events]
                ];
            }
            // component: input + button
            else if (this.component && this.inputField.length) {
                this._events = [
                    // For components that are not readonly, allow keyboard nav
                    [this.inputField, events],
                    [this.component, {
                        click: $.proxy(this.show, this)
                    }]
                ];
            }
            else {
                this._events = [
                    [this.element, {
                        click: $.proxy(this.show, this),
                        keydown: $.proxy(this.keydown, this)
                    }]
                ];
            }
            this._events.push(
                // Component: listen for blur on element descendants
                [this.element, '*', {
                    blur: $.proxy(function (e) {
                        this._focused_from = e.target;
                    }, this)
                }],
                // Input: listen for blur on element
                [this.element, {
                    blur: $.proxy(function (e) {
                        this._focused_from = e.target;
                    }, this)
                }]
            );

            if (this.o.immediateUpdates) {
                // Trigger input updates immediately on changed year/month
                this._events.push([this.element, {
                    'changeYear changeMonth': $.proxy(function (e) {
                        this.update(e.date);
                    }, this)
                }]);
            }

            this._secondaryEvents = [
                [this.picker, {
                    click: $.proxy(this.click, this)
                }],
                [this.picker, '.prev, .next', {
                    click: $.proxy(this.navArrowsClick, this)
                }],
                [this.picker, '.day:not(.disabled)', {
                    click: $.proxy(this.dayCellClick, this)
                }],
                [$(window), {
                    resize: $.proxy(this.place, this)
                }],
                [$(document), {
                    'mousedown touchstart': $.proxy(function (e) {
                        // Clicked outside the datepicker, hide it
                        if (!(
                            this.element.is(e.target) ||
                            this.element.find(e.target).length ||
                            this.picker.is(e.target) ||
                            this.picker.find(e.target).length ||
                            this.isInline
                        )) {
                            this.hide();
                        }
                    }, this)
                }]
            ];
        },
        _attachEvents: function () {
            this._detachEvents();
            this._applyEvents(this._events);
        },
        _detachEvents: function () {
            this._unapplyEvents(this._events);
        },
        _attachSecondaryEvents: function () {
            this._detachSecondaryEvents();
            this._applyEvents(this._secondaryEvents);
        },
        _detachSecondaryEvents: function () {
            this._unapplyEvents(this._secondaryEvents);
        },
        _trigger: function (event, altdate) {
            var date = altdate || this.dates.get(-1),
                local_date = this._utc_to_local(date);

            this.element.trigger({
                type: event,
                date: local_date,
                viewMode: this.viewMode,
                dates: $.map(this.dates, this._utc_to_local),
                format: $.proxy(function (ix, format) {
                    if (arguments.length === 0) {
                        ix = this.dates.length - 1;
                        format = this.o.format;
                    } else if (typeof ix === 'string') {
                        format = ix;
                        ix = this.dates.length - 1;
                    }
                    format = format || this.o.format;
                    var date = this.dates.get(ix);
                    return DPGlobal.formatDate(date, format, this.o.language);
                }, this)
            });
        },

        show: function () {
            if (this.inputField.prop('disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
                return;
            if (!this.isInline)
                this.picker.appendTo(this.o.container);
            this.place();
            this.picker.show();
            this._attachSecondaryEvents();
            this._trigger('show');
            if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
                $(this.element).blur();
            }
            return this;
        },

        hide: function () {
            if (this.isInline || !this.picker.is(':visible'))
                return this;
            this.focusDate = null;
            this.picker.hide().detach();
            this._detachSecondaryEvents();
            this.setViewMode(this.o.startView);

            if (this.o.forceParse && this.inputField.val())
                this.setValue();
            this._trigger('hide');
            return this;
        },

        destroy: function () {
            this.hide();
            this._detachEvents();
            this._detachSecondaryEvents();
            this.picker.remove();
            delete this.element.data().datepicker;
            if (!this.isInput) {
                delete this.element.data().date;
            }
            return this;
        },

        paste: function (e) {
            var dateString;
            if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
                && $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
                dateString = e.originalEvent.clipboardData.getData('text/plain');
            } else if (window.clipboardData) {
                dateString = window.clipboardData.getData('Text');
            } else {
                return;
            }
            this.setDate(dateString);
            this.update();
            e.preventDefault();
        },

        _utc_to_local: function (utc) {
            if (!utc) {
                return utc;
            }

            var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));

            if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
                local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
            }

            return local;
        },
        _local_to_utc: function (local) {
            return local && new Date(local.getTime() - (local.getTimezoneOffset() * 60000));
        },
        _zero_time: function (local) {
            return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
        },
        _zero_utc_time: function (utc) {
            return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
        },

        getDates: function () {
            return $.map(this.dates, this._utc_to_local);
        },

        getUTCDates: function () {
            return $.map(this.dates, function (d) {
                return new Date(d);
            });
        },

        getDate: function () {
            return this._utc_to_local(this.getUTCDate());
        },

        getUTCDate: function () {
            var selected_date = this.dates.get(-1);
            if (selected_date !== undefined) {
                return new Date(selected_date);
            } else {
                return null;
            }
        },

        clearDates: function () {
            this.inputField.val('');
            this.update();
            this._trigger('changeDate');

            if (this.o.autoclose) {
                this.hide();
            }
        },

        setDates: function () {
            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
            this.update.apply(this, args);
            this._trigger('changeDate');
            this.setValue();
            return this;
        },

        setUTCDates: function () {
            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
            this.setDates.apply(this, $.map(args, this._utc_to_local));
            return this;
        },

        setDate: alias('setDates'),
        setUTCDate: alias('setUTCDates'),
        remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),

        setValue: function () {
            var formatted = this.getFormattedDate();
            this.inputField.val(formatted);
            return this;
        },

        getFormattedDate: function (format) {
            if (format === undefined)
                format = this.o.format;

            var lang = this.o.language;
            return $.map(this.dates, function (d) {
                return DPGlobal.formatDate(d, format, lang);
            }).join(this.o.multidateSeparator);
        },

        getStartDate: function () {
            return this.o.startDate;
        },

        setStartDate: function (startDate) {
            this._process_options({ startDate: startDate });
            this.update();
            this.updateNavArrows();
            return this;
        },

        getEndDate: function () {
            return this.o.endDate;
        },

        setEndDate: function (endDate) {
            this._process_options({ endDate: endDate });
            this.update();
            this.updateNavArrows();
            return this;
        },

        setDaysOfWeekDisabled: function (daysOfWeekDisabled) {
            this._process_options({ daysOfWeekDisabled: daysOfWeekDisabled });
            this.update();
            return this;
        },

        setDaysOfWeekHighlighted: function (daysOfWeekHighlighted) {
            this._process_options({ daysOfWeekHighlighted: daysOfWeekHighlighted });
            this.update();
            return this;
        },

        setDatesDisabled: function (datesDisabled) {
            this._process_options({ datesDisabled: datesDisabled });
            this.update();
            return this;
        },

        place: function () {
            if (this.isInline)
                return this;
            var calendarWidth = this.picker.outerWidth(),
                calendarHeight = this.picker.outerHeight(),
                visualPadding = 10,
                container = $(this.o.container),
                windowWidth = container.width(),
                scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
                appendOffset = container.offset();

            var parentsZindex = [0];
            this.element.parents().each(function () {
                var itemZIndex = $(this).css('z-index');
                if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));
            });
            var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
            var offset = this.component ? this.component.parent().offset() : this.element.offset();
            var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
            var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
            var left = offset.left - appendOffset.left;
            var top = (offset.top - appendOffset.top) + 15;

            if (this.o.container !== 'body') {
                top += scrollTop;
            }

            this.picker.removeClass(
                'datepicker-orient-top datepicker-orient-bottom ' +
                'datepicker-orient-right datepicker-orient-left'
            );

            if (this.o.orientation.x !== 'auto') {
                this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
                if (this.o.orientation.x === 'right')
                    left -= calendarWidth - width;
            }
            // auto x orientation is best-placement: if it crosses a window
            // edge, fudge it sideways
            else {
                if (offset.left < 0) {
                    // component is outside the window on the left side. Move it into visible range
                    this.picker.addClass('datepicker-orient-left');
                    left -= offset.left - visualPadding;
                } else if (left + calendarWidth > windowWidth) {
                    // the calendar passes the widow right edge. Align it to component right side
                    this.picker.addClass('datepicker-orient-right');
                    left += width - calendarWidth;
                } else {
                    if (this.o.rtl) {
                        // Default to right
                        this.picker.addClass('datepicker-orient-right');
                    } else {
                        // Default to left
                        this.picker.addClass('datepicker-orient-left');
                    }
                }
            }

            // auto y orientation is best-situation: top or bottom, no fudging,
            // decision based on which shows more of the calendar
            var yorient = this.o.orientation.y,
                top_overflow;
            if (yorient === 'auto') {
                top_overflow = -scrollTop + top - calendarHeight;
                yorient = top_overflow < 0 ? 'bottom' : 'top';
            }

            this.picker.addClass('datepicker-orient-' + yorient);
            if (yorient === 'top')
                top -= calendarHeight + parseInt(this.picker.css('padding-top'));
            else
                top += height;

            if (this.o.rtl) {
                var right = windowWidth - (left + width);
                this.picker.css({
                    top: top,
                    right: right,
                    zIndex: zIndex
                });
            } else {
                this.picker.css({
                    top: top,
                    left: left,
                    zIndex: zIndex
                });
            }
            return this;
        },

        _allow_update: true,
        update: function () {
            if (!this._allow_update)
                return this;

            var oldDates = this.dates.copy(),
                dates = [],
                fromArgs = false;
            if (arguments.length) {
                $.each(arguments, $.proxy(function (i, date) {
                    if (date instanceof Date)
                        date = this._local_to_utc(date);
                    dates.push(date);
                }, this));
                fromArgs = true;
            } else {
                dates = this.isInput
                    ? this.element.val()
                    : this.element.data('date') || this.inputField.val();
                if (dates && this.o.multidate)
                    dates = dates.split(this.o.multidateSeparator);
                else
                    dates = [dates];
                delete this.element.data().date;
            }

            dates = $.map(dates, $.proxy(function (date) {
                return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
            }, this));
            dates = $.grep(dates, $.proxy(function (date) {
                return (
                    !this.dateWithinRange(date) ||
                    !date
                );
            }, this), true);
            this.dates.replace(dates);

            if (this.o.updateViewDate) {
                if (this.dates.length)
                    this.viewDate = new Date(this.dates.get(-1));
                else if (this.viewDate < this.o.startDate)
                    this.viewDate = new Date(this.o.startDate);
                else if (this.viewDate > this.o.endDate)
                    this.viewDate = new Date(this.o.endDate);
                else
                    this.viewDate = this.o.defaultViewDate;
            }

            if (fromArgs) {
                // setting date by clicking
                this.setValue();
                this.element.change();
            }
            else if (this.dates.length) {
                // setting date by typing
                if (String(oldDates) !== String(this.dates) && fromArgs) {
                    this._trigger('changeDate');
                    this.element.change();
                }
            }
            if (!this.dates.length && oldDates.length) {
                this._trigger('clearDate');
                this.element.change();
            }

            this.fill();
            return this;
        },

        fillDow: function () {
            if (this.o.showWeekDays) {
                var dowCnt = this.o.weekStart,
                    html = '<tr>';
                if (this.o.calendarWeeks) {
                    html += '<th class="cw">&#160;</th>';
                }
                while (dowCnt < this.o.weekStart + 7) {
                    html += '<th class="datepicker__day--heading dow';
                    if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
                        html += ' disabled';
                    html += '">' + dates[this.o.language].daysMin[(dowCnt++) % 7] + '</th>';
                }
                html += '</tr>';
                this.picker.find('.datepicker-days thead').append(html);
            }
        },

        fillMonths: function () {
            var localDate = this._utc_to_local(this.viewDate);
            var html = '';
            var focused;
            for (var i = 0; i < 12; i++) {
                focused = localDate && localDate.getMonth() === i ? ' focused' : '';
                html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i] + '</span>';
            }
            this.picker.find('.datepicker-months td').html(html);
        },

        setRange: function (range) {
            if (!range || !range.length)
                delete this.range;
            else
                this.range = $.map(range, function (d) {
                    return d.valueOf();
                });
            this.fill();
        },

        getClassNames: function (date) {
            var cls = [],
                year = this.viewDate.getUTCFullYear(),
                month = this.viewDate.getUTCMonth(),
                today = UTCToday();
            if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)) {
                cls.push('old');
            } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)) {
                cls.push('new');
            }
            if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
                cls.push('focused');
            // Compare internal UTC date with UTC today, not local today
            if (this.o.todayHighlight && isUTCEquals(date, today)) {
                cls.push('today');
            }
            if (this.dates.contains(date) !== -1)
                cls.push('active');
            if (!this.dateWithinRange(date)) {
                cls.push('disabled');
            }
            if (this.dateIsDisabled(date)) {
                cls.push('disabled', 'disabled-date');
            }
            if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1) {
                cls.push('highlighted');
            }

            if (this.range) {
                if (date > this.range[0] && date < this.range[this.range.length - 1]) {
                    cls.push('range');
                }
                if ($.inArray(date.valueOf(), this.range) !== -1) {
                    cls.push('selected');
                }
                if (date.valueOf() === this.range[0]) {
                    cls.push('range-start');
                }
                if (date.valueOf() === this.range[this.range.length - 1]) {
                    cls.push('range-end');
                }
            }
            return cls;
        },

        _fill_yearsView: function (selector, cssClass, factor, year, startYear, endYear, beforeFn) {
            var html = '';
            var step = factor / 10;
            var view = this.picker.find(selector);
            var startVal = Math.floor(year / factor) * factor;
            var endVal = startVal + step * 9;
            var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;
            var selected = $.map(this.dates, function (d) {
                return Math.floor(d.getUTCFullYear() / step) * step;
            });

            var classes, tooltip, before;
            for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {
                classes = [cssClass];
                tooltip = null;

                if (currVal === startVal - step) {
                    classes.push('old');
                } else if (currVal === endVal + step) {
                    classes.push('new');
                }
                if ($.inArray(currVal, selected) !== -1) {
                    classes.push('active');
                }
                if (currVal < startYear || currVal > endYear) {
                    classes.push('disabled');
                }
                if (currVal === focusedVal) {
                    classes.push('focused');
                }

                if (beforeFn !== $.noop) {
                    before = beforeFn(new Date(currVal, 0, 1));
                    if (before === undefined) {
                        before = {};
                    } else if (typeof before === 'boolean') {
                        before = { enabled: before };
                    } else if (typeof before === 'string') {
                        before = { classes: before };
                    }
                    if (before.enabled === false) {
                        classes.push('disabled');
                    }
                    if (before.classes) {
                        classes = classes.concat(before.classes.split(/\s+/));
                    }
                    if (before.tooltip) {
                        tooltip = before.tooltip;
                    }
                }

                html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + currVal + '</span>';
            }

            view.find('.switch').text(startVal + '-' + endVal);
            view.find('td').html(html);
        },

        fill: function () {
            var d = new Date(this.viewDate),
                year = d.getUTCFullYear(),
                month = d.getUTCMonth(),
                startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
                startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
                endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
                endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
                todaytxt = dates[this.o.language].today || dates['en'].today || '',
                cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
                titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
                tooltip,
                before;
            if (isNaN(year) || isNaN(month))
                return;
            this.picker.find('.datepicker-days .switch')
                .text(DPGlobal.formatDate(d, titleFormat, this.o.language));
            this.picker.find('tfoot .today')
                .text(todaytxt)
                .css('display', this.o.todayBtn === true || this.o.todayBtn === 'linked' ? 'table-cell' : 'none');
            this.picker.find('tfoot .clear')
                .text(cleartxt)
                .css('display', this.o.clearBtn === true ? 'table-cell' : 'none');
            this.picker.find('thead .datepicker-title')
                .text(this.o.title)
                .css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');
            this.updateNavArrows();
            this.fillMonths();
            var prevMonth = UTCDate(year, month, 0),
                day = prevMonth.getUTCDate();
            prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7) % 7);
            var nextMonth = new Date(prevMonth);
            if (prevMonth.getUTCFullYear() < 100) {
                nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
            }
            nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
            nextMonth = nextMonth.valueOf();
            var html = [];
            var weekDay, clsName;
            while (prevMonth.valueOf() < nextMonth) {
                weekDay = prevMonth.getUTCDay();
                if (weekDay === this.o.weekStart) {
                    html.push('<tr>');
                    if (this.o.calendarWeeks) {
                        // ISO 8601: First week contains first thursday.
                        // ISO also states week starts on Monday, but we can be more abstract here.
                        var
                            // Start of current week: based on weekstart/current date
                            ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
                            // Thursday of this week
                            th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
                            // First Thursday of year, year from thursday
                            yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
                            // Calendar week: ms between thursdays, div ms per day, div 7 days
                            calWeek = (th - yth) / 864e5 / 7 + 1;
                        html.push('<td class="cw">' + calWeek + '</td>');
                    }
                }
                clsName = this.getClassNames(prevMonth);
                clsName.push('day');

                var content = prevMonth.getUTCDate();

                if (this.o.beforeShowDay !== $.noop) {
                    before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
                    if (before === undefined)
                        before = {};
                    else if (typeof before === 'boolean')
                        before = { enabled: before };
                    else if (typeof before === 'string')
                        before = { classes: before };
                    if (before.enabled === false)
                        clsName.push('disabled');
                    if (before.classes)
                        clsName = clsName.concat(before.classes.split(/\s+/));
                    if (before.tooltip)
                        tooltip = before.tooltip;
                    if (before.content)
                        content = before.content;
                }

                //Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
                //Fallback to unique function for older jquery versions
                if ($.isFunction($.uniqueSort)) {
                    clsName = $.uniqueSort(clsName);
                } else {
                    clsName = $.unique(clsName);
                }

                html.push('<td class="' + clsName.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + ' data-date="' + prevMonth.getTime().toString() + '">' + content + '</td>');
                tooltip = null;
                if (weekDay === this.o.weekEnd) {
                    html.push('</tr>');
                }
                prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
            }
            this.picker.find('.datepicker-days tbody').html(html.join(''));

            var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
            var months = this.picker.find('.datepicker-months')
                .find('.switch')
                .text(this.o.maxViewMode < 2 ? monthsTitle : year)
                .end()
                .find('tbody span').removeClass('active');

            $.each(this.dates, function (i, d) {
                if (d.getUTCFullYear() === year)
                    months.eq(d.getUTCMonth()).addClass('active');
            });

            if (year < startYear || year > endYear) {
                months.addClass('disabled');
            }
            if (year === startYear) {
                months.slice(0, startMonth).addClass('disabled');
            }
            if (year === endYear) {
                months.slice(endMonth + 1).addClass('disabled');
            }

            if (this.o.beforeShowMonth !== $.noop) {
                var that = this;
                $.each(months, function (i, month) {
                    var moDate = new Date(year, i, 1);
                    var before = that.o.beforeShowMonth(moDate);
                    if (before === undefined)
                        before = {};
                    else if (typeof before === 'boolean')
                        before = { enabled: before };
                    else if (typeof before === 'string')
                        before = { classes: before };
                    if (before.enabled === false && !$(month).hasClass('disabled'))
                        $(month).addClass('disabled');
                    if (before.classes)
                        $(month).addClass(before.classes);
                    if (before.tooltip)
                        $(month).prop('title', before.tooltip);
                });
            }

            // Generating decade/years picker
            this._fill_yearsView(
                '.datepicker-years',
                'year',
                10,
                year,
                startYear,
                endYear,
                this.o.beforeShowYear
            );

            // Generating century/decades picker
            this._fill_yearsView(
                '.datepicker-decades',
                'decade',
                100,
                year,
                startYear,
                endYear,
                this.o.beforeShowDecade
            );

            // Generating millennium/centuries picker
            this._fill_yearsView(
                '.datepicker-centuries',
                'century',
                1000,
                year,
                startYear,
                endYear,
                this.o.beforeShowCentury
            );
        },

        updateNavArrows: function () {
            if (!this._allow_update)
                return;

            var d = new Date(this.viewDate),
                year = d.getUTCFullYear(),
                month = d.getUTCMonth(),
                startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
                startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
                endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
                endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
                prevIsDisabled,
                nextIsDisabled,
                factor = 1;
            switch (this.viewMode) {
                case 4:
                    factor *= 10;
                /* falls through */
                case 3:
                    factor *= 10;
                /* falls through */
                case 2:
                    factor *= 10;
                /* falls through */
                case 1:
                    prevIsDisabled = Math.floor(year / factor) * factor < startYear;
                    nextIsDisabled = Math.floor(year / factor) * factor + factor > endYear;
                    break;
                case 0:
                    prevIsDisabled = year <= startYear && month < startMonth;
                    nextIsDisabled = year >= endYear && month > endMonth;
                    break;
            }

            this.picker.find('.prev').toggleClass('disabled', prevIsDisabled);
            this.picker.find('.next').toggleClass('disabled', nextIsDisabled);
        },

        click: function (e) {
            e.preventDefault();
            e.stopPropagation();

            var target, dir, day, year, month;
            target = $(e.target);

            // Clicked on the switch
            if (target.hasClass('switch') && this.viewMode !== this.o.maxViewMode) {
                //this.setViewMode(this.viewMode + 1);
            }

            // Clicked on today button
            if (target.hasClass('today') && !target.hasClass('day')) {
                this.setViewMode(0);
                this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
            }

            // Clicked on clear button
            if (target.hasClass('clear')) {
                this.clearDates();
            }

            if (!target.hasClass('disabled')) {
                // Clicked on a month, year, decade, century
                if (target.hasClass('month')
                    || target.hasClass('year')
                    || target.hasClass('decade')
                    || target.hasClass('century')) {
                    this.viewDate.setUTCDate(1);

                    day = 1;
                    if (this.viewMode === 1) {
                        month = target.parent().find('span').index(target);
                        year = this.viewDate.getUTCFullYear();
                        this.viewDate.setUTCMonth(month);
                    } else {
                        month = 0;
                        year = Number(target.text());
                        this.viewDate.setUTCFullYear(year);
                    }

                    this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);

                    if (this.viewMode === this.o.minViewMode) {
                        this._setDate(UTCDate(year, month, day));
                    } else {
                        this.setViewMode(this.viewMode - 1);
                        this.fill();
                    }
                }
            }

            if (this.picker.is(':visible') && this._focused_from) {
                this._focused_from.focus();
            }
            delete this._focused_from;
        },

        dayCellClick: function (e) {
            var $target = $(e.currentTarget);
            var timestamp = $target.data('date');
            var date = new Date(timestamp);

            if (this.o.updateViewDate) {
                if (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {
                    this._trigger('changeYear', this.viewDate);
                }

                if (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {
                    this._trigger('changeMonth', this.viewDate);
                }
            }
            this._setDate(date);
        },

        // Clicked on prev or next
        navArrowsClick: function (e) {
            var $target = $(e.currentTarget);
            var dir = $target.hasClass('prev') ? -1 : 1;
            if (this.viewMode !== 0) {
                dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
            }
            this.viewDate = this.moveMonth(this.viewDate, dir);
            this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
            this.fill();
        },

        _toggle_multidate: function (date) {
            var ix = this.dates.contains(date);
            if (!date) {
                this.dates.clear();
            }

            if (ix !== -1) {
                if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive) {
                    this.dates.remove(ix);
                }
            } else if (this.o.multidate === false) {
                this.dates.clear();
                this.dates.push(date);
            }
            else {
                this.dates.push(date);
            }

            if (typeof this.o.multidate === 'number')
                while (this.dates.length > this.o.multidate)
                    this.dates.remove(0);
        },

        _setDate: function (date, which) {
            if (!which || which === 'date')
                this._toggle_multidate(date && new Date(date));
            if ((!which && this.o.updateViewDate) || which === 'view')
                this.viewDate = date && new Date(date);

            this.fill();
            this.setValue();
            if (!which || which !== 'view') {
                this._trigger('changeDate');
            }
            this.inputField.trigger('change');
            if (this.o.autoclose && (!which || which === 'date')) {
                this.hide();
            }
        },

        moveDay: function (date, dir) {
            var newDate = new Date(date);
            newDate.setUTCDate(date.getUTCDate() + dir);

            return newDate;
        },

        moveWeek: function (date, dir) {
            return this.moveDay(date, dir * 7);
        },

        moveMonth: function (date, dir) {
            if (!isValidDate(date))
                return this.o.defaultViewDate;
            if (!dir)
                return date;
            var new_date = new Date(date.valueOf()),
                day = new_date.getUTCDate(),
                month = new_date.getUTCMonth(),
                mag = Math.abs(dir),
                new_month, test;
            dir = dir > 0 ? 1 : -1;
            if (mag === 1) {
                test = dir === -1
                    // If going back one month, make sure month is not current month
                    // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
                    ? function () {
                        return new_date.getUTCMonth() === month;
                    }
                    // If going forward one month, make sure month is as expected
                    // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
                    : function () {
                        return new_date.getUTCMonth() !== new_month;
                    };
                new_month = month + dir;
                new_date.setUTCMonth(new_month);
                // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
                new_month = (new_month + 12) % 12;
            }
            else {
                // For magnitudes >1, move one month at a time...
                for (var i = 0; i < mag; i++)
                    // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
                    new_date = this.moveMonth(new_date, dir);
                // ...then reset the day, keeping it in the new month
                new_month = new_date.getUTCMonth();
                new_date.setUTCDate(day);
                test = function () {
                    return new_month !== new_date.getUTCMonth();
                };
            }
            // Common date-resetting loop -- if date is beyond end of month, make it
            // end of month
            while (test()) {
                new_date.setUTCDate(--day);
                new_date.setUTCMonth(new_month);
            }
            return new_date;
        },

        moveYear: function (date, dir) {
            return this.moveMonth(date, dir * 12);
        },

        moveAvailableDate: function (date, dir, fn) {
            do {
                date = this[fn](date, dir);

                if (!this.dateWithinRange(date))
                    return false;

                fn = 'moveDay';
            }
            while (this.dateIsDisabled(date));

            return date;
        },

        weekOfDateIsDisabled: function (date) {
            return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
        },

        dateIsDisabled: function (date) {
            return (
                this.weekOfDateIsDisabled(date) ||
                $.grep(this.o.datesDisabled, function (d) {
                    return isUTCEquals(date, d);
                }).length > 0
            );
        },

        dateWithinRange: function (date) {
            return date >= this.o.startDate && date <= this.o.endDate;
        },

        keydown: function (e) {
            if (!this.picker.is(':visible')) {
                if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
                    this.show();
                    e.stopPropagation();
                }
                return;
            }
            var dateChanged = false,
                dir, newViewDate,
                focusDate = this.focusDate || this.viewDate;
            switch (e.keyCode) {
                case 27: // escape
                    if (this.focusDate) {
                        this.focusDate = null;
                        this.viewDate = this.dates.get(-1) || this.viewDate;
                        this.fill();
                    }
                    else
                        this.hide();
                    e.preventDefault();
                    e.stopPropagation();
                    break;
                case 37: // left
                case 38: // up
                case 39: // right
                case 40: // down
                    if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
                        break;
                    dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
                    if (this.viewMode === 0) {
                        if (e.ctrlKey) {
                            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');

                            if (newViewDate)
                                this._trigger('changeYear', this.viewDate);
                        } else if (e.shiftKey) {
                            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');

                            if (newViewDate)
                                this._trigger('changeMonth', this.viewDate);
                        } else if (e.keyCode === 37 || e.keyCode === 39) {
                            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
                        } else if (!this.weekOfDateIsDisabled(focusDate)) {
                            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
                        }
                    } else if (this.viewMode === 1) {
                        if (e.keyCode === 38 || e.keyCode === 40) {
                            dir = dir * 4;
                        }
                        newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
                    } else if (this.viewMode === 2) {
                        if (e.keyCode === 38 || e.keyCode === 40) {
                            dir = dir * 4;
                        }
                        newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
                    }
                    if (newViewDate) {
                        this.focusDate = this.viewDate = newViewDate;
                        this.setValue();
                        this.fill();
                        e.preventDefault();
                    }
                    break;
                case 13: // enter
                    if (!this.o.forceParse)
                        break;
                    focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
                    if (this.o.keyboardNavigation) {
                        this._toggle_multidate(focusDate);
                        dateChanged = true;
                    }
                    this.focusDate = null;
                    this.viewDate = this.dates.get(-1) || this.viewDate;
                    this.setValue();
                    this.fill();
                    if (this.picker.is(':visible')) {
                        e.preventDefault();
                        e.stopPropagation();
                        if (this.o.autoclose)
                            this.hide();
                    }
                    break;
                case 9: // tab
                    this.focusDate = null;
                    this.viewDate = this.dates.get(-1) || this.viewDate;
                    this.fill();
                    this.hide();
                    break;
            }
            if (dateChanged) {
                if (this.dates.length)
                    this._trigger('changeDate');
                else
                    this._trigger('clearDate');
                this.inputField.trigger('change');
            }
        },

        setViewMode: function (viewMode) {
            this.viewMode = viewMode;
            this.picker
                .children('div')
                .hide()
                .filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
                .show();
            this.updateNavArrows();
            this._trigger('changeViewMode', new Date(this.viewDate));
        }
    };

    var DateRangePicker = function (element, options) {
        $.data(element, 'datepicker', this);
        this.element = $(element);
        this.inputs = $.map(options.inputs, function (i) {
            return i.jquery ? i[0] : i;
        });
        delete options.inputs;

        this.keepEmptyValues = options.keepEmptyValues;
        delete options.keepEmptyValues;

        datepickerPlugin.call($(this.inputs), options)
            .on('changeDate', $.proxy(this.dateUpdated, this));

        this.pickers = $.map(this.inputs, function (i) {
            return $.data(i, 'datepicker');
        });
        this.updateDates();
    };
    DateRangePicker.prototype = {
        updateDates: function () {
            this.dates = $.map(this.pickers, function (i) {
                return i.getUTCDate();
            });
            this.updateRanges();
        },
        updateRanges: function () {
            var range = $.map(this.dates, function (d) {
                return d.valueOf();
            });
            $.each(this.pickers, function (i, p) {
                p.setRange(range);
            });
        },
        clearDates: function () {
            $.each(this.pickers, function (i, p) {
                p.clearDates();
            });
        },
        dateUpdated: function (e) {
            // `this.updating` is a workaround for preventing infinite recursion
            // between `changeDate` triggering and `setUTCDate` calling.  Until
            // there is a better mechanism.
            if (this.updating)
                return;
            this.updating = true;

            var dp = $.data(e.target, 'datepicker');

            if (dp === undefined) {
                return;
            }

            var new_date = dp.getUTCDate(),
                keep_empty_values = this.keepEmptyValues,
                i = $.inArray(e.target, this.inputs),
                j = i - 1,
                k = i + 1,
                l = this.inputs.length;
            if (i === -1)
                return;

            $.each(this.pickers, function (i, p) {
                if (!p.getUTCDate() && (p === dp || !keep_empty_values))
                    p.setUTCDate(new_date);
            });

            if (new_date < this.dates[j]) {
                // Date being moved earlier/left
                while (j >= 0 && new_date < this.dates[j]) {
                    this.pickers[j--].setUTCDate(new_date);
                }
            } else if (new_date > this.dates[k]) {
                // Date being moved later/right
                while (k < l && new_date > this.dates[k]) {
                    this.pickers[k++].setUTCDate(new_date);
                }
            }
            this.updateDates();

            delete this.updating;
        },
        destroy: function () {
            $.map(this.pickers, function (p) { p.destroy(); });
            $(this.inputs).off('changeDate', this.dateUpdated);
            delete this.element.data().datepicker;
        },
        remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')
    };

    function opts_from_el(el, prefix) {
        // Derive options from element data-attrs
        var data = $(el).data(),
            out = {}, inkey,
            replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
        prefix = new RegExp('^' + prefix.toLowerCase());
        function re_lower(_, a) {
            return a.toLowerCase();
        }
        for (var key in data)
            if (prefix.test(key)) {
                inkey = key.replace(replace, re_lower);
                out[inkey] = data[key];
            }
        return out;
    }

    function opts_from_locale(lang) {
        // Derive options from locale plugins
        var out = {};
        // Check if "de-DE" style date is available, if not language should
        // fallback to 2 letter code eg "de"
        if (!dates[lang]) {
            lang = lang.split('-')[0];
            if (!dates[lang])
                return;
        }
        var d = dates[lang];
        $.each(locale_opts, function (i, k) {
            if (k in d)
                out[k] = d[k];
        });
        return out;
    }

    var old = $.fn.datepicker;
    var datepickerPlugin = function (option) {
        var args = Array.apply(null, arguments);
        args.shift();
        var internal_return;
        this.each(function () {
            var $this = $(this),
                data = $this.data('datepicker'),
                options = typeof option === 'object' && option;
            if (!data) {
                var elopts = opts_from_el(this, 'date'),
                    // Preliminary otions
                    xopts = $.extend({}, defaults, elopts, options),
                    locopts = opts_from_locale(xopts.language),
                    // Options priority: js args, data-attrs, locales, defaults
                    opts = $.extend({}, defaults, locopts, elopts, options);
                if ($this.hasClass('input-daterange') || opts.inputs) {
                    $.extend(opts, {
                        inputs: opts.inputs || $this.find('input').toArray()
                    });
                    data = new DateRangePicker(this, opts);
                }
                else {
                    data = new Datepicker(this, opts);
                }
                $this.data('datepicker', data);
            }
            if (typeof option === 'string' && typeof data[option] === 'function') {
                internal_return = data[option].apply(data, args);
            }
        });

        if (
            internal_return === undefined ||
            internal_return instanceof Datepicker ||
            internal_return instanceof DateRangePicker
        )
            return this;

        if (this.length > 1)
            throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
        else
            return internal_return;
    };
    $.fn.datepicker = datepickerPlugin;

    var defaults = $.fn.datepicker.defaults = {
        assumeNearbyYear: false,
        autoclose: false,
        beforeShowDay: $.noop,
        beforeShowMonth: $.noop,
        beforeShowYear: $.noop,
        beforeShowDecade: $.noop,
        beforeShowCentury: $.noop,
        calendarWeeks: false,
        clearBtn: false,
        toggleActive: false,
        daysOfWeekDisabled: [],
        daysOfWeekHighlighted: [],
        datesDisabled: [],
        endDate: Infinity,
        forceParse: true,
        format: 'mm/dd/yyyy',
        keepEmptyValues: false,
        keyboardNavigation: true,
        language: 'en',
        minViewMode: 0,
        maxViewMode: 4,
        multidate: false,
        multidateSeparator: ',',
        orientation: "auto",
        rtl: false,
        startDate: -Infinity,
        startView: 0,
        todayBtn: false,
        todayHighlight: false,
        updateViewDate: true,
        weekStart: 0,
        disableTouchKeyboard: false,
        enableOnReadonly: true,
        showOnFocus: true,
        zIndexOffset: 10,
        container: 'body',
        immediateUpdates: false,
        title: '',
        templates: {
            leftArrow: '<svg><use xlink:href="/css/libs/svg/icon-library.svg#chevron-left"></use></svg>',
            rightArrow: '<svg><use xlink:href="/css/libs/svg/icon-library.svg#chevron-right"></use></svg>'
        },
        showWeekDays: true
    };
    var locale_opts = $.fn.datepicker.locale_opts = [
        'format',
        'rtl',
        'weekStart'
    ];
    $.fn.datepicker.Constructor = Datepicker;
    var dates = $.fn.datepicker.dates = {
        en: {
            days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
            daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
            daysMin: ["S", "M", "T", "W", "T", "F", "S"],
            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
            today: "Today",
            clear: "Clear",
            titleFormat: "MM yyyy"
        }
    };

    var DPGlobal = {
        viewModes: [
            {
                names: ['days', 'month'],
                clsName: 'days',
                e: 'changeMonth'
            },
            {
                names: ['months', 'year'],
                clsName: 'months',
                e: 'changeYear',
                navStep: 1
            },
            {
                names: ['years', 'decade'],
                clsName: 'years',
                e: 'changeDecade',
                navStep: 10
            },
            {
                names: ['decades', 'century'],
                clsName: 'decades',
                e: 'changeCentury',
                navStep: 100
            },
            {
                names: ['centuries', 'millennium'],
                clsName: 'centuries',
                e: 'changeMillennium',
                navStep: 1000
            }
        ],
        validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
        nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
        parseFormat: function (format) {
            if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
                return format;
            // IE treats \0 as a string end in inputs (truncating the value),
            // so it's a bad format delimiter, anyway
            var separators = format.replace(this.validParts, '\0').split('\0'),
                parts = format.match(this.validParts);
            if (!separators || !separators.length || !parts || parts.length === 0) {
                throw new Error("Invalid date format.");
            }
            return { separators: separators, parts: parts };
        },
        parseDate: function (date, format, language, assumeNearby) {
            if (!date)
                return undefined;
            if (date instanceof Date)
                return date;
            if (typeof format === 'string')
                format = DPGlobal.parseFormat(format);
            if (format.toValue)
                return format.toValue(date, format, language);
            var fn_map = {
                d: 'moveDay',
                m: 'moveMonth',
                w: 'moveWeek',
                y: 'moveYear'
            },
                dateAliases = {
                    yesterday: '-1d',
                    today: '+0d',
                    tomorrow: '+1d'
                },
                parts, part, dir, i, fn;
            if (date in dateAliases) {
                date = dateAliases[date];
            }
            if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)) {
                parts = date.match(/([\-+]\d+)([dmwy])/gi);
                date = new Date();
                for (i = 0; i < parts.length; i++) {
                    part = parts[i].match(/([\-+]\d+)([dmwy])/i);
                    dir = Number(part[1]);
                    fn = fn_map[part[2].toLowerCase()];
                    date = Datepicker.prototype[fn](date, dir);
                }
                return Datepicker.prototype._zero_utc_time(date);
            }

            parts = date && date.match(this.nonpunctuation) || [];

            function applyNearbyYear(year, threshold) {
                if (threshold === true)
                    threshold = 10;

                // if year is 2 digits or less, than the user most likely is trying to get a recent century
                if (year < 100) {
                    year += 2000;
                    // if the new year is more than threshold years in advance, use last century
                    if (year > ((new Date()).getFullYear() + threshold)) {
                        year -= 100;
                    }
                }

                return year;
            }

            var parsed = {},
                setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
                setters_map = {
                    yyyy: function (d, v) {
                        return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
                    },
                    m: function (d, v) {
                        if (isNaN(d))
                            return d;
                        v -= 1;
                        while (v < 0) v += 12;
                        v %= 12;
                        d.setUTCMonth(v);
                        while (d.getUTCMonth() !== v)
                            d.setUTCDate(d.getUTCDate() - 1);
                        return d;
                    },
                    d: function (d, v) {
                        return d.setUTCDate(v);
                    }
                },
                val, filtered;
            setters_map['yy'] = setters_map['yyyy'];
            setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
            setters_map['dd'] = setters_map['d'];
            date = UTCToday();
            var fparts = format.parts.slice();
            // Remove noop parts
            if (parts.length !== fparts.length) {
                fparts = $(fparts).filter(function (i, p) {
                    return $.inArray(p, setters_order) !== -1;
                }).toArray();
            }
            // Process remainder
            function match_part() {
                var m = this.slice(0, parts[i].length),
                    p = parts[i].slice(0, m.length);
                return m.toLowerCase() === p.toLowerCase();
            }
            if (parts.length === fparts.length) {
                var cnt;
                for (i = 0, cnt = fparts.length; i < cnt; i++) {
                    val = parseInt(parts[i], 10);
                    part = fparts[i];
                    if (isNaN(val)) {
                        switch (part) {
                            case 'MM':
                                filtered = $(dates[language].months).filter(match_part);
                                val = $.inArray(filtered[0], dates[language].months) + 1;
                                break;
                            case 'M':
                                filtered = $(dates[language].monthsShort).filter(match_part);
                                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
                                break;
                        }
                    }
                    parsed[part] = val;
                }
                var _date, s;
                for (i = 0; i < setters_order.length; i++) {
                    s = setters_order[i];
                    if (s in parsed && !isNaN(parsed[s])) {
                        _date = new Date(date);
                        setters_map[s](_date, parsed[s]);
                        if (!isNaN(_date))
                            date = _date;
                    }
                }
            }
            return date;
        },
        formatDate: function (date, format, language) {
            if (!date)
                return '';
            if (typeof format === 'string')
                format = DPGlobal.parseFormat(format);
            if (format.toDisplay)
                return format.toDisplay(date, format, language);
            var val = {
                d: date.getUTCDate(),
                D: dates[language].daysShort[date.getUTCDay()],
                DD: dates[language].days[date.getUTCDay()],
                m: date.getUTCMonth() + 1,
                M: dates[language].monthsShort[date.getUTCMonth()],
                MM: dates[language].months[date.getUTCMonth()],
                yy: date.getUTCFullYear().toString().substring(2),
                yyyy: date.getUTCFullYear()
            };
            val.dd = (val.d < 10 ? '0' : '') + val.d;
            val.mm = (val.m < 10 ? '0' : '') + val.m;
            date = [];
            var seps = $.extend([], format.separators);
            for (var i = 0, cnt = format.parts.length; i <= cnt; i++) {
                if (seps.length)
                    date.push(seps.shift());
                date.push(val[format.parts[i]]);
            }
            return date.join('');
        },
        headTemplate: '<thead>' +
            '<tr class="datepicker__row--heading">' +
            '<th class="datepicker__arrows--prev prev">&lsaquo;</th>' +
            '<th colspan="5" class="datepicker__date-heading switch"></th>' +
            '<th class="datepicker__arrows--next next">&rsaquo;</th>' +
            '</tr>' +
            '</thead>',
        contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
    };
    DPGlobal.template = '<div class="datepicker dropdown-menu">' +
        '<div class="datepicker-days">' +
        '<table class=" table-condensed">' +
        DPGlobal.headTemplate +
        '<tbody></tbody>' +
        '</table>' +
        '</div>' +
        '<div class="datepicker-months">' +
        '<table class="table-condensed">' +
        DPGlobal.headTemplate +
        DPGlobal.contTemplate +
        '</table>' +
        '</div>' +
        '<div class="datepicker-years">' +
        '<table class="table-condensed">' +
        DPGlobal.headTemplate +
        DPGlobal.contTemplate +
        '</table>' +
        '</div>' +
        '</div>';
    //    headTemplate: '<thead>' +
    //        '<tr>' +
    //        '<th colspan="7" class="datepicker-title"></th>' +
    //        '</tr>' +
    //        '<tr>' +
    //        '<th class="prev">' + defaults.templates.leftArrow + '</th>' +
    //        '<th colspan="5" class="switch"></th>' +
    //        '<th class="next">' + defaults.templates.rightArrow + '</th>' +
    //        '</tr>' +
    //        '</thead>',
    //    contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
    //    footTemplate: '<tfoot>' +
    //        '<tr>' +
    //        '<th colspan="7" class="today"></th>' +
    //        '</tr>' +
    //        '<tr>' +
    //        '<th colspan="7" class="clear"></th>' +
    //        '</tr>' +
    //        '</tfoot>'
    //};
    //DPGlobal.template = '<div class="datepicker">' +
    //    '<div class="datepicker-days">' +
    //    '<table class="table-condensed">' +
    //    DPGlobal.headTemplate +
    //    '<tbody></tbody>' +
    //    DPGlobal.footTemplate +
    //    '</table>' +
    //    '</div>' +
    //    '<div class="datepicker-months">' +
    //    '<table class="table-condensed">' +
    //    DPGlobal.headTemplate +
    //    DPGlobal.contTemplate +
    //    DPGlobal.footTemplate +
    //    '</table>' +
    //    '</div>' +
    //    '<div class="datepicker-years">' +
    //    '<table class="table-condensed">' +
    //    DPGlobal.headTemplate +
    //    DPGlobal.contTemplate +
    //    DPGlobal.footTemplate +
    //    '</table>' +
    //    '</div>' +
    //    '<div class="datepicker-decades">' +
    //    '<table class="table-condensed">' +
    //    DPGlobal.headTemplate +
    //    DPGlobal.contTemplate +
    //    DPGlobal.footTemplate +
    //    '</table>' +
    //    '</div>' +
    //    '<div class="datepicker-centuries">' +
    //    '<table class="table-condensed">' +
    //    DPGlobal.headTemplate +
    //    DPGlobal.contTemplate +
    //    DPGlobal.footTemplate +
    //    '</table>' +
    //    '</div>' +
    //    '</div>';

    $.fn.datepicker.DPGlobal = DPGlobal;


	/* DATEPICKER NO CONFLICT
	* =================== */

    $.fn.datepicker.noConflict = function () {
        $.fn.datepicker = old;
        return this;
    };

	/* DATEPICKER VERSION
	 * =================== */
    $.fn.datepicker.version = '1.8.0';

    $.fn.datepicker.deprecated = function (msg) {
        var console = window.console;
        if (console && console.warn) {
            console.warn('DEPRECATED: ' + msg);
        }
    };


	/* DATEPICKER DATA-API
	* ================== */

    $(document).on(
        'focus.datepicker.data-api click.datepicker.data-api',
        '[data-provide="datepicker"]',
        function (e) {
            var $this = $(this);
            if ($this.data('datepicker'))
                return;
            e.preventDefault();
            // component click requires us to explicitly show it
            datepickerPlugin.call($this, 'show');
        }
    );
    $(function () {
        datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
    });

}));



//    headTemplate: '<thead>' +
//							'<tr>' +
//								'<th class="prev">&lsaquo;</th>' +
//								'<th colspan="5" class="switch"></th>' +
//								'<th class="next">&rsaquo;</th>' +
//							'</tr>' +
//						'</thead>',
//    contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
//  };
//  DPGlobal.template = '<div class="datepicker dropdown-menu">' +
//							'<div class="datepicker-days">' +
//								'<table class=" table-condensed">' +
//									DPGlobal.headTemplate +
//									'<tbody></tbody>' +
//								'</table>' +
//							'</div>' +
//							'<div class="datepicker-months">' +
//								'<table class="table-condensed">' +
//									DPGlobal.headTemplate +
//									DPGlobal.contTemplate +
//								'</table>' +
//							'</div>' +
//							'<div class="datepicker-years">' +
//								'<table class="table-condensed">' +
//									DPGlobal.headTemplate +
//									DPGlobal.contTemplate +
//								'</table>' +
//							'</div>' +
//						'</div>';

//})(window.jQuery);;
/*!
 * Flickity PACKAGED v2.2.1
 * Touch, responsive, flickable carousels
 *
 * Licensed GPLv3 for open source use
 * or Flickity Commercial License for commercial use
 *
 * https://flickity.metafizzy.co
 * Copyright 2015-2019 Metafizzy
 */

!function(e,i){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("jquery")):e.jQueryBridget=i(e,e.jQuery)}(window,function(t,e){"use strict";var i=Array.prototype.slice,n=t.console,d=void 0===n?function(){}:function(t){n.error(t)};function s(h,s,c){(c=c||e||t.jQuery)&&(s.prototype.option||(s.prototype.option=function(t){c.isPlainObject(t)&&(this.options=c.extend(!0,this.options,t))}),c.fn[h]=function(t){return"string"==typeof t?function(t,o,r){var a,l="$()."+h+'("'+o+'")';return t.each(function(t,e){var i=c.data(e,h);if(i){var n=i[o];if(n&&"_"!=o.charAt(0)){var s=n.apply(i,r);a=void 0===a?s:a}else d(l+" is not a valid method")}else d(h+" not initialized. Cannot call methods, i.e. "+l)}),void 0!==a?a:t}(this,t,i.call(arguments,1)):(function(t,n){t.each(function(t,e){var i=c.data(e,h);i?(i.option(n),i._init()):(i=new s(e,n),c.data(e,h,i))})}(this,t),this)},o(c))}function o(t){!t||t&&t.bridget||(t.bridget=s)}return o(e||t.jQuery),s}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var n=this._onceEvents&&this._onceEvents[t],s=0;s<i.length;s++){var o=i[s];n&&n[o]&&(this.off(t,o),delete n[o]),o.apply(this,e)}return this}},e.allOff=function(){delete this._events,delete this._onceEvents},t}),function(t,e){"function"==typeof define&&define.amd?define("get-size/get-size",e):"object"==typeof module&&module.exports?module.exports=e():t.getSize=e()}(window,function(){"use strict";function m(t){var e=parseFloat(t);return-1==t.indexOf("%")&&!isNaN(e)&&e}var i="undefined"==typeof console?function(){}:function(t){console.error(t)},y=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],b=y.length;function E(t){var e=getComputedStyle(t);return e||i("Style returned "+e+". Are you running this code in a hidden iframe on Firefox? See https://bit.ly/getsizebug1"),e}var S,C=!1;function x(t){if(function(){if(!C){C=!0;var t=document.createElement("div");t.style.width="200px",t.style.padding="1px 2px 3px 4px",t.style.borderStyle="solid",t.style.borderWidth="1px 2px 3px 4px",t.style.boxSizing="border-box";var e=document.body||document.documentElement;e.appendChild(t);var i=E(t);S=200==Math.round(m(i.width)),x.isBoxSizeOuter=S,e.removeChild(t)}}(),"string"==typeof t&&(t=document.querySelector(t)),t&&"object"==typeof t&&t.nodeType){var e=E(t);if("none"==e.display)return function(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},e=0;e<b;e++){t[y[e]]=0}return t}();var i={};i.width=t.offsetWidth,i.height=t.offsetHeight;for(var n=i.isBorderBox="border-box"==e.boxSizing,s=0;s<b;s++){var o=y[s],r=e[o],a=parseFloat(r);i[o]=isNaN(a)?0:a}var l=i.paddingLeft+i.paddingRight,h=i.paddingTop+i.paddingBottom,c=i.marginLeft+i.marginRight,d=i.marginTop+i.marginBottom,u=i.borderLeftWidth+i.borderRightWidth,f=i.borderTopWidth+i.borderBottomWidth,p=n&&S,g=m(e.width);!1!==g&&(i.width=g+(p?0:l+u));var v=m(e.height);return!1!==v&&(i.height=v+(p?0:h+f)),i.innerWidth=i.width-(l+u),i.innerHeight=i.height-(h+f),i.outerWidth=i.width+c,i.outerHeight=i.height+d,i}}return x}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("desandro-matches-selector/matches-selector",e):"object"==typeof module&&module.exports?module.exports=e():t.matchesSelector=e()}(window,function(){"use strict";var i=function(){var t=window.Element.prototype;if(t.matches)return"matches";if(t.matchesSelector)return"matchesSelector";for(var e=["webkit","moz","ms","o"],i=0;i<e.length;i++){var n=e[i]+"MatchesSelector";if(t[n])return n}}();return function(t,e){return t[i](e)}}),function(e,i){"function"==typeof define&&define.amd?define("fizzy-ui-utils/utils",["desandro-matches-selector/matches-selector"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("desandro-matches-selector")):e.fizzyUIUtils=i(e,e.matchesSelector)}(window,function(h,o){var c={extend:function(t,e){for(var i in e)t[i]=e[i];return t},modulo:function(t,e){return(t%e+e)%e}},e=Array.prototype.slice;c.makeArray=function(t){return Array.isArray(t)?t:null==t?[]:"object"==typeof t&&"number"==typeof t.length?e.call(t):[t]},c.removeFrom=function(t,e){var i=t.indexOf(e);-1!=i&&t.splice(i,1)},c.getParent=function(t,e){for(;t.parentNode&&t!=document.body;)if(t=t.parentNode,o(t,e))return t},c.getQueryElement=function(t){return"string"==typeof t?document.querySelector(t):t},c.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},c.filterFindElements=function(t,n){t=c.makeArray(t);var s=[];return t.forEach(function(t){if(t instanceof HTMLElement)if(n){o(t,n)&&s.push(t);for(var e=t.querySelectorAll(n),i=0;i<e.length;i++)s.push(e[i])}else s.push(t)}),s},c.debounceMethod=function(t,e,n){n=n||100;var s=t.prototype[e],o=e+"Timeout";t.prototype[e]=function(){var t=this[o];clearTimeout(t);var e=arguments,i=this;this[o]=setTimeout(function(){s.apply(i,e),delete i[o]},n)}},c.docReady=function(t){var e=document.readyState;"complete"==e||"interactive"==e?setTimeout(t):document.addEventListener("DOMContentLoaded",t)},c.toDashed=function(t){return t.replace(/(.)([A-Z])/g,function(t,e,i){return e+"-"+i}).toLowerCase()};var d=h.console;return c.htmlInit=function(a,l){c.docReady(function(){var t=c.toDashed(l),s="data-"+t,e=document.querySelectorAll("["+s+"]"),i=document.querySelectorAll(".js-"+t),n=c.makeArray(e).concat(c.makeArray(i)),o=s+"-options",r=h.jQuery;n.forEach(function(e){var t,i=e.getAttribute(s)||e.getAttribute(o);try{t=i&&JSON.parse(i)}catch(t){return void(d&&d.error("Error parsing "+s+" on "+e.className+": "+t))}var n=new a(e,t);r&&r.data(e,l,n)})})},c}),function(e,i){"function"==typeof define&&define.amd?define("flickity/js/cell",["get-size/get-size"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("get-size")):(e.Flickity=e.Flickity||{},e.Flickity.Cell=i(e,e.getSize))}(window,function(t,e){function i(t,e){this.element=t,this.parent=e,this.create()}var n=i.prototype;return n.create=function(){this.element.style.position="absolute",this.element.setAttribute("aria-hidden","true"),this.x=0,this.shift=0},n.destroy=function(){this.unselect(),this.element.style.position="";var t=this.parent.originSide;this.element.style[t]=""},n.getSize=function(){this.size=e(this.element)},n.setPosition=function(t){this.x=t,this.updateTarget(),this.renderPosition(t)},n.updateTarget=n.setDefaultTarget=function(){var t="left"==this.parent.originSide?"marginLeft":"marginRight";this.target=this.x+this.size[t]+this.size.width*this.parent.cellAlign},n.renderPosition=function(t){var e=this.parent.originSide;this.element.style[e]=this.parent.getPositionValue(t)},n.select=function(){this.element.classList.add("is-selected"),this.element.removeAttribute("aria-hidden")},n.unselect=function(){this.element.classList.remove("is-selected"),this.element.setAttribute("aria-hidden","true")},n.wrapShift=function(t){this.shift=t,this.renderPosition(this.x+this.parent.slideableWidth*t)},n.remove=function(){this.element.parentNode.removeChild(this.element)},i}),function(t,e){"function"==typeof define&&define.amd?define("flickity/js/slide",e):"object"==typeof module&&module.exports?module.exports=e():(t.Flickity=t.Flickity||{},t.Flickity.Slide=e())}(window,function(){"use strict";function t(t){this.parent=t,this.isOriginLeft="left"==t.originSide,this.cells=[],this.outerWidth=0,this.height=0}var e=t.prototype;return e.addCell=function(t){if(this.cells.push(t),this.outerWidth+=t.size.outerWidth,this.height=Math.max(t.size.outerHeight,this.height),1==this.cells.length){this.x=t.x;var e=this.isOriginLeft?"marginLeft":"marginRight";this.firstMargin=t.size[e]}},e.updateTarget=function(){var t=this.isOriginLeft?"marginRight":"marginLeft",e=this.getLastCell(),i=e?e.size[t]:0,n=this.outerWidth-(this.firstMargin+i);this.target=this.x+this.firstMargin+n*this.parent.cellAlign},e.getLastCell=function(){return this.cells[this.cells.length-1]},e.select=function(){this.cells.forEach(function(t){t.select()})},e.unselect=function(){this.cells.forEach(function(t){t.unselect()})},e.getCellElements=function(){return this.cells.map(function(t){return t.element})},t}),function(e,i){"function"==typeof define&&define.amd?define("flickity/js/animate",["fizzy-ui-utils/utils"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("fizzy-ui-utils")):(e.Flickity=e.Flickity||{},e.Flickity.animatePrototype=i(e,e.fizzyUIUtils))}(window,function(t,e){var i={startAnimation:function(){this.isAnimating||(this.isAnimating=!0,this.restingFrames=0,this.animate())},animate:function(){this.applyDragForce(),this.applySelectedAttraction();var t=this.x;if(this.integratePhysics(),this.positionSlider(),this.settle(t),this.isAnimating){var e=this;requestAnimationFrame(function(){e.animate()})}},positionSlider:function(){var t=this.x;this.options.wrapAround&&1<this.cells.length&&(t=e.modulo(t,this.slideableWidth),t-=this.slideableWidth,this.shiftWrapCells(t)),this.setTranslateX(t,this.isAnimating),this.dispatchScrollEvent()},setTranslateX:function(t,e){t+=this.cursorPosition,t=this.options.rightToLeft?-t:t;var i=this.getPositionValue(t);this.slider.style.transform=e?"translate3d("+i+",0,0)":"translateX("+i+")"},dispatchScrollEvent:function(){var t=this.slides[0];if(t){var e=-this.x-t.target,i=e/this.slidesWidth;this.dispatchEvent("scroll",null,[i,e])}},positionSliderAtSelected:function(){this.cells.length&&(this.x=-this.selectedSlide.target,this.velocity=0,this.positionSlider())},getPositionValue:function(t){return this.options.percentPosition?.01*Math.round(t/this.size.innerWidth*1e4)+"%":Math.round(t)+"px"},settle:function(t){this.isPointerDown||Math.round(100*this.x)!=Math.round(100*t)||this.restingFrames++,2<this.restingFrames&&(this.isAnimating=!1,delete this.isFreeScrolling,this.positionSlider(),this.dispatchEvent("settle",null,[this.selectedIndex]))},shiftWrapCells:function(t){var e=this.cursorPosition+t;this._shiftCells(this.beforeShiftCells,e,-1);var i=this.size.innerWidth-(t+this.slideableWidth+this.cursorPosition);this._shiftCells(this.afterShiftCells,i,1)},_shiftCells:function(t,e,i){for(var n=0;n<t.length;n++){var s=t[n],o=0<e?i:0;s.wrapShift(o),e-=s.size.outerWidth}},_unshiftCells:function(t){if(t&&t.length)for(var e=0;e<t.length;e++)t[e].wrapShift(0)},integratePhysics:function(){this.x+=this.velocity,this.velocity*=this.getFrictionFactor()},applyForce:function(t){this.velocity+=t},getFrictionFactor:function(){return 1-this.options[this.isFreeScrolling?"freeScrollFriction":"friction"]},getRestingPosition:function(){return this.x+this.velocity/(1-this.getFrictionFactor())},applyDragForce:function(){if(this.isDraggable&&this.isPointerDown){var t=this.dragX-this.x-this.velocity;this.applyForce(t)}},applySelectedAttraction:function(){if(!(this.isDraggable&&this.isPointerDown)&&!this.isFreeScrolling&&this.slides.length){var t=(-1*this.selectedSlide.target-this.x)*this.options.selectedAttraction;this.applyForce(t)}}};return i}),function(r,a){if("function"==typeof define&&define.amd)define("flickity/js/flickity",["ev-emitter/ev-emitter","get-size/get-size","fizzy-ui-utils/utils","./cell","./slide","./animate"],function(t,e,i,n,s,o){return a(r,t,e,i,n,s,o)});else if("object"==typeof module&&module.exports)module.exports=a(r,require("ev-emitter"),require("get-size"),require("fizzy-ui-utils"),require("./cell"),require("./slide"),require("./animate"));else{var t=r.Flickity;r.Flickity=a(r,r.EvEmitter,r.getSize,r.fizzyUIUtils,t.Cell,t.Slide,t.animatePrototype)}}(window,function(n,t,e,a,i,r,s){var l=n.jQuery,o=n.getComputedStyle,h=n.console;function c(t,e){for(t=a.makeArray(t);t.length;)e.appendChild(t.shift())}var d=0,u={};function f(t,e){var i=a.getQueryElement(t);if(i){if(this.element=i,this.element.flickityGUID){var n=u[this.element.flickityGUID];return n.option(e),n}l&&(this.$element=l(this.element)),this.options=a.extend({},this.constructor.defaults),this.option(e),this._create()}else h&&h.error("Bad element for Flickity: "+(i||t))}f.defaults={accessibility:!0,cellAlign:"center",freeScrollFriction:.075,friction:.28,namespaceJQueryEvents:!0,percentPosition:!0,resize:!0,selectedAttraction:.025,setGallerySize:!0},f.createMethods=[];var p=f.prototype;a.extend(p,t.prototype),p._create=function(){var t=this.guid=++d;for(var e in this.element.flickityGUID=t,(u[t]=this).selectedIndex=0,this.restingFrames=0,this.x=0,this.velocity=0,this.originSide=this.options.rightToLeft?"right":"left",this.viewport=document.createElement("div"),this.viewport.className="flickity-viewport",this._createSlider(),(this.options.resize||this.options.watchCSS)&&n.addEventListener("resize",this),this.options.on){var i=this.options.on[e];this.on(e,i)}f.createMethods.forEach(function(t){this[t]()},this),this.options.watchCSS?this.watchCSS():this.activate()},p.option=function(t){a.extend(this.options,t)},p.activate=function(){this.isActive||(this.isActive=!0,this.element.classList.add("flickity-enabled"),this.options.rightToLeft&&this.element.classList.add("flickity-rtl"),this.getSize(),c(this._filterFindCellElements(this.element.children),this.slider),this.viewport.appendChild(this.slider),this.element.appendChild(this.viewport),this.reloadCells(),this.options.accessibility&&(this.element.tabIndex=0,this.element.addEventListener("keydown",this)),this.emitEvent("activate"),this.selectInitialIndex(),this.isInitActivated=!0,this.dispatchEvent("ready"))},p._createSlider=function(){var t=document.createElement("div");t.className="flickity-slider",t.style[this.originSide]=0,this.slider=t},p._filterFindCellElements=function(t){return a.filterFindElements(t,this.options.cellSelector)},p.reloadCells=function(){this.cells=this._makeCells(this.slider.children),this.positionCells(),this._getWrapShiftCells(),this.setGallerySize()},p._makeCells=function(t){return this._filterFindCellElements(t).map(function(t){return new i(t,this)},this)},p.getLastCell=function(){return this.cells[this.cells.length-1]},p.getLastSlide=function(){return this.slides[this.slides.length-1]},p.positionCells=function(){this._sizeCells(this.cells),this._positionCells(0)},p._positionCells=function(t){t=t||0,this.maxCellHeight=t&&this.maxCellHeight||0;var e=0;if(0<t){var i=this.cells[t-1];e=i.x+i.size.outerWidth}for(var n=this.cells.length,s=t;s<n;s++){var o=this.cells[s];o.setPosition(e),e+=o.size.outerWidth,this.maxCellHeight=Math.max(o.size.outerHeight,this.maxCellHeight)}this.slideableWidth=e,this.updateSlides(),this._containSlides(),this.slidesWidth=n?this.getLastSlide().target-this.slides[0].target:0},p._sizeCells=function(t){t.forEach(function(t){t.getSize()})},p.updateSlides=function(){if(this.slides=[],this.cells.length){var n=new r(this);this.slides.push(n);var s="left"==this.originSide?"marginRight":"marginLeft",o=this._getCanCellFit();this.cells.forEach(function(t,e){if(n.cells.length){var i=n.outerWidth-n.firstMargin+(t.size.outerWidth-t.size[s]);o.call(this,e,i)||(n.updateTarget(),n=new r(this),this.slides.push(n)),n.addCell(t)}else n.addCell(t)},this),n.updateTarget(),this.updateSelectedSlide()}},p._getCanCellFit=function(){var t=this.options.groupCells;if(!t)return function(){return!1};if("number"==typeof t){var e=parseInt(t,10);return function(t){return t%e!=0}}var i="string"==typeof t&&t.match(/^(\d+)%$/),n=i?parseInt(i[1],10)/100:1;return function(t,e){return e<=(this.size.innerWidth+1)*n}},p._init=p.reposition=function(){this.positionCells(),this.positionSliderAtSelected()},p.getSize=function(){this.size=e(this.element),this.setCellAlign(),this.cursorPosition=this.size.innerWidth*this.cellAlign};var g={center:{left:.5,right:.5},left:{left:0,right:1},right:{right:0,left:1}};return p.setCellAlign=function(){var t=g[this.options.cellAlign];this.cellAlign=t?t[this.originSide]:this.options.cellAlign},p.setGallerySize=function(){if(this.options.setGallerySize){var t=this.options.adaptiveHeight&&this.selectedSlide?this.selectedSlide.height:this.maxCellHeight;this.viewport.style.height=t+"px"}},p._getWrapShiftCells=function(){if(this.options.wrapAround){this._unshiftCells(this.beforeShiftCells),this._unshiftCells(this.afterShiftCells);var t=this.cursorPosition,e=this.cells.length-1;this.beforeShiftCells=this._getGapCells(t,e,-1),t=this.size.innerWidth-this.cursorPosition,this.afterShiftCells=this._getGapCells(t,0,1)}},p._getGapCells=function(t,e,i){for(var n=[];0<t;){var s=this.cells[e];if(!s)break;n.push(s),e+=i,t-=s.size.outerWidth}return n},p._containSlides=function(){if(this.options.contain&&!this.options.wrapAround&&this.cells.length){var t=this.options.rightToLeft,e=t?"marginRight":"marginLeft",i=t?"marginLeft":"marginRight",n=this.slideableWidth-this.getLastCell().size[i],s=n<this.size.innerWidth,o=this.cursorPosition+this.cells[0].size[e],r=n-this.size.innerWidth*(1-this.cellAlign);this.slides.forEach(function(t){s?t.target=n*this.cellAlign:(t.target=Math.max(t.target,o),t.target=Math.min(t.target,r))},this)}},p.dispatchEvent=function(t,e,i){var n=e?[e].concat(i):i;if(this.emitEvent(t,n),l&&this.$element){var s=t+=this.options.namespaceJQueryEvents?".flickity":"";if(e){var o=l.Event(e);o.type=t,s=o}this.$element.trigger(s,i)}},p.select=function(t,e,i){if(this.isActive&&(t=parseInt(t,10),this._wrapSelect(t),(this.options.wrapAround||e)&&(t=a.modulo(t,this.slides.length)),this.slides[t])){var n=this.selectedIndex;this.selectedIndex=t,this.updateSelectedSlide(),i?this.positionSliderAtSelected():this.startAnimation(),this.options.adaptiveHeight&&this.setGallerySize(),this.dispatchEvent("select",null,[t]),t!=n&&this.dispatchEvent("change",null,[t]),this.dispatchEvent("cellSelect")}},p._wrapSelect=function(t){var e=this.slides.length;if(!(this.options.wrapAround&&1<e))return t;var i=a.modulo(t,e),n=Math.abs(i-this.selectedIndex),s=Math.abs(i+e-this.selectedIndex),o=Math.abs(i-e-this.selectedIndex);!this.isDragSelect&&s<n?t+=e:!this.isDragSelect&&o<n&&(t-=e),t<0?this.x-=this.slideableWidth:e<=t&&(this.x+=this.slideableWidth)},p.previous=function(t,e){this.select(this.selectedIndex-1,t,e)},p.next=function(t,e){this.select(this.selectedIndex+1,t,e)},p.updateSelectedSlide=function(){var t=this.slides[this.selectedIndex];t&&(this.unselectSelectedSlide(),(this.selectedSlide=t).select(),this.selectedCells=t.cells,this.selectedElements=t.getCellElements(),this.selectedCell=t.cells[0],this.selectedElement=this.selectedElements[0])},p.unselectSelectedSlide=function(){this.selectedSlide&&this.selectedSlide.unselect()},p.selectInitialIndex=function(){var t=this.options.initialIndex;if(this.isInitActivated)this.select(this.selectedIndex,!1,!0);else{if(t&&"string"==typeof t)if(this.queryCell(t))return void this.selectCell(t,!1,!0);var e=0;t&&this.slides[t]&&(e=t),this.select(e,!1,!0)}},p.selectCell=function(t,e,i){var n=this.queryCell(t);if(n){var s=this.getCellSlideIndex(n);this.select(s,e,i)}},p.getCellSlideIndex=function(t){for(var e=0;e<this.slides.length;e++){if(-1!=this.slides[e].cells.indexOf(t))return e}},p.getCell=function(t){for(var e=0;e<this.cells.length;e++){var i=this.cells[e];if(i.element==t)return i}},p.getCells=function(t){t=a.makeArray(t);var i=[];return t.forEach(function(t){var e=this.getCell(t);e&&i.push(e)},this),i},p.getCellElements=function(){return this.cells.map(function(t){return t.element})},p.getParentCell=function(t){var e=this.getCell(t);return e||(t=a.getParent(t,".flickity-slider > *"),this.getCell(t))},p.getAdjacentCellElements=function(t,e){if(!t)return this.selectedSlide.getCellElements();e=void 0===e?this.selectedIndex:e;var i=this.slides.length;if(i<=1+2*t)return this.getCellElements();for(var n=[],s=e-t;s<=e+t;s++){var o=this.options.wrapAround?a.modulo(s,i):s,r=this.slides[o];r&&(n=n.concat(r.getCellElements()))}return n},p.queryCell=function(t){if("number"==typeof t)return this.cells[t];if("string"==typeof t){if(t.match(/^[#\.]?[\d\/]/))return;t=this.element.querySelector(t)}return this.getCell(t)},p.uiChange=function(){this.emitEvent("uiChange")},p.childUIPointerDown=function(t){"touchstart"!=t.type&&t.preventDefault(),this.focus()},p.onresize=function(){this.watchCSS(),this.resize()},a.debounceMethod(f,"onresize",150),p.resize=function(){if(this.isActive){this.getSize(),this.options.wrapAround&&(this.x=a.modulo(this.x,this.slideableWidth)),this.positionCells(),this._getWrapShiftCells(),this.setGallerySize(),this.emitEvent("resize");var t=this.selectedElements&&this.selectedElements[0];this.selectCell(t,!1,!0)}},p.watchCSS=function(){this.options.watchCSS&&(-1!=o(this.element,":after").content.indexOf("flickity")?this.activate():this.deactivate())},p.onkeydown=function(t){var e=document.activeElement&&document.activeElement!=this.element;if(this.options.accessibility&&!e){var i=f.keyboardHandlers[t.keyCode];i&&i.call(this)}},f.keyboardHandlers={37:function(){var t=this.options.rightToLeft?"next":"previous";this.uiChange(),this[t]()},39:function(){var t=this.options.rightToLeft?"previous":"next";this.uiChange(),this[t]()}},p.focus=function(){var t=n.pageYOffset;this.element.focus({preventScroll:!0}),n.pageYOffset!=t&&n.scrollTo(n.pageXOffset,t)},p.deactivate=function(){this.isActive&&(this.element.classList.remove("flickity-enabled"),this.element.classList.remove("flickity-rtl"),this.unselectSelectedSlide(),this.cells.forEach(function(t){t.destroy()}),this.element.removeChild(this.viewport),c(this.slider.children,this.element),this.options.accessibility&&(this.element.removeAttribute("tabIndex"),this.element.removeEventListener("keydown",this)),this.isActive=!1,this.emitEvent("deactivate"))},p.destroy=function(){this.deactivate(),n.removeEventListener("resize",this),this.allOff(),this.emitEvent("destroy"),l&&this.$element&&l.removeData(this.element,"flickity"),delete this.element.flickityGUID,delete u[this.guid]},a.extend(p,s),f.data=function(t){var e=(t=a.getQueryElement(t))&&t.flickityGUID;return e&&u[e]},a.htmlInit(f,"flickity"),l&&l.bridget&&l.bridget("flickity",f),f.setJQuery=function(t){l=t},f.Cell=i,f.Slide=r,f}),function(e,i){"function"==typeof define&&define.amd?define("unipointer/unipointer",["ev-emitter/ev-emitter"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("ev-emitter")):e.Unipointer=i(e,e.EvEmitter)}(window,function(s,t){function e(){}var i=e.prototype=Object.create(t.prototype);i.bindStartEvent=function(t){this._bindStartEvent(t,!0)},i.unbindStartEvent=function(t){this._bindStartEvent(t,!1)},i._bindStartEvent=function(t,e){var i=(e=void 0===e||e)?"addEventListener":"removeEventListener",n="mousedown";s.PointerEvent?n="pointerdown":"ontouchstart"in s&&(n="touchstart"),t[i](n,this)},i.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.getTouch=function(t){for(var e=0;e<t.length;e++){var i=t[e];if(i.identifier==this.pointerIdentifier)return i}},i.onmousedown=function(t){var e=t.button;e&&0!==e&&1!==e||this._pointerDown(t,t)},i.ontouchstart=function(t){this._pointerDown(t,t.changedTouches[0])},i.onpointerdown=function(t){this._pointerDown(t,t)},i._pointerDown=function(t,e){t.button||this.isPointerDown||(this.isPointerDown=!0,this.pointerIdentifier=void 0!==e.pointerId?e.pointerId:e.identifier,this.pointerDown(t,e))},i.pointerDown=function(t,e){this._bindPostStartEvents(t),this.emitEvent("pointerDown",[t,e])};var n={mousedown:["mousemove","mouseup"],touchstart:["touchmove","touchend","touchcancel"],pointerdown:["pointermove","pointerup","pointercancel"]};return i._bindPostStartEvents=function(t){if(t){var e=n[t.type];e.forEach(function(t){s.addEventListener(t,this)},this),this._boundPointerEvents=e}},i._unbindPostStartEvents=function(){this._boundPointerEvents&&(this._boundPointerEvents.forEach(function(t){s.removeEventListener(t,this)},this),delete this._boundPointerEvents)},i.onmousemove=function(t){this._pointerMove(t,t)},i.onpointermove=function(t){t.pointerId==this.pointerIdentifier&&this._pointerMove(t,t)},i.ontouchmove=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerMove(t,e)},i._pointerMove=function(t,e){this.pointerMove(t,e)},i.pointerMove=function(t,e){this.emitEvent("pointerMove",[t,e])},i.onmouseup=function(t){this._pointerUp(t,t)},i.onpointerup=function(t){t.pointerId==this.pointerIdentifier&&this._pointerUp(t,t)},i.ontouchend=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerUp(t,e)},i._pointerUp=function(t,e){this._pointerDone(),this.pointerUp(t,e)},i.pointerUp=function(t,e){this.emitEvent("pointerUp",[t,e])},i._pointerDone=function(){this._pointerReset(),this._unbindPostStartEvents(),this.pointerDone()},i._pointerReset=function(){this.isPointerDown=!1,delete this.pointerIdentifier},i.pointerDone=function(){},i.onpointercancel=function(t){t.pointerId==this.pointerIdentifier&&this._pointerCancel(t,t)},i.ontouchcancel=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerCancel(t,e)},i._pointerCancel=function(t,e){this._pointerDone(),this.pointerCancel(t,e)},i.pointerCancel=function(t,e){this.emitEvent("pointerCancel",[t,e])},e.getPointerPoint=function(t){return{x:t.pageX,y:t.pageY}},e}),function(e,i){"function"==typeof define&&define.amd?define("unidragger/unidragger",["unipointer/unipointer"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("unipointer")):e.Unidragger=i(e,e.Unipointer)}(window,function(o,t){function e(){}var i=e.prototype=Object.create(t.prototype);i.bindHandles=function(){this._bindHandles(!0)},i.unbindHandles=function(){this._bindHandles(!1)},i._bindHandles=function(t){for(var e=(t=void 0===t||t)?"addEventListener":"removeEventListener",i=t?this._touchActionValue:"",n=0;n<this.handles.length;n++){var s=this.handles[n];this._bindStartEvent(s,t),s[e]("click",this),o.PointerEvent&&(s.style.touchAction=i)}},i._touchActionValue="none",i.pointerDown=function(t,e){this.okayPointerDown(t)&&(this.pointerDownPointer=e,t.preventDefault(),this.pointerDownBlur(),this._bindPostStartEvents(t),this.emitEvent("pointerDown",[t,e]))};var s={TEXTAREA:!0,INPUT:!0,SELECT:!0,OPTION:!0},r={radio:!0,checkbox:!0,button:!0,submit:!0,image:!0,file:!0};return i.okayPointerDown=function(t){var e=s[t.target.nodeName],i=r[t.target.type],n=!e||i;return n||this._pointerReset(),n},i.pointerDownBlur=function(){var t=document.activeElement;t&&t.blur&&t!=document.body&&t.blur()},i.pointerMove=function(t,e){var i=this._dragPointerMove(t,e);this.emitEvent("pointerMove",[t,e,i]),this._dragMove(t,e,i)},i._dragPointerMove=function(t,e){var i={x:e.pageX-this.pointerDownPointer.pageX,y:e.pageY-this.pointerDownPointer.pageY};return!this.isDragging&&this.hasDragStarted(i)&&this._dragStart(t,e),i},i.hasDragStarted=function(t){return 3<Math.abs(t.x)||3<Math.abs(t.y)},i.pointerUp=function(t,e){this.emitEvent("pointerUp",[t,e]),this._dragPointerUp(t,e)},i._dragPointerUp=function(t,e){this.isDragging?this._dragEnd(t,e):this._staticClick(t,e)},i._dragStart=function(t,e){this.isDragging=!0,this.isPreventingClicks=!0,this.dragStart(t,e)},i.dragStart=function(t,e){this.emitEvent("dragStart",[t,e])},i._dragMove=function(t,e,i){this.isDragging&&this.dragMove(t,e,i)},i.dragMove=function(t,e,i){t.preventDefault(),this.emitEvent("dragMove",[t,e,i])},i._dragEnd=function(t,e){this.isDragging=!1,setTimeout(function(){delete this.isPreventingClicks}.bind(this)),this.dragEnd(t,e)},i.dragEnd=function(t,e){this.emitEvent("dragEnd",[t,e])},i.onclick=function(t){this.isPreventingClicks&&t.preventDefault()},i._staticClick=function(t,e){this.isIgnoringMouseUp&&"mouseup"==t.type||(this.staticClick(t,e),"mouseup"!=t.type&&(this.isIgnoringMouseUp=!0,setTimeout(function(){delete this.isIgnoringMouseUp}.bind(this),400)))},i.staticClick=function(t,e){this.emitEvent("staticClick",[t,e])},e.getPointerPoint=t.getPointerPoint,e}),function(n,s){"function"==typeof define&&define.amd?define("flickity/js/drag",["./flickity","unidragger/unidragger","fizzy-ui-utils/utils"],function(t,e,i){return s(n,t,e,i)}):"object"==typeof module&&module.exports?module.exports=s(n,require("./flickity"),require("unidragger"),require("fizzy-ui-utils")):n.Flickity=s(n,n.Flickity,n.Unidragger,n.fizzyUIUtils)}(window,function(i,t,e,a){a.extend(t.defaults,{draggable:">1",dragThreshold:3}),t.createMethods.push("_createDrag");var n=t.prototype;a.extend(n,e.prototype),n._touchActionValue="pan-y";var s="createTouch"in document,o=!1;n._createDrag=function(){this.on("activate",this.onActivateDrag),this.on("uiChange",this._uiChangeDrag),this.on("deactivate",this.onDeactivateDrag),this.on("cellChange",this.updateDraggable),s&&!o&&(i.addEventListener("touchmove",function(){}),o=!0)},n.onActivateDrag=function(){this.handles=[this.viewport],this.bindHandles(),this.updateDraggable()},n.onDeactivateDrag=function(){this.unbindHandles(),this.element.classList.remove("is-draggable")},n.updateDraggable=function(){">1"==this.options.draggable?this.isDraggable=1<this.slides.length:this.isDraggable=this.options.draggable,this.isDraggable?this.element.classList.add("is-draggable"):this.element.classList.remove("is-draggable")},n.bindDrag=function(){this.options.draggable=!0,this.updateDraggable()},n.unbindDrag=function(){this.options.draggable=!1,this.updateDraggable()},n._uiChangeDrag=function(){delete this.isFreeScrolling},n.pointerDown=function(t,e){this.isDraggable?this.okayPointerDown(t)&&(this._pointerDownPreventDefault(t),this.pointerDownFocus(t),document.activeElement!=this.element&&this.pointerDownBlur(),this.dragX=this.x,this.viewport.classList.add("is-pointer-down"),this.pointerDownScroll=l(),i.addEventListener("scroll",this),this._pointerDownDefault(t,e)):this._pointerDownDefault(t,e)},n._pointerDownDefault=function(t,e){this.pointerDownPointer={pageX:e.pageX,pageY:e.pageY},this._bindPostStartEvents(t),this.dispatchEvent("pointerDown",t,[e])};var r={INPUT:!0,TEXTAREA:!0,SELECT:!0};function l(){return{x:i.pageXOffset,y:i.pageYOffset}}return n.pointerDownFocus=function(t){r[t.target.nodeName]||this.focus()},n._pointerDownPreventDefault=function(t){var e="touchstart"==t.type,i="touch"==t.pointerType,n=r[t.target.nodeName];e||i||n||t.preventDefault()},n.hasDragStarted=function(t){return Math.abs(t.x)>this.options.dragThreshold},n.pointerUp=function(t,e){delete this.isTouchScrolling,this.viewport.classList.remove("is-pointer-down"),this.dispatchEvent("pointerUp",t,[e]),this._dragPointerUp(t,e)},n.pointerDone=function(){i.removeEventListener("scroll",this),delete this.pointerDownScroll},n.dragStart=function(t,e){this.isDraggable&&(this.dragStartPosition=this.x,this.startAnimation(),i.removeEventListener("scroll",this),this.dispatchEvent("dragStart",t,[e]))},n.pointerMove=function(t,e){var i=this._dragPointerMove(t,e);this.dispatchEvent("pointerMove",t,[e,i]),this._dragMove(t,e,i)},n.dragMove=function(t,e,i){if(this.isDraggable){t.preventDefault(),this.previousDragX=this.dragX;var n=this.options.rightToLeft?-1:1;this.options.wrapAround&&(i.x=i.x%this.slideableWidth);var s=this.dragStartPosition+i.x*n;if(!this.options.wrapAround&&this.slides.length){var o=Math.max(-this.slides[0].target,this.dragStartPosition);s=o<s?.5*(s+o):s;var r=Math.min(-this.getLastSlide().target,this.dragStartPosition);s=s<r?.5*(s+r):s}this.dragX=s,this.dragMoveTime=new Date,this.dispatchEvent("dragMove",t,[e,i])}},n.dragEnd=function(t,e){if(this.isDraggable){this.options.freeScroll&&(this.isFreeScrolling=!0);var i=this.dragEndRestingSelect();if(this.options.freeScroll&&!this.options.wrapAround){var n=this.getRestingPosition();this.isFreeScrolling=-n>this.slides[0].target&&-n<this.getLastSlide().target}else this.options.freeScroll||i!=this.selectedIndex||(i+=this.dragEndBoostSelect());delete this.previousDragX,this.isDragSelect=this.options.wrapAround,this.select(i),delete this.isDragSelect,this.dispatchEvent("dragEnd",t,[e])}},n.dragEndRestingSelect=function(){var t=this.getRestingPosition(),e=Math.abs(this.getSlideDistance(-t,this.selectedIndex)),i=this._getClosestResting(t,e,1),n=this._getClosestResting(t,e,-1);return i.distance<n.distance?i.index:n.index},n._getClosestResting=function(t,e,i){for(var n=this.selectedIndex,s=1/0,o=this.options.contain&&!this.options.wrapAround?function(t,e){return t<=e}:function(t,e){return t<e};o(e,s)&&(n+=i,s=e,null!==(e=this.getSlideDistance(-t,n)));)e=Math.abs(e);return{distance:s,index:n-i}},n.getSlideDistance=function(t,e){var i=this.slides.length,n=this.options.wrapAround&&1<i,s=n?a.modulo(e,i):e,o=this.slides[s];if(!o)return null;var r=n?this.slideableWidth*Math.floor(e/i):0;return t-(o.target+r)},n.dragEndBoostSelect=function(){if(void 0===this.previousDragX||!this.dragMoveTime||100<new Date-this.dragMoveTime)return 0;var t=this.getSlideDistance(-this.dragX,this.selectedIndex),e=this.previousDragX-this.dragX;return 0<t&&0<e?1:t<0&&e<0?-1:0},n.staticClick=function(t,e){var i=this.getParentCell(t.target),n=i&&i.element,s=i&&this.cells.indexOf(i);this.dispatchEvent("staticClick",t,[e,n,s])},n.onscroll=function(){var t=l(),e=this.pointerDownScroll.x-t.x,i=this.pointerDownScroll.y-t.y;(3<Math.abs(e)||3<Math.abs(i))&&this._pointerDone()},t}),function(n,s){"function"==typeof define&&define.amd?define("flickity/js/prev-next-button",["./flickity","unipointer/unipointer","fizzy-ui-utils/utils"],function(t,e,i){return s(n,t,e,i)}):"object"==typeof module&&module.exports?module.exports=s(n,require("./flickity"),require("unipointer"),require("fizzy-ui-utils")):s(n,n.Flickity,n.Unipointer,n.fizzyUIUtils)}(window,function(t,e,i,n){"use strict";var s="http://www.w3.org/2000/svg";function o(t,e){this.direction=t,this.parent=e,this._create()}(o.prototype=Object.create(i.prototype))._create=function(){this.isEnabled=!0,this.isPrevious=-1==this.direction;var t=this.parent.options.rightToLeft?1:-1;this.isLeft=this.direction==t;var e=this.element=document.createElement("button");e.className="flickity-button flickity-prev-next-button",e.className+=this.isPrevious?" previous":" next",e.setAttribute("type","button"),this.disable(),e.setAttribute("aria-label",this.isPrevious?"Previous":"Next");var i=this.createSVG();e.appendChild(i),this.parent.on("select",this.update.bind(this)),this.on("pointerDown",this.parent.childUIPointerDown.bind(this.parent))},o.prototype.activate=function(){this.bindStartEvent(this.element),this.element.addEventListener("click",this),this.parent.element.appendChild(this.element)},o.prototype.deactivate=function(){this.parent.element.removeChild(this.element),this.unbindStartEvent(this.element),this.element.removeEventListener("click",this)},o.prototype.createSVG=function(){var t=document.createElementNS(s,"svg");t.setAttribute("class","flickity-button-icon"),t.setAttribute("viewBox","0 0 100 100");var e=document.createElementNS(s,"path"),i=function(t){return"string"!=typeof t?"M "+t.x0+",50 L "+t.x1+","+(t.y1+50)+" L "+t.x2+","+(t.y2+50)+" L "+t.x3+",50  L "+t.x2+","+(50-t.y2)+" L "+t.x1+","+(50-t.y1)+" Z":t}(this.parent.options.arrowShape);return e.setAttribute("d",i),e.setAttribute("class","arrow"),this.isLeft||e.setAttribute("transform","translate(100, 100) rotate(180) "),t.appendChild(e),t},o.prototype.handleEvent=n.handleEvent,o.prototype.onclick=function(){if(this.isEnabled){this.parent.uiChange();var t=this.isPrevious?"previous":"next";this.parent[t]()}},o.prototype.enable=function(){this.isEnabled||(this.element.disabled=!1,this.isEnabled=!0)},o.prototype.disable=function(){this.isEnabled&&(this.element.disabled=!0,this.isEnabled=!1)},o.prototype.update=function(){var t=this.parent.slides;if(this.parent.options.wrapAround&&1<t.length)this.enable();else{var e=t.length?t.length-1:0,i=this.isPrevious?0:e;this[this.parent.selectedIndex==i?"disable":"enable"]()}},o.prototype.destroy=function(){this.deactivate(),this.allOff()},n.extend(e.defaults,{prevNextButtons:!0,arrowShape:{x0:10,x1:60,y1:50,x2:70,y2:40,x3:30}}),e.createMethods.push("_createPrevNextButtons");var r=e.prototype;return r._createPrevNextButtons=function(){this.options.prevNextButtons&&(this.prevButton=new o(-1,this),this.nextButton=new o(1,this),this.on("activate",this.activatePrevNextButtons))},r.activatePrevNextButtons=function(){this.prevButton.activate(),this.nextButton.activate(),this.on("deactivate",this.deactivatePrevNextButtons)},r.deactivatePrevNextButtons=function(){this.prevButton.deactivate(),this.nextButton.deactivate(),this.off("deactivate",this.deactivatePrevNextButtons)},e.PrevNextButton=o,e}),function(n,s){"function"==typeof define&&define.amd?define("flickity/js/page-dots",["./flickity","unipointer/unipointer","fizzy-ui-utils/utils"],function(t,e,i){return s(n,t,e,i)}):"object"==typeof module&&module.exports?module.exports=s(n,require("./flickity"),require("unipointer"),require("fizzy-ui-utils")):s(n,n.Flickity,n.Unipointer,n.fizzyUIUtils)}(window,function(t,e,i,n){function s(t){this.parent=t,this._create()}(s.prototype=Object.create(i.prototype))._create=function(){this.holder=document.createElement("ol"),this.holder.className="flickity-page-dots",this.dots=[],this.handleClick=this.onClick.bind(this),this.on("pointerDown",this.parent.childUIPointerDown.bind(this.parent))},s.prototype.activate=function(){this.setDots(),this.holder.addEventListener("click",this.handleClick),this.bindStartEvent(this.holder),this.parent.element.appendChild(this.holder)},s.prototype.deactivate=function(){this.holder.removeEventListener("click",this.handleClick),this.unbindStartEvent(this.holder),this.parent.element.removeChild(this.holder)},s.prototype.setDots=function(){var t=this.parent.slides.length-this.dots.length;0<t?this.addDots(t):t<0&&this.removeDots(-t)},s.prototype.addDots=function(t){for(var e=document.createDocumentFragment(),i=[],n=this.dots.length,s=n+t,o=n;o<s;o++){var r=document.createElement("li");r.className="dot",r.setAttribute("aria-label","Page dot "+(o+1)),e.appendChild(r),i.push(r)}this.holder.appendChild(e),this.dots=this.dots.concat(i)},s.prototype.removeDots=function(t){this.dots.splice(this.dots.length-t,t).forEach(function(t){this.holder.removeChild(t)},this)},s.prototype.updateSelected=function(){this.selectedDot&&(this.selectedDot.className="dot",this.selectedDot.removeAttribute("aria-current")),this.dots.length&&(this.selectedDot=this.dots[this.parent.selectedIndex],this.selectedDot.className="dot is-selected",this.selectedDot.setAttribute("aria-current","step"))},s.prototype.onTap=s.prototype.onClick=function(t){var e=t.target;if("LI"==e.nodeName){this.parent.uiChange();var i=this.dots.indexOf(e);this.parent.select(i)}},s.prototype.destroy=function(){this.deactivate(),this.allOff()},e.PageDots=s,n.extend(e.defaults,{pageDots:!0}),e.createMethods.push("_createPageDots");var o=e.prototype;return o._createPageDots=function(){this.options.pageDots&&(this.pageDots=new s(this),this.on("activate",this.activatePageDots),this.on("select",this.updateSelectedPageDots),this.on("cellChange",this.updatePageDots),this.on("resize",this.updatePageDots),this.on("deactivate",this.deactivatePageDots))},o.activatePageDots=function(){this.pageDots.activate()},o.updateSelectedPageDots=function(){this.pageDots.updateSelected()},o.updatePageDots=function(){this.pageDots.setDots()},o.deactivatePageDots=function(){this.pageDots.deactivate()},e.PageDots=s,e}),function(t,n){"function"==typeof define&&define.amd?define("flickity/js/player",["ev-emitter/ev-emitter","fizzy-ui-utils/utils","./flickity"],function(t,e,i){return n(t,e,i)}):"object"==typeof module&&module.exports?module.exports=n(require("ev-emitter"),require("fizzy-ui-utils"),require("./flickity")):n(t.EvEmitter,t.fizzyUIUtils,t.Flickity)}(window,function(t,e,i){function n(t){this.parent=t,this.state="stopped",this.onVisibilityChange=this.visibilityChange.bind(this),this.onVisibilityPlay=this.visibilityPlay.bind(this)}(n.prototype=Object.create(t.prototype)).play=function(){"playing"!=this.state&&(document.hidden?document.addEventListener("visibilitychange",this.onVisibilityPlay):(this.state="playing",document.addEventListener("visibilitychange",this.onVisibilityChange),this.tick()))},n.prototype.tick=function(){if("playing"==this.state){var t=this.parent.options.autoPlay;t="number"==typeof t?t:3e3;var e=this;this.clear(),this.timeout=setTimeout(function(){e.parent.next(!0),e.tick()},t)}},n.prototype.stop=function(){this.state="stopped",this.clear(),document.removeEventListener("visibilitychange",this.onVisibilityChange)},n.prototype.clear=function(){clearTimeout(this.timeout)},n.prototype.pause=function(){"playing"==this.state&&(this.state="paused",this.clear())},n.prototype.unpause=function(){"paused"==this.state&&this.play()},n.prototype.visibilityChange=function(){this[document.hidden?"pause":"unpause"]()},n.prototype.visibilityPlay=function(){this.play(),document.removeEventListener("visibilitychange",this.onVisibilityPlay)},e.extend(i.defaults,{pauseAutoPlayOnHover:!0}),i.createMethods.push("_createPlayer");var s=i.prototype;return s._createPlayer=function(){this.player=new n(this),this.on("activate",this.activatePlayer),this.on("uiChange",this.stopPlayer),this.on("pointerDown",this.stopPlayer),this.on("deactivate",this.deactivatePlayer)},s.activatePlayer=function(){this.options.autoPlay&&(this.player.play(),this.element.addEventListener("mouseenter",this))},s.playPlayer=function(){this.player.play()},s.stopPlayer=function(){this.player.stop()},s.pausePlayer=function(){this.player.pause()},s.unpausePlayer=function(){this.player.unpause()},s.deactivatePlayer=function(){this.player.stop(),this.element.removeEventListener("mouseenter",this)},s.onmouseenter=function(){this.options.pauseAutoPlayOnHover&&(this.player.pause(),this.element.addEventListener("mouseleave",this))},s.onmouseleave=function(){this.player.unpause(),this.element.removeEventListener("mouseleave",this)},i.Player=n,i}),function(i,n){"function"==typeof define&&define.amd?define("flickity/js/add-remove-cell",["./flickity","fizzy-ui-utils/utils"],function(t,e){return n(i,t,e)}):"object"==typeof module&&module.exports?module.exports=n(i,require("./flickity"),require("fizzy-ui-utils")):n(i,i.Flickity,i.fizzyUIUtils)}(window,function(t,e,n){var i=e.prototype;return i.insert=function(t,e){var i=this._makeCells(t);if(i&&i.length){var n=this.cells.length;e=void 0===e?n:e;var s=function(t){var e=document.createDocumentFragment();return t.forEach(function(t){e.appendChild(t.element)}),e}(i),o=e==n;if(o)this.slider.appendChild(s);else{var r=this.cells[e].element;this.slider.insertBefore(s,r)}if(0===e)this.cells=i.concat(this.cells);else if(o)this.cells=this.cells.concat(i);else{var a=this.cells.splice(e,n-e);this.cells=this.cells.concat(i).concat(a)}this._sizeCells(i),this.cellChange(e,!0)}},i.append=function(t){this.insert(t,this.cells.length)},i.prepend=function(t){this.insert(t,0)},i.remove=function(t){var e=this.getCells(t);if(e&&e.length){var i=this.cells.length-1;e.forEach(function(t){t.remove();var e=this.cells.indexOf(t);i=Math.min(e,i),n.removeFrom(this.cells,t)},this),this.cellChange(i,!0)}},i.cellSizeChange=function(t){var e=this.getCell(t);if(e){e.getSize();var i=this.cells.indexOf(e);this.cellChange(i)}},i.cellChange=function(t,e){var i=this.selectedElement;this._positionCells(t),this._getWrapShiftCells(),this.setGallerySize();var n=this.getCell(i);n&&(this.selectedIndex=this.getCellSlideIndex(n)),this.selectedIndex=Math.min(this.slides.length-1,this.selectedIndex),this.emitEvent("cellChange",[t]),this.select(this.selectedIndex),e&&this.positionSliderAtSelected()},e}),function(i,n){"function"==typeof define&&define.amd?define("flickity/js/lazyload",["./flickity","fizzy-ui-utils/utils"],function(t,e){return n(i,t,e)}):"object"==typeof module&&module.exports?module.exports=n(i,require("./flickity"),require("fizzy-ui-utils")):n(i,i.Flickity,i.fizzyUIUtils)}(window,function(t,e,o){"use strict";e.createMethods.push("_createLazyload");var i=e.prototype;function s(t,e){this.img=t,this.flickity=e,this.load()}return i._createLazyload=function(){this.on("select",this.lazyLoad)},i.lazyLoad=function(){var t=this.options.lazyLoad;if(t){var e="number"==typeof t?t:0,i=this.getAdjacentCellElements(e),n=[];i.forEach(function(t){var e=function(t){if("IMG"==t.nodeName){var e=t.getAttribute("data-flickity-lazyload"),i=t.getAttribute("data-flickity-lazyload-src"),n=t.getAttribute("data-flickity-lazyload-srcset");if(e||i||n)return[t]}var s=t.querySelectorAll("img[data-flickity-lazyload], img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]");return o.makeArray(s)}(t);n=n.concat(e)}),n.forEach(function(t){new s(t,this)},this)}},s.prototype.handleEvent=o.handleEvent,s.prototype.load=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this);var t=this.img.getAttribute("data-flickity-lazyload")||this.img.getAttribute("data-flickity-lazyload-src"),e=this.img.getAttribute("data-flickity-lazyload-srcset");this.img.src=t,e&&this.img.setAttribute("srcset",e),this.img.removeAttribute("data-flickity-lazyload"),this.img.removeAttribute("data-flickity-lazyload-src"),this.img.removeAttribute("data-flickity-lazyload-srcset")},s.prototype.onload=function(t){this.complete(t,"flickity-lazyloaded")},s.prototype.onerror=function(t){this.complete(t,"flickity-lazyerror")},s.prototype.complete=function(t,e){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this);var i=this.flickity.getParentCell(this.img),n=i&&i.element;this.flickity.cellSizeChange(n),this.img.classList.add(e),this.flickity.dispatchEvent("lazyLoad",t,n)},e.LazyLoader=s,e}),function(t,e){"function"==typeof define&&define.amd?define("flickity/js/index",["./flickity","./drag","./prev-next-button","./page-dots","./player","./add-remove-cell","./lazyload"],e):"object"==typeof module&&module.exports&&(module.exports=e(require("./flickity"),require("./drag"),require("./prev-next-button"),require("./page-dots"),require("./player"),require("./add-remove-cell"),require("./lazyload")))}(window,function(t){return t}),function(t,e){"function"==typeof define&&define.amd?define("flickity-as-nav-for/as-nav-for",["flickity/js/index","fizzy-ui-utils/utils"],e):"object"==typeof module&&module.exports?module.exports=e(require("flickity"),require("fizzy-ui-utils")):t.Flickity=e(t.Flickity,t.fizzyUIUtils)}(window,function(n,s){n.createMethods.push("_createAsNavFor");var t=n.prototype;return t._createAsNavFor=function(){this.on("activate",this.activateAsNavFor),this.on("deactivate",this.deactivateAsNavFor),this.on("destroy",this.destroyAsNavFor);var t=this.options.asNavFor;if(t){var e=this;setTimeout(function(){e.setNavCompanion(t)})}},t.setNavCompanion=function(t){t=s.getQueryElement(t);var e=n.data(t);if(e&&e!=this){this.navCompanion=e;var i=this;this.onNavCompanionSelect=function(){i.navCompanionSelect()},e.on("select",this.onNavCompanionSelect),this.on("staticClick",this.onNavStaticClick),this.navCompanionSelect(!0)}},t.navCompanionSelect=function(t){var e=this.navCompanion&&this.navCompanion.selectedCells;if(e){var i=e[0],n=this.navCompanion.cells.indexOf(i),s=n+e.length-1,o=Math.floor(function(t,e,i){return(e-t)*i+t}(n,s,this.navCompanion.cellAlign));if(this.selectCell(o,!1,t),this.removeNavSelectedElements(),!(o>=this.cells.length)){var r=this.cells.slice(n,1+s);this.navSelectedElements=r.map(function(t){return t.element}),this.changeNavSelectedClass("add")}}},t.changeNavSelectedClass=function(e){this.navSelectedElements.forEach(function(t){t.classList[e]("is-nav-selected")})},t.activateAsNavFor=function(){this.navCompanionSelect(!0)},t.removeNavSelectedElements=function(){this.navSelectedElements&&(this.changeNavSelectedClass("remove"),delete this.navSelectedElements)},t.onNavStaticClick=function(t,e,i,n){"number"==typeof n&&this.navCompanion.selectCell(n)},t.deactivateAsNavFor=function(){this.removeNavSelectedElements()},t.destroyAsNavFor=function(){this.navCompanion&&(this.navCompanion.off("select",this.onNavCompanionSelect),this.off("staticClick",this.onNavStaticClick),delete this.navCompanion)},n}),function(e,i){"use strict";"function"==typeof define&&define.amd?define("imagesloaded/imagesloaded",["ev-emitter/ev-emitter"],function(t){return i(e,t)}):"object"==typeof module&&module.exports?module.exports=i(e,require("ev-emitter")):e.imagesLoaded=i(e,e.EvEmitter)}("undefined"!=typeof window?window:this,function(e,t){var s=e.jQuery,o=e.console;function r(t,e){for(var i in e)t[i]=e[i];return t}var a=Array.prototype.slice;function l(t,e,i){if(!(this instanceof l))return new l(t,e,i);var n=t;"string"==typeof t&&(n=document.querySelectorAll(t)),n?(this.elements=function(t){return Array.isArray(t)?t:"object"==typeof t&&"number"==typeof t.length?a.call(t):[t]}(n),this.options=r({},this.options),"function"==typeof e?i=e:r(this.options,e),i&&this.on("always",i),this.getImages(),s&&(this.jqDeferred=new s.Deferred),setTimeout(this.check.bind(this))):o.error("Bad element for imagesLoaded "+(n||t))}(l.prototype=Object.create(t.prototype)).options={},l.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)},l.prototype.addElementImages=function(t){"IMG"==t.nodeName&&this.addImage(t),!0===this.options.background&&this.addElementBackgroundImages(t);var e=t.nodeType;if(e&&h[e]){for(var i=t.querySelectorAll("img"),n=0;n<i.length;n++){var s=i[n];this.addImage(s)}if("string"==typeof this.options.background){var o=t.querySelectorAll(this.options.background);for(n=0;n<o.length;n++){var r=o[n];this.addElementBackgroundImages(r)}}}};var h={1:!0,9:!0,11:!0};function i(t){this.img=t}function n(t,e){this.url=t,this.element=e,this.img=new Image}return l.prototype.addElementBackgroundImages=function(t){var e=getComputedStyle(t);if(e)for(var i=/url\((['"])?(.*?)\1\)/gi,n=i.exec(e.backgroundImage);null!==n;){var s=n&&n[2];s&&this.addBackground(s,t),n=i.exec(e.backgroundImage)}},l.prototype.addImage=function(t){var e=new i(t);this.images.push(e)},l.prototype.addBackground=function(t,e){var i=new n(t,e);this.images.push(i)},l.prototype.check=function(){var n=this;function e(t,e,i){setTimeout(function(){n.progress(t,e,i)})}this.progressedCount=0,this.hasAnyBroken=!1,this.images.length?this.images.forEach(function(t){t.once("progress",e),t.check()}):this.complete()},l.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent("progress",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount==this.images.length&&this.complete(),this.options.debug&&o&&o.log("progress: "+i,t,e)},l.prototype.complete=function(){var t=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent("always",[this]),this.jqDeferred){var e=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[e](this)}},(i.prototype=Object.create(t.prototype)).check=function(){this.getIsImageComplete()?this.confirm(0!==this.img.naturalWidth,"naturalWidth"):(this.proxyImage=new Image,this.proxyImage.addEventListener("load",this),this.proxyImage.addEventListener("error",this),this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.proxyImage.src=this.img.src)},i.prototype.getIsImageComplete=function(){return this.img.complete&&this.img.naturalWidth},i.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.img,e])},i.prototype.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindEvents()},i.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindEvents()},i.prototype.unbindEvents=function(){this.proxyImage.removeEventListener("load",this),this.proxyImage.removeEventListener("error",this),this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},(n.prototype=Object.create(i.prototype)).check=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.img.src=this.url,this.getIsImageComplete()&&(this.confirm(0!==this.img.naturalWidth,"naturalWidth"),this.unbindEvents())},n.prototype.unbindEvents=function(){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},n.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.element,e])},l.makeJQueryPlugin=function(t){(t=t||e.jQuery)&&((s=t).fn.imagesLoaded=function(t,e){return new l(this,t,e).jqDeferred.promise(s(this))})},l.makeJQueryPlugin(),l}),function(i,n){"function"==typeof define&&define.amd?define(["flickity/js/index","imagesloaded/imagesloaded"],function(t,e){return n(i,t,e)}):"object"==typeof module&&module.exports?module.exports=n(i,require("flickity"),require("imagesloaded")):i.Flickity=n(i,i.Flickity,i.imagesLoaded)}(window,function(t,e,i){"use strict";e.createMethods.push("_createImagesLoaded");var n=e.prototype;return n._createImagesLoaded=function(){this.on("activate",this.imagesLoaded)},n.imagesLoaded=function(){if(this.options.imagesLoaded){var n=this;i(this.slider).on("progress",function(t,e){var i=n.getParentCell(e.img);n.cellSizeChange(i&&i.element),n.options.freeScroll||n.positionSliderAtSelected()})}},e});;
/*
 RequireJS 2.1.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
 Available via the MIT or new BSD license.
 see: http://github.com/jrburke/requirejs for details
*/
var requirejs, require, define;
(function (Y) {
    function I(b) { return "[object Function]" === L.call(b) } function J(b) { return "[object Array]" === L.call(b) } function x(b, c) { if (b) { var d; for (d = 0; d < b.length && (!b[d] || !c(b[d], d, b)) ; d += 1); } } function M(b, c) { if (b) { var d; for (d = b.length - 1; -1 < d && (!b[d] || !c(b[d], d, b)) ; d -= 1); } } function r(b, c) { return da.call(b, c) } function i(b, c) { return r(b, c) && b[c] } function E(b, c) { for (var d in b) if (r(b, d) && c(b[d], d)) break } function Q(b, c, d, i) {
        c && E(c, function (c, h) {
            if (d || !r(b, h)) i && "string" !== typeof c ? (b[h] || (b[h] = {}), Q(b[h],
            c, d, i)) : b[h] = c
        }); return b
    } function t(b, c) { return function () { return c.apply(b, arguments) } } function Z(b) { if (!b) return b; var c = Y; x(b.split("."), function (b) { c = c[b] }); return c } function F(b, c, d, i) { c = Error(c + "\nhttp://requirejs.org/docs/errors.html#" + b); c.requireType = b; c.requireModules = i; d && (c.originalError = d); return c } function ea(b) {
        function c(a, f, v) {
            var e, n, b, c, d, k, g, h = f && f.split("/"); e = h; var l = m.map, j = l && l["*"]; if (a && "." === a.charAt(0)) if (f) {
                e = i(m.pkgs, f) ? h = [f] : h.slice(0, h.length - 1); f = a = e.concat(a.split("/"));
                for (e = 0; f[e]; e += 1) if (n = f[e], "." === n) f.splice(e, 1), e -= 1; else if (".." === n) if (1 === e && (".." === f[2] || ".." === f[0])) break; else 0 < e && (f.splice(e - 1, 2), e -= 2); e = i(m.pkgs, f = a[0]); a = a.join("/"); e && a === f + "/" + e.main && (a = f)
            } else 0 === a.indexOf("./") && (a = a.substring(2)); if (v && (h || j) && l) {
                f = a.split("/"); for (e = f.length; 0 < e; e -= 1) { b = f.slice(0, e).join("/"); if (h) for (n = h.length; 0 < n; n -= 1) if (v = i(l, h.slice(0, n).join("/"))) if (v = i(v, b)) { c = v; d = e; break } if (c) break; !k && (j && i(j, b)) && (k = i(j, b), g = e) } !c && k && (c = k, d = g); c && (f.splice(0, d,
                c), a = f.join("/"))
            } return a
        } function d(a) { z && x(document.getElementsByTagName("script"), function (f) { if (f.getAttribute("data-requiremodule") === a && f.getAttribute("data-requirecontext") === k.contextName) return f.parentNode.removeChild(f), !0 }) } function y(a) { var f = i(m.paths, a); if (f && J(f) && 1 < f.length) return d(a), f.shift(), k.require.undef(a), k.require([a]), !0 } function g(a) { var f, b = a ? a.indexOf("!") : -1; -1 < b && (f = a.substring(0, b), a = a.substring(b + 1, a.length)); return [f, a] } function h(a, f, b, e) {
            var n, u, d = null, h = f ? f.name :
            null, l = a, m = !0, j = ""; a || (m = !1, a = "_@r" + (L += 1)); a = g(a); d = a[0]; a = a[1]; d && (d = c(d, h, e), u = i(p, d)); a && (d ? j = u && u.normalize ? u.normalize(a, function (a) { return c(a, h, e) }) : c(a, h, e) : (j = c(a, h, e), a = g(j), d = a[0], j = a[1], b = !0, n = k.nameToUrl(j))); b = d && !u && !b ? "_unnormalized" + (M += 1) : ""; return { prefix: d, name: j, parentMap: f, unnormalized: !!b, url: n, originalName: l, isDefine: m, id: (d ? d + "!" + j : j) + b }
        } function q(a) { var f = a.id, b = i(j, f); b || (b = j[f] = new k.Module(a)); return b } function s(a, f, b) {
            var e = a.id, n = i(j, e); if (r(p, e) && (!n || n.defineEmitComplete)) "defined" ===
            f && b(p[e]); else q(a).on(f, b)
        } function A(a, f) { var b = a.requireModules, e = !1; if (f) f(a); else if (x(b, function (f) { if (f = i(j, f)) f.error = a, f.events.error && (e = !0, f.emit("error", a)) }), !e) l.onError(a) } function w() { R.length && (fa.apply(G, [G.length - 1, 0].concat(R)), R = []) } function B(a, f, b) { var e = a.map.id; a.error ? a.emit("error", a.error) : (f[e] = !0, x(a.depMaps, function (e, c) { var d = e.id, h = i(j, d); h && (!a.depMatched[c] && !b[d]) && (i(f, d) ? (a.defineDep(c, p[d]), a.check()) : B(h, f, b)) }), b[e] = !0) } function C() {
            var a, f, b, e, n = (b = 1E3 * m.waitSeconds) &&
            k.startTime + b < (new Date).getTime(), c = [], h = [], g = !1, l = !0; if (!T) { T = !0; E(j, function (b) { a = b.map; f = a.id; if (b.enabled && (a.isDefine || h.push(b), !b.error)) if (!b.inited && n) y(f) ? g = e = !0 : (c.push(f), d(f)); else if (!b.inited && (b.fetched && a.isDefine) && (g = !0, !a.prefix)) return l = !1 }); if (n && c.length) return b = F("timeout", "Load timeout for modules: " + c, null, c), b.contextName = k.contextName, A(b); l && x(h, function (a) { B(a, {}, {}) }); if ((!n || e) && g) if ((z || $) && !U) U = setTimeout(function () { U = 0; C() }, 50); T = !1 }
        } function D(a) {
            r(p, a[0]) ||
            q(h(a[0], null, !0)).init(a[1], a[2])
        } function H(a) { var a = a.currentTarget || a.srcElement, b = k.onScriptLoad; a.detachEvent && !V ? a.detachEvent("onreadystatechange", b) : a.removeEventListener("load", b, !1); b = k.onScriptError; (!a.detachEvent || V) && a.removeEventListener("error", b, !1); return { node: a, id: a && a.getAttribute("data-requiremodule") } } function K() { var a; for (w() ; G.length;) { a = G.shift(); if (null === a[0]) return A(F("mismatch", "Mismatched anonymous define() module: " + a[a.length - 1])); D(a) } } var T, W, k, N, U, m = {
            waitSeconds: 7,
            baseUrl: "./", paths: {}, pkgs: {}, shim: {}, map: {}, config: {}
        }, j = {}, X = {}, G = [], p = {}, S = {}, L = 1, M = 1; N = { require: function (a) { return a.require ? a.require : a.require = k.makeRequire(a.map) }, exports: function (a) { a.usingExports = !0; if (a.map.isDefine) return a.exports ? a.exports : a.exports = p[a.map.id] = {} }, module: function (a) { return a.module ? a.module : a.module = { id: a.map.id, uri: a.map.url, config: function () { return m.config && i(m.config, a.map.id) || {} }, exports: p[a.map.id] } } }; W = function (a) {
            this.events = i(X, a.id) || {}; this.map = a; this.shim =
            i(m.shim, a.id); this.depExports = []; this.depMaps = []; this.depMatched = []; this.pluginMaps = {}; this.depCount = 0
        }; W.prototype = {
            init: function (a, b, c, e) { e = e || {}; if (!this.inited) { this.factory = b; if (c) this.on("error", c); else this.events.error && (c = t(this, function (a) { this.emit("error", a) })); this.depMaps = a && a.slice(0); this.errback = c; this.inited = !0; this.ignore = e.ignore; e.enabled || this.enabled ? this.enable() : this.check() } }, defineDep: function (a, b) {
                this.depMatched[a] || (this.depMatched[a] = !0, this.depCount -= 1, this.depExports[a] =
                b)
            }, fetch: function () { if (!this.fetched) { this.fetched = !0; k.startTime = (new Date).getTime(); var a = this.map; if (this.shim) k.makeRequire(this.map, { enableBuildCallback: !0 })(this.shim.deps || [], t(this, function () { return a.prefix ? this.callPlugin() : this.load() })); else return a.prefix ? this.callPlugin() : this.load() } }, load: function () { var a = this.map.url; S[a] || (S[a] = !0, k.load(this.map.id, a)) }, check: function () {
                if (this.enabled && !this.enabling) {
                    var a, b, c = this.map.id; b = this.depExports; var e = this.exports, n = this.factory;
                    if (this.inited) if (this.error) this.emit("error", this.error); else {
                        if (!this.defining) {
                            this.defining = !0; if (1 > this.depCount && !this.defined) {
                                if (I(n)) { if (this.events.error) try { e = k.execCb(c, n, b, e) } catch (d) { a = d } else e = k.execCb(c, n, b, e); this.map.isDefine && ((b = this.module) && void 0 !== b.exports && b.exports !== this.exports ? e = b.exports : void 0 === e && this.usingExports && (e = this.exports)); if (a) return a.requireMap = this.map, a.requireModules = [this.map.id], a.requireType = "define", A(this.error = a) } else e = n; this.exports = e; if (this.map.isDefine &&
                                !this.ignore && (p[c] = e, l.onResourceLoad)) l.onResourceLoad(k, this.map, this.depMaps); delete j[c]; this.defined = !0
                            } this.defining = !1; this.defined && !this.defineEmitted && (this.defineEmitted = !0, this.emit("defined", this.exports), this.defineEmitComplete = !0)
                        }
                    } else this.fetch()
                }
            }, callPlugin: function () {
                var a = this.map, b = a.id, d = h(a.prefix); this.depMaps.push(d); s(d, "defined", t(this, function (e) {
                    var n, d; d = this.map.name; var v = this.map.parentMap ? this.map.parentMap.name : null, g = k.makeRequire(a.parentMap, { enableBuildCallback: !0 });
                    if (this.map.unnormalized) { if (e.normalize && (d = e.normalize(d, function (a) { return c(a, v, !0) }) || ""), e = h(a.prefix + "!" + d, this.map.parentMap), s(e, "defined", t(this, function (a) { this.init([], function () { return a }, null, { enabled: !0, ignore: !0 }) })), d = i(j, e.id)) { this.depMaps.push(e); if (this.events.error) d.on("error", t(this, function (a) { this.emit("error", a) })); d.enable() } } else n = t(this, function (a) { this.init([], function () { return a }, null, { enabled: !0 }) }), n.error = t(this, function (a) {
                        this.inited = !0; this.error = a; a.requireModules =
                        [b]; E(j, function (a) { 0 === a.map.id.indexOf(b + "_unnormalized") && delete j[a.map.id] }); A(a)
                    }), n.fromText = t(this, function (e, c) { var d = a.name, u = h(d), v = O; c && (e = c); v && (O = !1); q(u); r(m.config, b) && (m.config[d] = m.config[b]); try { l.exec(e) } catch (j) { return A(F("fromtexteval", "fromText eval for " + b + " failed: " + j, j, [b])) } v && (O = !0); this.depMaps.push(u); k.completeLoad(d); g([d], n) }), e.load(a.name, g, n, m)
                })); k.enable(d, this); this.pluginMaps[d.id] = d
            }, enable: function () {
                this.enabling = this.enabled = !0; x(this.depMaps, t(this, function (a,
                b) { var c, e; if ("string" === typeof a) { a = h(a, this.map.isDefine ? this.map : this.map.parentMap, !1, !this.skipMap); this.depMaps[b] = a; if (c = i(N, a.id)) { this.depExports[b] = c(this); return } this.depCount += 1; s(a, "defined", t(this, function (a) { this.defineDep(b, a); this.check() })); this.errback && s(a, "error", this.errback) } c = a.id; e = j[c]; !r(N, c) && (e && !e.enabled) && k.enable(a, this) })); E(this.pluginMaps, t(this, function (a) { var b = i(j, a.id); b && !b.enabled && k.enable(a, this) })); this.enabling = !1; this.check()
            }, on: function (a, b) {
                var c =
                this.events[a]; c || (c = this.events[a] = []); c.push(b)
            }, emit: function (a, b) { x(this.events[a], function (a) { a(b) }); "error" === a && delete this.events[a] }
        }; k = {
            config: m, contextName: b, registry: j, defined: p, urlFetched: S, defQueue: G, Module: W, makeModuleMap: h, nextTick: l.nextTick, configure: function (a) {
                a.baseUrl && "/" !== a.baseUrl.charAt(a.baseUrl.length - 1) && (a.baseUrl += "/"); var b = m.pkgs, c = m.shim, e = { paths: !0, config: !0, map: !0 }; E(a, function (a, b) { e[b] ? "map" === b ? Q(m[b], a, !0, !0) : Q(m[b], a, !0) : m[b] = a }); a.shim && (E(a.shim, function (a,
                b) { J(a) && (a = { deps: a }); if ((a.exports || a.init) && !a.exportsFn) a.exportsFn = k.makeShimExports(a); c[b] = a }), m.shim = c); a.packages && (x(a.packages, function (a) { a = "string" === typeof a ? { name: a } : a; b[a.name] = { name: a.name, location: a.location || a.name, main: (a.main || "main").replace(ga, "").replace(aa, "") } }), m.pkgs = b); E(j, function (a, b) { !a.inited && !a.map.unnormalized && (a.map = h(b)) }); if (a.deps || a.callback) k.require(a.deps || [], a.callback)
            }, makeShimExports: function (a) {
                return function () {
                    var b; a.init && (b = a.init.apply(Y, arguments));
                    return b || a.exports && Z(a.exports)
                }
            }, makeRequire: function (a, d) {
                function g(e, c, u) {
                    var i, m; d.enableBuildCallback && (c && I(c)) && (c.__requireJsBuild = !0); if ("string" === typeof e) { if (I(c)) return A(F("requireargs", "Invalid require call"), u); if (a && r(N, e)) return N[e](j[a.id]); if (l.get) return l.get(k, e, a); i = h(e, a, !1, !0); i = i.id; return !r(p, i) ? A(F("notloaded", 'Module name "' + i + '" has not been loaded yet for context: ' + b + (a ? "" : ". Use require([])"))) : p[i] } K(); k.nextTick(function () {
                        K(); m = q(h(null, a)); m.skipMap = d.skipMap;
                        m.init(e, c, u, { enabled: !0 }); C()
                    }); return g
                } d = d || {}; Q(g, { isBrowser: z, toUrl: function (b) { var d, f = b.lastIndexOf("."), h = b.split("/")[0]; if (-1 !== f && (!("." === h || ".." === h) || 1 < f)) d = b.substring(f, b.length), b = b.substring(0, f); b = k.nameToUrl(c(b, a && a.id, !0), d || ".fake"); return d ? b : b.substring(0, b.length - 5) }, defined: function (b) { return r(p, h(b, a, !1, !0).id) }, specified: function (b) { b = h(b, a, !1, !0).id; return r(p, b) || r(j, b) } }); a || (g.undef = function (b) {
                    w(); var c = h(b, a, !0), d = i(j, b); delete p[b]; delete S[c.url]; delete X[b];
                    d && (d.events.defined && (X[b] = d.events), delete j[b])
                }); return g
            }, enable: function (a) { i(j, a.id) && q(a).enable() }, completeLoad: function (a) { var b, c, d = i(m.shim, a) || {}, h = d.exports; for (w() ; G.length;) { c = G.shift(); if (null === c[0]) { c[0] = a; if (b) break; b = !0 } else c[0] === a && (b = !0); D(c) } c = i(j, a); if (!b && !r(p, a) && c && !c.inited) { if (m.enforceDefine && (!h || !Z(h))) return y(a) ? void 0 : A(F("nodefine", "No define call for " + a, null, [a])); D([a, d.deps || [], d.exportsFn]) } C() }, nameToUrl: function (a, b) {
                var c, d, h, g, k, j; if (l.jsExtRegExp.test(a)) g =
                a + (b || ""); else { c = m.paths; d = m.pkgs; g = a.split("/"); for (k = g.length; 0 < k; k -= 1) if (j = g.slice(0, k).join("/"), h = i(d, j), j = i(c, j)) { J(j) && (j = j[0]); g.splice(0, k, j); break } else if (h) { c = a === h.name ? h.location + "/" + h.main : h.location; g.splice(0, k, c); break } g = g.join("/"); g += b || (/\?/.test(g) ? "" : ".js"); g = ("/" === g.charAt(0) || g.match(/^[\w\+\.\-]+:/) ? "" : m.baseUrl) + g } return m.urlArgs ? g + ((-1 === g.indexOf("?") ? "?" : "&") + m.urlArgs) : g
            }, load: function (a, b) { l.load(k, a, b) }, execCb: function (a, b, c, d) { return b.apply(d, c) }, onScriptLoad: function (a) {
                if ("load" ===
                a.type || ha.test((a.currentTarget || a.srcElement).readyState)) P = null, a = H(a), k.completeLoad(a.id)
            }, onScriptError: function (a) { var b = H(a); if (!y(b.id)) return A(F("scripterror", "Script error", a, [b.id])) }
        }; k.require = k.makeRequire(); return k
    } var l, w, B, D, s, H, P, K, ba, ca, ia = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, ja = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, aa = /\.js$/, ga = /^\.\//; w = Object.prototype; var L = w.toString, da = w.hasOwnProperty, fa = Array.prototype.splice, z = !!("undefined" !== typeof window && navigator &&
    document), $ = !z && "undefined" !== typeof importScripts, ha = z && "PLAYSTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/, V = "undefined" !== typeof opera && "[object Opera]" === opera.toString(), C = {}, q = {}, R = [], O = !1; if ("undefined" === typeof define) {
        if ("undefined" !== typeof requirejs) { if (I(requirejs)) return; q = requirejs; requirejs = void 0 } "undefined" !== typeof require && !I(require) && (q = require, require = void 0); l = requirejs = function (b, c, d, y) {
            var g, h = "_"; !J(b) && "string" !== typeof b && (g = b, J(c) ? (b = c, c = d, d = y) : b = []);
            g && g.context && (h = g.context); (y = i(C, h)) || (y = C[h] = l.s.newContext(h)); g && y.configure(g); return y.require(b, c, d)
        }; l.config = function (b) { return l(b) }; l.nextTick = "undefined" !== typeof setTimeout ? function (b) { setTimeout(b, 4) } : function (b) { b() }; require || (require = l); l.version = "2.1.4"; l.jsExtRegExp = /^\/|:|\?|\.js$/; l.isBrowser = z; w = l.s = { contexts: C, newContext: ea }; l({}); x(["toUrl", "undef", "defined", "specified"], function (b) { l[b] = function () { var c = C._; return c.require[b].apply(c, arguments) } }); if (z && (B = w.head = document.getElementsByTagName("head")[0],
        D = document.getElementsByTagName("base")[0])) B = w.head = D.parentNode; l.onError = function (b) { throw b; }; l.load = function (b, c, d) {
            var i = b && b.config || {}, g; if (z) return g = i.xhtml ? document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") : document.createElement("script"), g.type = i.scriptType || "text/javascript", g.charset = "utf-8", g.async = !0, g.setAttribute("data-requirecontext", b.contextName), g.setAttribute("data-requiremodule", c), g.attachEvent && !(g.attachEvent.toString && 0 > g.attachEvent.toString().indexOf("[native code")) &&
            !V ? (O = !0, g.attachEvent("onreadystatechange", b.onScriptLoad)) : (g.addEventListener("load", b.onScriptLoad, !1), g.addEventListener("error", b.onScriptError, !1)), g.src = d, K = g, D ? B.insertBefore(g, D) : B.appendChild(g), K = null, g; $ && (importScripts(d), b.completeLoad(c))
        }; z && M(document.getElementsByTagName("script"), function (b) {
            B || (B = b.parentNode); if (s = b.getAttribute("data-main")) return q.baseUrl || (H = s.split("/"), ba = H.pop(), ca = H.length ? H.join("/") + "/" : "./", q.baseUrl = ca, s = ba), s = s.replace(aa, ""), q.deps = q.deps ? q.deps.concat(s) :
            [s], !0
        }); define = function (b, c, d) {
            var i, g; "string" !== typeof b && (d = c, c = b, b = null); J(c) || (d = c, c = []); !c.length && I(d) && d.length && (d.toString().replace(ia, "").replace(ja, function (b, d) { c.push(d) }), c = (1 === d.length ? ["require"] : ["require", "exports", "module"]).concat(c)); if (O) { if (!(i = K)) P && "interactive" === P.readyState || M(document.getElementsByTagName("script"), function (b) { if ("interactive" === b.readyState) return P = b }), i = P; i && (b || (b = i.getAttribute("data-requiremodule")), g = C[i.getAttribute("data-requirecontext")]) } (g ?
            g.defQueue : R).push([b, c, d])
        }; define.amd = { jQuery: !0 }; l.exec = function (b) { return eval(b) }; l(q)
    }
})(this);;
/*\
|*|
|*|  :: cookies.js ::
|*|
|*|  A complete cookies reader/writer framework with full unicode support.
|*|
|*|  Revision #1 - September 4, 2014
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|  https://developer.mozilla.org/User:fusionchess
|*|
|*|  This framework is released under the GNU Public License, version 3 or later.
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*|  Syntaxes:
|*|
|*|  * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*|  * docCookies.getItem(name)
|*|  * docCookies.removeItem(name[, path[, domain]])
|*|  * docCookies.hasItem(name)
|*|  * docCookies.keys()
|*|
\*/

var docCookies = {
    getItem: function (sKey) {
        if (!sKey) { return null; }
        return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
    },
    setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
        if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
        var sExpires = "";
        if (vEnd) {
            switch (vEnd.constructor) {
                case Number:
                    sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
                    break;
                case String:
                    sExpires = "; expires=" + vEnd;
                    break;
                case Date:
                    sExpires = "; expires=" + vEnd.toUTCString();
                    break;
            }
        }
        document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "") + "; SameSite=Lax";
        return true;
    },
    removeItem: function (sKey, sPath, sDomain) {
        if (!this.hasItem(sKey)) { return false; }
        document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
        return true;
    },
    hasItem: function (sKey) {
        if (!sKey) { return false; }
        return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
    },
    keys: function () {
        var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
        for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
        return aKeys;
    }
};;
/*!
 * jScrollPane - v2.0.23 - 2016-01-28
 * http://jscrollpane.kelvinluck.com/
 *
 * Copyright (c) 2014 Kelvin Luck
 * Dual licensed under the MIT or GPL licenses.
 */

// Script: jScrollPane - cross browser customisable scrollbars
//
// *Version: 2.0.23, Last updated: 2016-01-28*
//
// Project Home - http://jscrollpane.kelvinluck.com/
// GitHub       - http://github.com/vitch/jScrollPane
// Source       - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.js
// (Minified)   - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.min.js
//
// About: License
//
// Copyright (c) 2014 Kelvin Luck
// Dual licensed under the MIT or GPL Version 2 licenses.
// http://jscrollpane.kelvinluck.com/MIT-LICENSE.txt
// http://jscrollpane.kelvinluck.com/GPL-LICENSE.txt
//
// About: Examples
//
// All examples and demos are available through the jScrollPane example site at:
// http://jscrollpane.kelvinluck.com/
//
// About: Support and Testing
//
// This plugin is tested on the browsers below and has been found to work reliably on them. If you run
// into a problem on one of the supported browsers then please visit the support section on the jScrollPane
// website (http://jscrollpane.kelvinluck.com/) for more information on getting support. You are also
// welcome to fork the project on GitHub if you can contribute a fix for a given issue.
//
// jQuery Versions - tested in 1.4.2+ - reported to work in 1.3.x
// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8
//
// About: Release History
//
// 2.0.23 - (2016-01-28) Various 
// 2.0.22 - (2015-04-25) Resolve a memory leak due to an event handler that isn't cleaned up in destroy (thanks @timjnh)
// 2.0.21 - (2015-02-24) Simplify UMD pattern: fixes browserify when loading jQuery outside of bundle
// 2.0.20 - (2014-10-23) Adds AMD support (thanks @carlosrberto) and support for overflow-x/overflow-y (thanks @darimpulso)
// 2.0.19 - (2013-11-16) Changes for more reliable scroll amount with latest mousewheel plugin (thanks @brandonaaron)
// 2.0.18 - (2013-10-23) Fix for issue with gutters and scrollToElement (thanks @Dubiy)
// 2.0.17 - (2013-08-17) Working correctly when box-sizing is set to border-box (thanks @pieht)
// 2.0.16 - (2013-07-30) Resetting left position when scroll is removed. Fixes #189
// 2.0.15 - (2013-07-29) Fixed issue with scrollToElement where the destX and destY are undefined.
// 2.0.14 - (2013-05-01) Updated to most recent mouse wheel plugin (see #106) and related changes for sensible scroll speed
// 2.0.13 - (2013-05-01) Switched to semver compatible version name
// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+
// 2.0.0beta11 - (2012-05-14)
// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes
// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX
// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support
// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas)
// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support
// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes
// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes
// 2.0.0beta3 - (2010-08-27) Horizontal mousewheel, mwheelIntent, keyboard support, bug fixes
// 2.0.0beta2 - (2010-08-21) Bug fixes
// 2.0.0beta1 - (2010-08-17) Rewrite to follow modern best practices and enable horizontal scrolling, initially hidden
//							 elements and dynamically sized elements.
// 1.x - (2006-12-31 - 2010-07-31) Initial version, hosted at googlecode, deprecated

(function (factory) {    
    // Browser globals
    factory(jQuery);
}(function ($) {

    $.fn.jScrollPane = function (settings) {
        // JScrollPane "class" - public methods are available through $('selector').data('jsp')
        function JScrollPane(elem, s) {
            var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
				percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
				verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
				verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
				horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
				reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
				wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
				originalElement = elem.clone(false, false).empty(),
				mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';

            if (elem.css('box-sizing') === 'border-box') {
                originalPadding = 0;
                originalPaddingTotalWidth = 0;
            } else {
                originalPadding = elem.css('paddingTop') + ' ' +
									elem.css('paddingRight') + ' ' +
									elem.css('paddingBottom') + ' ' +
									elem.css('paddingLeft');
                originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
											(parseInt(elem.css('paddingRight'), 10) || 0);
            }

            function initialise(s) {

                var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
						hasContainingSpaceChanged, originalScrollTop, originalScrollLeft,
						maintainAtBottom = false, maintainAtRight = false;

                settings = s;

                if (pane === undefined) {
                    originalScrollTop = elem.scrollTop();
                    originalScrollLeft = elem.scrollLeft();

                    elem.css(
						{
						    overflow: 'hidden',
						    padding: 0
						}
					);
                    // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
                    // come back to it later and check once it is unhidden...
                    paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
                    paneHeight = elem.innerHeight();

                    elem.width(paneWidth);

                    pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
                    container = $('<div class="jspContainer" />')
						.css({
						    'width': paneWidth + 'px',
						    'height': paneHeight + 'px'
						}
					).append(pane).appendTo(elem);

                    /*
					// Move any margins from the first and last children up to the container so they can still
					// collapse with neighbouring elements as they would before jScrollPane
					firstChild = pane.find(':first-child');
					lastChild = pane.find(':last-child');
					elem.css(
						{
							'margin-top': firstChild.css('margin-top'),
							'margin-bottom': lastChild.css('margin-bottom')
						}
					);
					firstChild.css('margin-top', 0);
					lastChild.css('margin-bottom', 0);
					*/
                } else {
                    paneHeight = pane.outerHeight() - 1; // hack
                    container.css('height', paneHeight + 'px'); // hack

                    elem.css('width', '');

                    maintainAtBottom = settings.stickToBottom && isCloseToBottom();
                    maintainAtRight = settings.stickToRight && isCloseToRight();

                    hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;

                    if (hasContainingSpaceChanged) {
                        paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
                        paneHeight = elem.innerHeight();
                        container.css({
                            width: paneWidth + 'px',
                            height: paneHeight + 'px'
                        });
                    }

                    // If nothing changed since last check...
                    if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
                        elem.width(paneWidth);
                        return;
                    }
                    previousContentWidth = contentWidth;

                    pane.css('width', '');
                    elem.width(paneWidth);

                    container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
                }

                pane.css('overflow', 'auto');
                if (s.contentWidth) {
                    contentWidth = s.contentWidth;
                } else {
                    contentWidth = pane[0].scrollWidth;
                }
                contentHeight = pane[0].scrollHeight;
                pane.css('overflow', '');

                percentInViewH = contentWidth / paneWidth;
                percentInViewV = contentHeight / paneHeight;
                isScrollableV = percentInViewV > 1;

                isScrollableH = percentInViewH > 1;

                //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);

                if (!(isScrollableH || isScrollableV)) {
                    elem.removeClass('jspScrollable');
                    pane.css({
                        top: 0,
                        left: 0,
                        width: container.width() - originalPaddingTotalWidth
                    });
                    removeMousewheel();
                    removeFocusHandler();
                    removeKeyboardNav();
                    removeClickOnTrack();
                } else {
                    elem.addClass('jspScrollable');

                    isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
                    if (isMaintainingPositon) {
                        lastContentX = contentPositionX();
                        lastContentY = contentPositionY();
                    }

                    initialiseVerticalScroll();
                    initialiseHorizontalScroll();
                    resizeScrollbars();

                    if (isMaintainingPositon) {
                        scrollToX(maintainAtRight ? (contentWidth - paneWidth) : lastContentX, false);
                        scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false);
                    }

                    initFocusHandler();
                    initMousewheel();
                    initTouch();

                    if (settings.enableKeyboardNavigation) {
                        initKeyboardNav();
                    }
                    if (settings.clickOnTrack) {
                        initClickOnTrack();
                    }

                    observeHash();
                    if (settings.hijackInternalLinks) {
                        hijackInternalLinks();
                    }
                }

                if (settings.autoReinitialise && !reinitialiseInterval) {
                    reinitialiseInterval = setInterval(
						function () {
						    initialise(settings);
						},
						settings.autoReinitialiseDelay
					);
                } else if (!settings.autoReinitialise && reinitialiseInterval) {
                    clearInterval(reinitialiseInterval);
                }

                originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
                originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);

                elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
            }

            function initialiseVerticalScroll() {
                if (isScrollableV) {

                    container.append(
						$('<div class="jspVerticalBar" />').append(
							$('<div class="jspCap jspCapTop" />'),
							$('<div class="jspTrack" />').append(
								$('<div class="jspDrag" />').append(
									$('<div class="jspDragTop" />'),
									$('<div class="jspDragBottom" />')
								)
							),
							$('<div class="jspCap jspCapBottom" />')
						)
					);

                    verticalBar = container.find('>.jspVerticalBar');
                    verticalTrack = verticalBar.find('>.jspTrack');
                    verticalDrag = verticalTrack.find('>.jspDrag');

                    if (settings.showArrows) {
                        arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
							'mousedown.jsp', getArrowScroll(0, -1)
						).bind('click.jsp', nil);
                        arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
							'mousedown.jsp', getArrowScroll(0, 1)
						).bind('click.jsp', nil);
                        if (settings.arrowScrollOnHover) {
                            arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
                            arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
                        }

                        appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
                    }

                    verticalTrackHeight = paneHeight;
                    container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
						function () {
						    verticalTrackHeight -= $(this).outerHeight();
						}
					);


                    verticalDrag.hover(
						function () {
						    verticalDrag.addClass('jspHover');
						},
						function () {
						    verticalDrag.removeClass('jspHover');
						}
					).bind(
						'mousedown.jsp',
						function (e) {
						    // Stop IE from allowing text selection
						    $('html').bind('dragstart.jsp selectstart.jsp', nil);

						    verticalDrag.addClass('jspActive');

						    var startY = e.pageY - verticalDrag.position().top;

						    $('html').bind(
								'mousemove.jsp',
								function (e) {
								    positionDragY(e.pageY - startY, false);
								}
							).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
						    return false;
						}
					);
                    sizeVerticalScrollbar();
                }
            }

            function sizeVerticalScrollbar() {
                verticalTrack.height(verticalTrackHeight + 'px');
                verticalDragPosition = 0;
                scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();

                // Make the pane thinner to allow for the vertical scrollbar
                pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);

                // Add margin to the left of the pane if scrollbars are on that side (to position
                // the scrollbar on the left or right set it's left or right property in CSS)
                try {
                    if (verticalBar.position().left === 0) {
                        pane.css('margin-left', scrollbarWidth + 'px');
                    }
                } catch (err) {
                }
            }

            function initialiseHorizontalScroll() {
                if (isScrollableH) {

                    container.append(
						$('<div class="jspHorizontalBar" />').append(
							$('<div class="jspCap jspCapLeft" />'),
							$('<div class="jspTrack" />').append(
								$('<div class="jspDrag" />').append(
									$('<div class="jspDragLeft" />'),
									$('<div class="jspDragRight" />')
								)
							),
							$('<div class="jspCap jspCapRight" />')
						)
					);

                    horizontalBar = container.find('>.jspHorizontalBar');
                    horizontalTrack = horizontalBar.find('>.jspTrack');
                    horizontalDrag = horizontalTrack.find('>.jspDrag');

                    if (settings.showArrows) {
                        arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
							'mousedown.jsp', getArrowScroll(-1, 0)
						).bind('click.jsp', nil);
                        arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
							'mousedown.jsp', getArrowScroll(1, 0)
						).bind('click.jsp', nil);
                        if (settings.arrowScrollOnHover) {
                            arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
                            arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
                        }
                        appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
                    }

                    horizontalDrag.hover(
						function () {
						    horizontalDrag.addClass('jspHover');
						},
						function () {
						    horizontalDrag.removeClass('jspHover');
						}
					).bind(
						'mousedown.jsp',
						function (e) {
						    // Stop IE from allowing text selection
						    $('html').bind('dragstart.jsp selectstart.jsp', nil);

						    horizontalDrag.addClass('jspActive');

						    var startX = e.pageX - horizontalDrag.position().left;

						    $('html').bind(
								'mousemove.jsp',
								function (e) {
								    positionDragX(e.pageX - startX, false);
								}
							).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
						    return false;
						}
					);
                    horizontalTrackWidth = container.innerWidth();
                    sizeHorizontalScrollbar();
                }
            }

            function sizeHorizontalScrollbar() {
                container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
					function () {
					    horizontalTrackWidth -= $(this).outerWidth();
					}
				);

                horizontalTrack.width(horizontalTrackWidth + 'px');
                horizontalDragPosition = 0;
            }

            function resizeScrollbars() {
                if (isScrollableH && isScrollableV) {
                    var horizontalTrackHeight = horizontalTrack.outerHeight(),
						verticalTrackWidth = verticalTrack.outerWidth();
                    verticalTrackHeight -= horizontalTrackHeight;
                    $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
						function () {
						    horizontalTrackWidth += $(this).outerWidth();
						}
					);
                    horizontalTrackWidth -= verticalTrackWidth;
                    paneHeight -= verticalTrackWidth;
                    paneWidth -= horizontalTrackHeight;
                    horizontalTrack.parent().append(
						$('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
					);
                    sizeVerticalScrollbar();
                    sizeHorizontalScrollbar();
                }
                // reflow content
                if (isScrollableH) {
                    pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
                }
                contentHeight = pane.outerHeight();
                percentInViewV = contentHeight / paneHeight;

                if (isScrollableH) {
                    horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
                    if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
                        horizontalDragWidth = settings.horizontalDragMaxWidth;
                    } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
                        horizontalDragWidth = settings.horizontalDragMinWidth;
                    }
                    horizontalDrag.width(horizontalDragWidth + 'px');
                    dragMaxX = horizontalTrackWidth - horizontalDragWidth;
                    _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons
                }
                if (isScrollableV) {
                    verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
                    if (verticalDragHeight > settings.verticalDragMaxHeight) {
                        verticalDragHeight = settings.verticalDragMaxHeight;
                    } else if (verticalDragHeight < settings.verticalDragMinHeight) {
                        verticalDragHeight = settings.verticalDragMinHeight;
                    }
                    verticalDrag.height(verticalDragHeight + 'px');
                    dragMaxY = verticalTrackHeight - verticalDragHeight;
                    _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
                }
            }

            function appendArrows(ele, p, a1, a2) {
                var p1 = "before", p2 = "after", aTemp;

                // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
                // at the top or the bottom of the bar?
                if (p == "os") {
                    p = /Mac/.test(navigator.platform) ? "after" : "split";
                }
                if (p == p1) {
                    p2 = p;
                } else if (p == p2) {
                    p1 = p;
                    aTemp = a1;
                    a1 = a2;
                    a2 = aTemp;
                }

                ele[p1](a1)[p2](a2);
            }

            function getArrowScroll(dirX, dirY, ele) {
                return function () {
                    arrowScroll(dirX, dirY, this, ele);
                    this.blur();
                    return false;
                };
            }

            function arrowScroll(dirX, dirY, arrow, ele) {
                arrow = $(arrow).addClass('jspActive');

                var eve,
					scrollTimeout,
					isFirst = true,
					doScroll = function () {
					    if (dirX !== 0) {
					        jsp.scrollByX(dirX * settings.arrowButtonSpeed);
					    }
					    if (dirY !== 0) {
					        jsp.scrollByY(dirY * settings.arrowButtonSpeed);
					    }
					    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
					    isFirst = false;
					};

                doScroll();

                eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
                ele = ele || $('html');
                ele.bind(
					eve,
					function () {
					    arrow.removeClass('jspActive');
					    scrollTimeout && clearTimeout(scrollTimeout);
					    scrollTimeout = null;
					    ele.unbind(eve);
					}
				);
            }

            function initClickOnTrack() {
                removeClickOnTrack();
                if (isScrollableV) {
                    verticalTrack.bind(
						'mousedown.jsp',
						function (e) {
						    if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
						        var clickedTrack = $(this),
									offset = clickedTrack.offset(),
									direction = e.pageY - offset.top - verticalDragPosition,
									scrollTimeout,
									isFirst = true,
									doScroll = function () {
									    var offset = clickedTrack.offset(),
											pos = e.pageY - offset.top - verticalDragHeight / 2,
											contentDragY = paneHeight * settings.scrollPagePercent,
											dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
									    if (direction < 0) {
									        if (verticalDragPosition - dragY > pos) {
									            jsp.scrollByY(-contentDragY);
									        } else {
									            positionDragY(pos);
									        }
									    } else if (direction > 0) {
									        if (verticalDragPosition + dragY < pos) {
									            jsp.scrollByY(contentDragY);
									        } else {
									            positionDragY(pos);
									        }
									    } else {
									        cancelClick();
									        return;
									    }
									    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
									    isFirst = false;
									},
									cancelClick = function () {
									    scrollTimeout && clearTimeout(scrollTimeout);
									    scrollTimeout = null;
									    $(document).unbind('mouseup.jsp', cancelClick);
									};
						        doScroll();
						        $(document).bind('mouseup.jsp', cancelClick);
						        return false;
						    }
						}
					);
                }

                if (isScrollableH) {
                    horizontalTrack.bind(
						'mousedown.jsp',
						function (e) {
						    if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
						        var clickedTrack = $(this),
									offset = clickedTrack.offset(),
									direction = e.pageX - offset.left - horizontalDragPosition,
									scrollTimeout,
									isFirst = true,
									doScroll = function () {
									    var offset = clickedTrack.offset(),
											pos = e.pageX - offset.left - horizontalDragWidth / 2,
											contentDragX = paneWidth * settings.scrollPagePercent,
											dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
									    if (direction < 0) {
									        if (horizontalDragPosition - dragX > pos) {
									            jsp.scrollByX(-contentDragX);
									        } else {
									            positionDragX(pos);
									        }
									    } else if (direction > 0) {
									        if (horizontalDragPosition + dragX < pos) {
									            jsp.scrollByX(contentDragX);
									        } else {
									            positionDragX(pos);
									        }
									    } else {
									        cancelClick();
									        return;
									    }
									    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
									    isFirst = false;
									},
									cancelClick = function () {
									    scrollTimeout && clearTimeout(scrollTimeout);
									    scrollTimeout = null;
									    $(document).unbind('mouseup.jsp', cancelClick);
									};
						        doScroll();
						        $(document).bind('mouseup.jsp', cancelClick);
						        return false;
						    }
						}
					);
                }
            }

            function removeClickOnTrack() {
                if (horizontalTrack) {
                    horizontalTrack.unbind('mousedown.jsp');
                }
                if (verticalTrack) {
                    verticalTrack.unbind('mousedown.jsp');
                }
            }

            function cancelDrag() {
                $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');

                if (verticalDrag) {
                    verticalDrag.removeClass('jspActive');
                }
                if (horizontalDrag) {
                    horizontalDrag.removeClass('jspActive');
                }
            }

            function positionDragY(destY, animate) {
                if (!isScrollableV) {
                    return;
                }
                if (destY < 0) {
                    destY = 0;
                } else if (destY > dragMaxY) {
                    destY = dragMaxY;
                }

                // allow for devs to prevent the JSP from being scrolled
                var willScrollYEvent = new $.Event("jsp-will-scroll-y");
                elem.trigger(willScrollYEvent, [destY]);

                if (willScrollYEvent.isDefaultPrevented()) {
                    return;
                }

                var tmpVerticalDragPosition = destY || 0;

                var isAtTop = tmpVerticalDragPosition === 0,
					isAtBottom = tmpVerticalDragPosition == dragMaxY,
					percentScrolled = destY / dragMaxY,
					destTop = -percentScrolled * (contentHeight - paneHeight);

                // can't just check if(animate) because false is a valid value that could be passed in...
                if (animate === undefined) {
                    animate = settings.animateScroll;
                }
                if (animate) {
                    jsp.animate(verticalDrag, 'top', destY, _positionDragY, function () {
                        elem.trigger('jsp-user-scroll-y', [-destTop, isAtTop, isAtBottom]);
                    });
                } else {
                    verticalDrag.css('top', destY);
                    _positionDragY(destY);
                    elem.trigger('jsp-user-scroll-y', [-destTop, isAtTop, isAtBottom]);
                }

            }

            function _positionDragY(destY) {
                if (destY === undefined) {
                    destY = verticalDrag.position().top;
                }

                container.scrollTop(0);
                verticalDragPosition = destY || 0;

                var isAtTop = verticalDragPosition === 0,
					isAtBottom = verticalDragPosition == dragMaxY,
					percentScrolled = destY / dragMaxY,
					destTop = -percentScrolled * (contentHeight - paneHeight);

                if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
                    wasAtTop = isAtTop;
                    wasAtBottom = isAtBottom;
                    elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
                }

                updateVerticalArrows(isAtTop, isAtBottom);
                pane.css('top', destTop);
                elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
            }

            function positionDragX(destX, animate) {
                if (!isScrollableH) {
                    return;
                }
                if (destX < 0) {
                    destX = 0;
                } else if (destX > dragMaxX) {
                    destX = dragMaxX;
                }


                // allow for devs to prevent the JSP from being scrolled
                var willScrollXEvent = new $.Event("jsp-will-scroll-x");
                elem.trigger(willScrollXEvent, [destX]);

                if (willScrollXEvent.isDefaultPrevented()) {
                    return;
                }

                var tmpHorizontalDragPosition = destX || 0;

                var isAtLeft = tmpHorizontalDragPosition === 0,
					isAtRight = tmpHorizontalDragPosition == dragMaxX,
					percentScrolled = destX / dragMaxX,
					destLeft = -percentScrolled * (contentWidth - paneWidth);

                if (animate === undefined) {
                    animate = settings.animateScroll;
                }
                if (animate) {
                    jsp.animate(horizontalDrag, 'left', destX, _positionDragX, function () {
                        elem.trigger('jsp-user-scroll-x', [-destLeft, isAtLeft, isAtRight]);
                    });
                } else {
                    horizontalDrag.css('left', destX);
                    _positionDragX(destX);
                    elem.trigger('jsp-user-scroll-x', [-destLeft, isAtLeft, isAtRight]);
                }
            }

            function _positionDragX(destX) {
                if (destX === undefined) {
                    destX = horizontalDrag.position().left;
                }

                container.scrollTop(0);
                horizontalDragPosition = destX || 0;

                var isAtLeft = horizontalDragPosition === 0,
					isAtRight = horizontalDragPosition == dragMaxX,
					percentScrolled = destX / dragMaxX,
					destLeft = -percentScrolled * (contentWidth - paneWidth);

                if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
                    wasAtLeft = isAtLeft;
                    wasAtRight = isAtRight;
                    elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
                }

                updateHorizontalArrows(isAtLeft, isAtRight);
                pane.css('left', destLeft);
                elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
            }

            function updateVerticalArrows(isAtTop, isAtBottom) {
                if (settings.showArrows) {
                    arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
                    arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
                }
            }

            function updateHorizontalArrows(isAtLeft, isAtRight) {
                if (settings.showArrows) {
                    arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
                    arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
                }
            }

            function scrollToY(destY, animate) {
                var percentScrolled = destY / (contentHeight - paneHeight);
                positionDragY(percentScrolled * dragMaxY, animate);
            }

            function scrollToX(destX, animate) {
                var percentScrolled = destX / (contentWidth - paneWidth);
                positionDragX(percentScrolled * dragMaxX, animate);
            }

            function scrollToElement(ele, stickToTop, animate) {
                var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;

                // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
                // errors from the lookup...
                try {
                    e = $(ele);
                } catch (err) {
                    return;
                }
                eleHeight = e.outerHeight();
                eleWidth = e.outerWidth();

                container.scrollTop(0);
                container.scrollLeft(0);

                // loop through parents adding the offset top of any elements that are relatively positioned between
                // the focused element and the jspPane so we can get the true distance from the top
                // of the focused element to the top of the scrollpane...
                while (!e.is('.jspPane')) {
                    eleTop += e.position().top;
                    eleLeft += e.position().left;
                    e = e.offsetParent();
                    if (/^body|html$/i.test(e[0].nodeName)) {
                        // we ended up too high in the document structure. Quit!
                        return;
                    }
                }

                viewportTop = contentPositionY();
                maxVisibleEleTop = viewportTop + paneHeight;
                if (eleTop < viewportTop || stickToTop) { // element is above viewport
                    destY = eleTop - settings.horizontalGutter;
                } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
                    destY = eleTop - paneHeight + eleHeight + settings.horizontalGutter;
                }
                if (!isNaN(destY)) {
                    scrollToY(destY, animate);
                }

                viewportLeft = contentPositionX();
                maxVisibleEleLeft = viewportLeft + paneWidth;
                if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
                    destX = eleLeft - settings.horizontalGutter;
                } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
                    destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
                }
                if (!isNaN(destX)) {
                    scrollToX(destX, animate);
                }

            }

            function contentPositionX() {
                return -pane.position().left;
            }

            function contentPositionY() {
                return -pane.position().top;
            }

            function isCloseToBottom() {
                var scrollableHeight = contentHeight - paneHeight;
                return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10);
            }

            function isCloseToRight() {
                var scrollableWidth = contentWidth - paneWidth;
                return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10);
            }

            function initMousewheel() {
                container.unbind(mwEvent).bind(
					mwEvent,
					function (event, delta, deltaX, deltaY) {

					    if (!horizontalDragPosition) horizontalDragPosition = 0;
					    if (!verticalDragPosition) verticalDragPosition = 0;

					    var dX = horizontalDragPosition, dY = verticalDragPosition, factor = event.deltaFactor || settings.mouseWheelSpeed;
					    jsp.scrollBy(deltaX * factor, -deltaY * factor, false);
					    // return true if there was no movement so rest of screen can scroll
					    return dX == horizontalDragPosition && dY == verticalDragPosition;
					}
				);
            }

            function removeMousewheel() {
                container.unbind(mwEvent);
            }

            function nil() {
                return false;
            }

            function initFocusHandler() {
                pane.find(':input,a').unbind('focus.jsp').bind(
					'focus.jsp',
					function (e) {
					    scrollToElement(e.target, false);
					}
				);
            }

            function removeFocusHandler() {
                pane.find(':input,a').unbind('focus.jsp');
            }

            function initKeyboardNav() {
                var keyDown, elementHasScrolled, validParents = [];
                isScrollableH && validParents.push(horizontalBar[0]);
                isScrollableV && validParents.push(verticalBar[0]);

                // IE also focuses elements that don't have tabindex set.
                pane.bind(
					'focus.jsp',
					function () {
					    elem.focus();
					}
				);

                elem.attr('tabindex', 0)
					.unbind('keydown.jsp keypress.jsp')
					.bind(
						'keydown.jsp',
						function (e) {
						    if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)) {
						        return;
						    }
						    var dX = horizontalDragPosition, dY = verticalDragPosition;
						    switch (e.keyCode) {
						        case 40: // down
						        case 38: // up
						        case 34: // page down
						        case 32: // space
						        case 33: // page up
						        case 39: // right
						        case 37: // left
						            keyDown = e.keyCode;
						            keyDownHandler();
						            break;
						        case 35: // end
						            scrollToY(contentHeight - paneHeight);
						            keyDown = null;
						            break;
						        case 36: // home
						            scrollToY(0);
						            keyDown = null;
						            break;
						    }

						    elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition;
						    return !elementHasScrolled;
						}
					).bind(
						'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
						function (e) {
						    if (e.keyCode == keyDown) {
						        keyDownHandler();
						    }
						    // If the keypress is not related to the area, ignore it. Fixes problem with inputs inside scrolled area. Copied from line 955.
						    if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)) {
						        return;
						    }
						    return !elementHasScrolled;
						}
					);

                if (settings.hideFocus) {
                    elem.css('outline', 'none');
                    if ('hideFocus' in container[0]) {
                        elem.attr('hideFocus', true);
                    }
                } else {
                    elem.css('outline', '');
                    if ('hideFocus' in container[0]) {
                        elem.attr('hideFocus', false);
                    }
                }

                function keyDownHandler() {
                    var dX = horizontalDragPosition, dY = verticalDragPosition;
                    switch (keyDown) {
                        case 40: // down
                            jsp.scrollByY(settings.keyboardSpeed, false);
                            break;
                        case 38: // up
                            jsp.scrollByY(-settings.keyboardSpeed, false);
                            break;
                        case 34: // page down
                        case 32: // space
                            jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
                            break;
                        case 33: // page up
                            jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
                            break;
                        case 39: // right
                            jsp.scrollByX(settings.keyboardSpeed, false);
                            break;
                        case 37: // left
                            jsp.scrollByX(-settings.keyboardSpeed, false);
                            break;
                    }

                    elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition;
                    return elementHasScrolled;
                }
            }

            function removeKeyboardNav() {
                elem.attr('tabindex', '-1')
					.removeAttr('tabindex')
					.unbind('keydown.jsp keypress.jsp');

                pane.unbind('.jsp');
            }

            function observeHash() {
                if (location.hash && location.hash.length > 1) {
                    var e,
						retryInt,
						hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS
                    ;
                    try {
                        e = $('#' + hash + ', a[name="' + hash + '"]');
                    } catch (err) {
                        return;
                    }

                    if (e.length && pane.find(hash)) {
                        // nasty workaround but it appears to take a little while before the hash has done its thing
                        // to the rendered page so we just wait until the container's scrollTop has been messed up.
                        if (container.scrollTop() === 0) {
                            retryInt = setInterval(
								function () {
								    if (container.scrollTop() > 0) {
								        scrollToElement(e, true);
								        $(document).scrollTop(container.position().top);
								        clearInterval(retryInt);
								    }
								},
								50
							);
                        } else {
                            scrollToElement(e, true);
                            $(document).scrollTop(container.position().top);
                        }
                    }
                }
            }

            function hijackInternalLinks() {
                // only register the link handler once
                if ($(document.body).data('jspHijack')) {
                    return;
                }

                // remember that the handler was bound
                $(document.body).data('jspHijack', true);

                // use live handler to also capture newly created links
                $(document.body).delegate('a[href*="#"]', 'click', function (event) {
                    // does the link point to the same page?
                    // this also takes care of cases with a <base>-Tag or Links not starting with the hash #
                    // e.g. <a href="index.html#test"> when the current url already is index.html
                    var href = this.href.substr(0, this.href.indexOf('#')),
						locationHref = location.href,
						hash,
						element,
						container,
						jsp,
						scrollTop,
						elementTop;
                    if (location.href.indexOf('#') !== -1) {
                        locationHref = location.href.substr(0, location.href.indexOf('#'));
                    }
                    if (href !== locationHref) {
                        // the link points to another page
                        return;
                    }

                    // check if jScrollPane should handle this click event
                    hash = escape(this.href.substr(this.href.indexOf('#') + 1));

                    // find the element on the page
                    element;
                    try {
                        element = $('#' + hash + ', a[name="' + hash + '"]');
                    } catch (e) {
                        // hash is not a valid jQuery identifier
                        return;
                    }

                    if (!element.length) {
                        // this link does not point to an element on this page
                        return;
                    }

                    container = element.closest('.jspScrollable');
                    jsp = container.data('jsp');

                    // jsp might be another jsp instance than the one, that bound this event
                    // remember: this event is only bound once for all instances.
                    jsp.scrollToElement(element, true);

                    if (container[0].scrollIntoView) {
                        // also scroll to the top of the container (if it is not visible)
                        scrollTop = $(window).scrollTop();
                        elementTop = element.offset().top;
                        if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) {
                            container[0].scrollIntoView();
                        }
                    }

                    // jsp handled this event, prevent the browser default (scrolling :P)
                    event.preventDefault();
                });
            }

            // Init touch on iPad, iPhone, iPod, Android
            function initTouch() {
                var startX,
					startY,
					touchStartX,
					touchStartY,
					moved,
					moving = false;

                container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind(
					'touchstart.jsp',
					function (e) {
					    var touch = e.originalEvent.touches[0];
					    startX = contentPositionX();
					    startY = contentPositionY();
					    touchStartX = touch.pageX;
					    touchStartY = touch.pageY;
					    moved = false;
					    moving = true;
					}
				).bind(
					'touchmove.jsp',
					function (ev) {
					    if (!moving) {
					        return;
					    }

					    var touchPos = ev.originalEvent.touches[0],
							dX = horizontalDragPosition, dY = verticalDragPosition;

					    jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);

					    moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;

					    // return true if there was no movement so rest of screen can scroll
					    return dX == horizontalDragPosition && dY == verticalDragPosition;
					}
				).bind(
					'touchend.jsp',
					function (e) {
					    moving = false;
					    /*if(moved) {
							return false;
						}*/
					}
				).bind(
					'click.jsp-touchclick',
					function (e) {
					    if (moved) {
					        moved = false;
					        return false;
					    }
					}
				);
            }

            function destroy() {
                var currentY = contentPositionY(),
					currentX = contentPositionX();
                elem.removeClass('jspScrollable').unbind('.jsp');
                pane.unbind('.jsp');
                elem.replaceWith(originalElement.append(pane.children()));
                originalElement.scrollTop(currentY);
                originalElement.scrollLeft(currentX);

                // clear reinitialize timer if active
                if (reinitialiseInterval) {
                    clearInterval(reinitialiseInterval);
                }
            }

            // Public API
            $.extend(
				jsp,
				{
				    // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
				    // was initialised). The settings object which is passed in will override any settings from the
				    // previous time it was initialised - if you don't pass any settings then the ones from the previous
				    // initialisation will be used.
				    reinitialise: function (s) {
				        s = $.extend({}, settings, s);
				        initialise(s);
				    },
				    // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
				    // that it can be seen within the viewport. If stickToTop is true then the element will appear at
				    // the top of the viewport, if it is false then the viewport will scroll as little as possible to
				    // show the element. You can also specify if you want animation to occur. If you don't provide this
				    // argument then the animateScroll value from the settings object is used instead.
				    scrollToElement: function (ele, stickToTop, animate) {
				        scrollToElement(ele, stickToTop, animate);
				    },
				    // Scrolls the pane so that the specified co-ordinates within the content are at the top left
				    // of the viewport. animate is optional and if not passed then the value of animateScroll from
				    // the settings object this jScrollPane was initialised with is used.
				    scrollTo: function (destX, destY, animate) {
				        scrollToX(destX, animate);
				        scrollToY(destY, animate);
				    },
				    // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
				    // viewport. animate is optional and if not passed then the value of animateScroll from the settings
				    // object this jScrollPane was initialised with is used.
				    scrollToX: function (destX, animate) {
				        scrollToX(destX, animate);
				    },
				    // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
				    // viewport. animate is optional and if not passed then the value of animateScroll from the settings
				    // object this jScrollPane was initialised with is used.
				    scrollToY: function (destY, animate) {
				        scrollToY(destY, animate);
				    },
				    // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
				    // is optional and if not passed then the value of animateScroll from the settings object this
				    // jScrollPane was initialised with is used.
				    scrollToPercentX: function (destPercentX, animate) {
				        scrollToX(destPercentX * (contentWidth - paneWidth), animate);
				    },
				    // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
				    // is optional and if not passed then the value of animateScroll from the settings object this
				    // jScrollPane was initialised with is used.
				    scrollToPercentY: function (destPercentY, animate) {
				        scrollToY(destPercentY * (contentHeight - paneHeight), animate);
				    },
				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
				    scrollBy: function (deltaX, deltaY, animate) {
				        jsp.scrollByX(deltaX, animate);
				        jsp.scrollByY(deltaY, animate);
				    },
				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
				    scrollByX: function (deltaX, animate) {
				        var destX = contentPositionX() + Math[deltaX < 0 ? 'floor' : 'ceil'](deltaX),
							percentScrolled = destX / (contentWidth - paneWidth);
				        positionDragX(percentScrolled * dragMaxX, animate);
				    },
				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
				    scrollByY: function (deltaY, animate) {
				        var destY = contentPositionY() + Math[deltaY < 0 ? 'floor' : 'ceil'](deltaY),
							percentScrolled = destY / (contentHeight - paneHeight);
				        positionDragY(percentScrolled * dragMaxY, animate);
				    },
				    // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
				    // this). animate is optional and if not passed then the value of animateScroll from the settings
				    // object this jScrollPane was initialised with is used.
				    positionDragX: function (x, animate) {
				        positionDragX(x, animate);
				    },
				    // Positions the vertical drag at the specified y position (and updates the viewport to reflect
				    // this). animate is optional and if not passed then the value of animateScroll from the settings
				    // object this jScrollPane was initialised with is used.
				    positionDragY: function (y, animate) {
				        positionDragY(y, animate);
				    },
				    // This method is called when jScrollPane is trying to animate to a new position. You can override
				    // it if you want to provide advanced animation functionality. It is passed the following arguments:
				    //  * ele          - the element whose position is being animated
				    //  * prop         - the property that is being animated
				    //  * value        - the value it's being animated to
				    //  * stepCallback - a function that you must execute each time you update the value of the property
				    //  * completeCallback - a function that will be executed after the animation had finished
				    // You can use the default implementation (below) as a starting point for your own implementation.
				    animate: function (ele, prop, value, stepCallback, completeCallback) {
				        var params = {};
				        params[prop] = value;
				        ele.animate(
							params,
							{
							    'duration': settings.animateDuration,
							    'easing': settings.animateEase,
							    'queue': false,
							    'step': stepCallback,
							    'complete': completeCallback
							}
						);
				    },
				    // Returns the current x position of the viewport with regards to the content pane.
				    getContentPositionX: function () {
				        return contentPositionX();
				    },
				    // Returns the current y position of the viewport with regards to the content pane.
				    getContentPositionY: function () {
				        return contentPositionY();
				    },
				    // Returns the width of the content within the scroll pane.
				    getContentWidth: function () {
				        return contentWidth;
				    },
				    // Returns the height of the content within the scroll pane.
				    getContentHeight: function () {
				        return contentHeight;
				    },
				    // Returns the horizontal position of the viewport within the pane content.
				    getPercentScrolledX: function () {
				        return contentPositionX() / (contentWidth - paneWidth);
				    },
				    // Returns the vertical position of the viewport within the pane content.
				    getPercentScrolledY: function () {
				        return contentPositionY() / (contentHeight - paneHeight);
				    },
				    // Returns whether or not this scrollpane has a horizontal scrollbar.
				    getIsScrollableH: function () {
				        return isScrollableH;
				    },
				    // Returns whether or not this scrollpane has a vertical scrollbar.
				    getIsScrollableV: function () {
				        return isScrollableV;
				    },
				    // Gets a reference to the content pane. It is important that you use this method if you want to
				    // edit the content of your jScrollPane as if you access the element directly then you may have some
				    // problems (as your original element has had additional elements for the scrollbars etc added into
				    // it).
				    getContentPane: function () {
				        return pane;
				    },
				    // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
				    // animateScroll value from settings is used instead.
				    scrollToBottom: function (animate) {
				        positionDragY(dragMaxY, animate);
				    },
				    // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
				    // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
				    // contents of your scroll pane will work then call this function.
				    hijackInternalLinks: $.noop,
				    // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
				    // initialised.
				    destroy: function () {
				        destroy();
				    }
				}
			);

            initialise(s);
        }

        // Pluginifying code...
        settings = $.extend({}, $.fn.jScrollPane.defaults, settings);

        // Apply default speed
        $.each(['arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function () {
            settings[this] = settings[this] || settings.speed;
        });

        return this.each(
			function () {
			    var elem = $(this), jspApi = elem.data('jsp');
			    if (jspApi) {
			        jspApi.reinitialise(settings);
			    } else {
			        $("script", elem).filter('[type="text/javascript"],:not([type])').remove();
			        jspApi = new JScrollPane(elem, settings);
			        elem.data('jsp', jspApi);
			    }
			}
		);
    };

    $.fn.jScrollPane.defaults = {
        showArrows: false,
        maintainPosition: true,
        stickToBottom: false,
        stickToRight: false,
        clickOnTrack: true,
        autoReinitialise: false,
        autoReinitialiseDelay: 500,
        verticalDragMinHeight: 0,
        verticalDragMaxHeight: 99999,
        horizontalDragMinWidth: 0,
        horizontalDragMaxWidth: 99999,
        contentWidth: undefined,
        animateScroll: false,
        animateDuration: 300,
        animateEase: 'linear',
        hijackInternalLinks: false,
        verticalGutter: 4,
        horizontalGutter: 4,
        mouseWheelSpeed: 3,
        arrowButtonSpeed: 0,
        arrowRepeatFreq: 50,
        arrowScrollOnHover: false,
        trackClickSpeed: 0,
        trackClickRepeatFreq: 70,
        verticalArrowPositions: 'split',
        horizontalArrowPositions: 'split',
        enableKeyboardNavigation: true,
        hideFocus: false,
        keyboardSpeed: 0,
        initialDelay: 300,        // Delay before starting repeating
        speed: 30,		// Default speed when others falsey
        scrollPagePercent: .8		// Percent of visible area scrolled when pageUp/Down or track area pressed
    };

}));;
/*!
 * jQuery Mousewheel 3.1.12
 *
 * Copyright 2014 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

(function (factory) {    
    // Browser globals
    factory(jQuery);
}(function ($) {

    var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
        toBind = ('onwheel' in document || document.documentMode >= 9) ?
                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
        slice = Array.prototype.slice,
        nullLowestDeltaTimeout, lowestDelta;

    if ($.event.fixHooks) {
        for (var i = toFix.length; i;) {
            $.event.fixHooks[toFix[--i]] = $.event.mouseHooks;
        }
    }

    var special = $.event.special.mousewheel = {
        version: '3.1.12',

        setup: function () {
            if (this.addEventListener) {
                for (var i = toBind.length; i;) {
                    this.addEventListener(toBind[--i], handler, false);
                }
            } else {
                this.onmousewheel = handler;
            }
            // Store the line height and page height for this particular element
            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
        },

        teardown: function () {
            if (this.removeEventListener) {
                for (var i = toBind.length; i;) {
                    this.removeEventListener(toBind[--i], handler, false);
                }
            } else {
                this.onmousewheel = null;
            }
            // Clean up the data we added to the element
            $.removeData(this, 'mousewheel-line-height');
            $.removeData(this, 'mousewheel-page-height');
        },

        getLineHeight: function (elem) {
            var $elem = $(elem),
                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
            if (!$parent.length) {
                $parent = $('body');
            }
            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
        },

        getPageHeight: function (elem) {
            return $(elem).height();
        },

        settings: {
            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
            normalizeOffset: true  // calls getBoundingClientRect for each event
        }
    };

    $.fn.extend({
        mousewheel: function (fn) {
            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
        },

        unmousewheel: function (fn) {
            return this.unbind('mousewheel', fn);
        }
    });


    function handler(event) {
        var orgEvent = event || window.event,
            args = slice.call(arguments, 1),
            delta = 0,
            deltaX = 0,
            deltaY = 0,
            absDelta = 0,
            offsetX = 0,
            offsetY = 0;
        event = $.event.fix(orgEvent);
        event.type = 'mousewheel';

        // Old school scrollwheel delta
        if ('detail' in orgEvent) { deltaY = orgEvent.detail * -1; }
        if ('wheelDelta' in orgEvent) { deltaY = orgEvent.wheelDelta; }
        if ('wheelDeltaY' in orgEvent) { deltaY = orgEvent.wheelDeltaY; }
        if ('wheelDeltaX' in orgEvent) { deltaX = orgEvent.wheelDeltaX * -1; }

        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
        if ('axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
            deltaX = deltaY * -1;
            deltaY = 0;
        }

        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
        delta = deltaY === 0 ? deltaX : deltaY;

        // New school wheel delta (wheel event)
        if ('deltaY' in orgEvent) {
            deltaY = orgEvent.deltaY * -1;
            delta = deltaY;
        }
        if ('deltaX' in orgEvent) {
            deltaX = orgEvent.deltaX;
            if (deltaY === 0) { delta = deltaX * -1; }
        }

        // No change actually happened, no reason to go any further
        if (deltaY === 0 && deltaX === 0) { return; }

        // Need to convert lines and pages to pixels if we aren't already in pixels
        // There are three delta modes:
        //   * deltaMode 0 is by pixels, nothing to do
        //   * deltaMode 1 is by lines
        //   * deltaMode 2 is by pages
        if (orgEvent.deltaMode === 1) {
            var lineHeight = $.data(this, 'mousewheel-line-height');
            delta *= lineHeight;
            deltaY *= lineHeight;
            deltaX *= lineHeight;
        } else if (orgEvent.deltaMode === 2) {
            var pageHeight = $.data(this, 'mousewheel-page-height');
            delta *= pageHeight;
            deltaY *= pageHeight;
            deltaX *= pageHeight;
        }

        // Store lowest absolute delta to normalize the delta values
        absDelta = Math.max(Math.abs(deltaY), Math.abs(deltaX));

        if (!lowestDelta || absDelta < lowestDelta) {
            lowestDelta = absDelta;

            // Adjust older deltas if necessary
            if (shouldAdjustOldDeltas(orgEvent, absDelta)) {
                lowestDelta /= 40;
            }
        }

        // Adjust older deltas if necessary
        if (shouldAdjustOldDeltas(orgEvent, absDelta)) {
            // Divide all the things by 40!
            delta /= 40;
            deltaX /= 40;
            deltaY /= 40;
        }

        // Get a whole, normalized value for the deltas
        delta = Math[delta >= 1 ? 'floor' : 'ceil'](delta / lowestDelta);
        deltaX = Math[deltaX >= 1 ? 'floor' : 'ceil'](deltaX / lowestDelta);
        deltaY = Math[deltaY >= 1 ? 'floor' : 'ceil'](deltaY / lowestDelta);

        // Normalise offsetX and offsetY properties
        if (special.settings.normalizeOffset && this.getBoundingClientRect) {
            var boundingRect = this.getBoundingClientRect();
            offsetX = event.clientX - boundingRect.left;
            offsetY = event.clientY - boundingRect.top;
        }

        // Add information to the event object
        event.deltaX = deltaX;
        event.deltaY = deltaY;
        event.deltaFactor = lowestDelta;
        event.offsetX = offsetX;
        event.offsetY = offsetY;
        // Go ahead and set deltaMode to 0 since we converted to pixels
        // Although this is a little odd since we overwrite the deltaX/Y
        // properties with normalized deltas.
        event.deltaMode = 0;

        // Add event and delta to the front of the arguments
        args.unshift(event, delta, deltaX, deltaY);

        // Clearout lowestDelta after sometime to better
        // handle multiple device types that give different
        // a different lowestDelta
        // Ex: trackpad = 3 and mouse wheel = 120
        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);

        return ($.event.dispatch || $.event.handle).apply(this, args);
    }

    function nullLowestDelta() {
        lowestDelta = null;
    }

    function shouldAdjustOldDeltas(orgEvent, absDelta) {
        // If this is an older event and the delta is divisable by 120,
        // then we are assuming that the browser is treating this as an
        // older mouse wheel event and that we should divide the deltas
        // by 40 to try and get a more usable deltaFactor.
        // Side note, this actually impacts the reported scroll distance
        // in older browsers and can cause scrolling to be slower than native.
        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
    }

}));;
/*
     _ _      _       _
 ___| (_) ___| | __  (_)___
/ __| | |/ __| |/ /  | / __|
\__ \ | | (__|   < _ | \__ \
|___/_|_|\___|_|\_(_)/ |___/
                   |__/

 Version: 1.8.1
  Author: Ken Wheeler
 Website: http://kenwheeler.github.io
    Docs: http://kenwheeler.github.io/slick
    Repo: http://github.com/kenwheeler/slick
  Issues: http://github.com/kenwheeler/slick/issues

 */
/* global window, document, define, jQuery, setInterval, clearInterval */
(function ($) {
    'use strict';
    var Slick = window.Slick || {};

    Slick = (function () {

        var instanceUid = 0;

        function Slick(element, settings) {

            var _ = this, dataSettings;

            _.defaults = {
                accessibility: true,
                adaptiveHeight: false,
                appendArrows: $(element),
                appendDots: $(element),
                arrows: true,
                asNavFor: null,
                prevArrow: '<button class="slick-prev" aria-label="Previous" type="button">Previous</button>',
                nextArrow: '<button class="slick-next" aria-label="Next" type="button">Next</button>',
                autoplay: false,
                autoplaySpeed: 3000,
                centerMode: false,
                centerPadding: '50px',
                cssEase: 'ease',
                customPaging: function (slider, i) {
                    return $('<button type="button" />').text(i + 1);
                },
                dots: false,
                dotsClass: 'slick-dots',
                draggable: true,
                easing: 'linear',
                edgeFriction: 0.35,
                fade: false,
                focusOnSelect: false,
                focusOnChange: false,
                infinite: true,
                initialSlide: 0,
                lazyLoad: 'ondemand',
                mobileFirst: false,
                pauseOnHover: true,
                pauseOnFocus: true,
                pauseOnDotsHover: false,
                respondTo: 'window',
                responsive: null,
                rows: 0,
                rtl: false,
                slide: '',
                slidesPerRow: 1,
                slidesToShow: 1,
                slidesToScroll: 1,
                speed: 500,
                swipe: true,
                swipeToSlide: false,
                touchMove: true,
                touchThreshold: 5,
                useCSS: true,
                useTransform: true,
                variableWidth: false,
                vertical: false,
                verticalSwiping: false,
                waitForAnimate: true,
                zIndex: 1000
            };

            _.initials = {
                animating: false,
                dragging: false,
                autoPlayTimer: null,
                currentDirection: 0,
                currentLeft: null,
                currentSlide: 0,
                direction: 1,
                $dots: null,
                listWidth: null,
                listHeight: null,
                loadIndex: 0,
                $nextArrow: null,
                $prevArrow: null,
                scrolling: false,
                slideCount: null,
                slideWidth: null,
                $slideTrack: null,
                $slides: null,
                sliding: false,
                slideOffset: 0,
                swipeLeft: null,
                swiping: false,
                $list: null,
                touchObject: {},
                transformsEnabled: false,
                unslicked: false
            };

            $.extend(_, _.initials);

            _.activeBreakpoint = null;
            _.animType = null;
            _.animProp = null;
            _.breakpoints = [];
            _.breakpointSettings = [];
            _.cssTransitions = false;
            _.focussed = false;
            _.interrupted = false;
            _.hidden = 'hidden';
            _.paused = true;
            _.positionProp = null;
            _.respondTo = null;
            _.rowCount = 1;
            _.shouldClick = true;
            _.$slider = $(element);
            _.$slidesCache = null;
            _.transformType = null;
            _.transitionType = null;
            _.visibilityChange = 'visibilitychange';
            _.windowWidth = 0;
            _.windowTimer = null;

            dataSettings = $(element).data('slick') || {};

            _.options = $.extend({}, _.defaults, settings, dataSettings);

            _.currentSlide = _.options.initialSlide;

            _.originalSettings = _.options;

            if (typeof document.mozHidden !== 'undefined') {
                _.hidden = 'mozHidden';
                _.visibilityChange = 'mozvisibilitychange';
            } else if (typeof document.webkitHidden !== 'undefined') {
                _.hidden = 'webkitHidden';
                _.visibilityChange = 'webkitvisibilitychange';
            }

            _.autoPlay = $.proxy(_.autoPlay, _);
            _.autoPlayClear = $.proxy(_.autoPlayClear, _);
            _.autoPlayIterator = $.proxy(_.autoPlayIterator, _);
            _.changeSlide = $.proxy(_.changeSlide, _);
            _.clickHandler = $.proxy(_.clickHandler, _);
            _.selectHandler = $.proxy(_.selectHandler, _);
            _.setPosition = $.proxy(_.setPosition, _);
            _.swipeHandler = $.proxy(_.swipeHandler, _);
            _.dragHandler = $.proxy(_.dragHandler, _);
            _.keyHandler = $.proxy(_.keyHandler, _);

            _.instanceUid = instanceUid++;

            // A simple way to check for HTML strings
            // Strict HTML recognition (must start with <)
            // Extracted from jQuery v1.11 source
            _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;


            _.registerBreakpoints();
            _.init(true);

        }

        return Slick;

    }());

    Slick.prototype.activateADA = function () {
        var _ = this;

        _.$slideTrack.find('.slick-active').attr({
            'aria-hidden': 'false'
        }).find('a, input, button, select').attr({
            'tabindex': '0'
        });

    };

    Slick.prototype.addSlide = Slick.prototype.slickAdd = function (markup, index, addBefore) {

        var _ = this;

        if (typeof (index) === 'boolean') {
            addBefore = index;
            index = null;
        } else if (index < 0 || (index >= _.slideCount)) {
            return false;
        }

        _.unload();

        if (typeof (index) === 'number') {
            if (index === 0 && _.$slides.length === 0) {
                $(markup).appendTo(_.$slideTrack);
            } else if (addBefore) {
                $(markup).insertBefore(_.$slides.eq(index));
            } else {
                $(markup).insertAfter(_.$slides.eq(index));
            }
        } else {
            if (addBefore === true) {
                $(markup).prependTo(_.$slideTrack);
            } else {
                $(markup).appendTo(_.$slideTrack);
            }
        }

        _.$slides = _.$slideTrack.children(this.options.slide);

        _.$slideTrack.children(this.options.slide).detach();

        _.$slideTrack.append(_.$slides);

        _.$slides.each(function (index, element) {
            $(element).attr('data-slick-index', index);
        });

        _.$slidesCache = _.$slides;

        _.reinit();

    };

    Slick.prototype.animateHeight = function () {
        var _ = this;
        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
            _.$list.animate({
                height: targetHeight
            }, _.options.speed);
        }
    };

    Slick.prototype.animateSlide = function (targetLeft, callback) {

        var animProps = {},
            _ = this;

        _.animateHeight();

        if (_.options.rtl === true && _.options.vertical === false) {
            targetLeft = -targetLeft;
        }
        if (_.transformsEnabled === false) {
            if (_.options.vertical === false) {
                _.$slideTrack.animate({
                    left: targetLeft
                }, _.options.speed, _.options.easing, callback);
            } else {
                _.$slideTrack.animate({
                    top: targetLeft
                }, _.options.speed, _.options.easing, callback);
            }

        } else {

            if (_.cssTransitions === false) {
                if (_.options.rtl === true) {
                    _.currentLeft = -(_.currentLeft);
                }
                $({
                    animStart: _.currentLeft
                }).animate({
                    animStart: targetLeft
                }, {
                    duration: _.options.speed,
                    easing: _.options.easing,
                    step: function (now) {
                        now = Math.ceil(now);
                        if (_.options.vertical === false) {
                            animProps[_.animType] = 'translate(' +
                                now + 'px, 0px)';
                            _.$slideTrack.css(animProps);
                        } else {
                            animProps[_.animType] = 'translate(0px,' +
                                now + 'px)';
                            _.$slideTrack.css(animProps);
                        }
                    },
                    complete: function () {
                        if (callback) {
                            callback.call();
                        }
                    }
                });

            } else {

                _.applyTransition();
                targetLeft = Math.ceil(targetLeft);

                if (_.options.vertical === false) {
                    animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)';
                } else {
                    animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)';
                }
                _.$slideTrack.css(animProps);

                if (callback) {
                    setTimeout(function () {

                        _.disableTransition();

                        callback.call();
                    }, _.options.speed);
                }

            }

        }

    };

    Slick.prototype.getNavTarget = function () {

        var _ = this,
            asNavFor = _.options.asNavFor;

        if (asNavFor && asNavFor !== null) {
            asNavFor = $(asNavFor).not(_.$slider);
        }

        return asNavFor;

    };

    Slick.prototype.asNavFor = function (index) {

        var _ = this,
            asNavFor = _.getNavTarget();

        if (asNavFor !== null && typeof asNavFor === 'object') {
            asNavFor.each(function () {
                var target = $(this).slick('getSlick');
                if (!target.unslicked) {
                    target.slideHandler(index, true);
                }
            });
        }

    };

    Slick.prototype.applyTransition = function (slide) {

        var _ = this,
            transition = {};

        if (_.options.fade === false) {
            transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase;
        } else {
            transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase;
        }

        if (_.options.fade === false) {
            _.$slideTrack.css(transition);
        } else {
            _.$slides.eq(slide).css(transition);
        }

    };

    Slick.prototype.autoPlay = function () {

        var _ = this;

        _.autoPlayClear();

        if (_.slideCount > _.options.slidesToShow) {
            _.autoPlayTimer = setInterval(_.autoPlayIterator, _.options.autoplaySpeed);
        }

    };

    Slick.prototype.autoPlayClear = function () {

        var _ = this;

        if (_.autoPlayTimer) {
            clearInterval(_.autoPlayTimer);
        }

    };

    Slick.prototype.autoPlayIterator = function () {

        var _ = this,
            slideTo = _.currentSlide + _.options.slidesToScroll;

        if (!_.paused && !_.interrupted && !_.focussed) {

            if (_.options.infinite === false) {

                if (_.direction === 1 && (_.currentSlide + 1) === (_.slideCount - 1)) {
                    _.direction = 0;
                }

                else if (_.direction === 0) {

                    slideTo = _.currentSlide - _.options.slidesToScroll;

                    if (_.currentSlide - 1 === 0) {
                        _.direction = 1;
                    }

                }

            }

            _.slideHandler(slideTo);

        }

    };

    Slick.prototype.buildArrows = function () {

        var _ = this;

        if (_.options.arrows === true) {

            _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow');
            _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow');

            if (_.slideCount > _.options.slidesToShow) {

                _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
                _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');

                if (_.htmlExpr.test(_.options.prevArrow)) {
                    _.$prevArrow.prependTo(_.options.appendArrows);
                }

                if (_.htmlExpr.test(_.options.nextArrow)) {
                    _.$nextArrow.appendTo(_.options.appendArrows);
                }

                if (_.options.infinite !== true) {
                    _.$prevArrow
                        .addClass('slick-disabled')
                        .attr('aria-disabled', 'true');
                }

            } else {

                _.$prevArrow.add(_.$nextArrow)

                    .addClass('slick-hidden')
                    .attr({
                        'aria-disabled': 'true',
                        'tabindex': '-1'
                    });

            }

        }

    };

    Slick.prototype.buildDots = function () {

        var _ = this,
            i, dot;

        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {

            _.$slider.addClass('slick-dotted');

            dot = $('<ul />').addClass(_.options.dotsClass);

            for (i = 0; i <= _.getDotCount() ; i += 1) {
                dot.append($('<li />').append(_.options.customPaging.call(this, _, i)));
            }

            _.$dots = dot.appendTo(_.options.appendDots);

            _.$dots.find('li').first().addClass('slick-active');

        }

    };

    Slick.prototype.buildOut = function () {

        var _ = this;

        _.$slides =
            _.$slider
                .children(_.options.slide + ':not(.slick-cloned)')
                .addClass('slick-slide');

        _.slideCount = _.$slides.length;

        _.$slides.each(function (index, element) {
            $(element)
                .attr('data-slick-index', index)
                .data('originalStyling', $(element).attr('style') || '');
        });

        _.$slider.addClass('slick-slider');

        _.$slideTrack = (_.slideCount === 0) ?
            $('<div class="slick-track"/>').appendTo(_.$slider) :
            _.$slides.wrapAll('<div class="slick-track"/>').parent();

        _.$list = _.$slideTrack.wrap(
            '<div class="slick-list"/>').parent();
        _.$slideTrack.css('opacity', 0);

        if (_.options.centerMode === true || _.options.swipeToSlide === true) {
            _.options.slidesToScroll = 1;
        }

        $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading');

        _.setupInfinite();

        _.buildArrows();

        _.buildDots();

        _.updateDots();


        _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);

        if (_.options.draggable === true) {
            _.$list.addClass('draggable');
        }

    };

    Slick.prototype.buildRows = function () {

        var _ = this, a, b, c, newSlides, numOfSlides, originalSlides, slidesPerSection;

        newSlides = document.createDocumentFragment();
        originalSlides = _.$slider.children();

        if (_.options.rows > 0) {

            slidesPerSection = _.options.slidesPerRow * _.options.rows;
            numOfSlides = Math.ceil(
                originalSlides.length / slidesPerSection
            );

            for (a = 0; a < numOfSlides; a++) {
                var slide = document.createElement('div');
                for (b = 0; b < _.options.rows; b++) {
                    var row = document.createElement('div');
                    for (c = 0; c < _.options.slidesPerRow; c++) {
                        var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c));
                        if (originalSlides.get(target)) {
                            row.appendChild(originalSlides.get(target));
                        }
                    }
                    slide.appendChild(row);
                }
                newSlides.appendChild(slide);
            }

            _.$slider.empty().append(newSlides);
            _.$slider.children().children().children()
                .css({
                    'width': (100 / _.options.slidesPerRow) + '%',
                    'display': 'inline-block'
                });

        }

    };

    Slick.prototype.checkResponsive = function (initial, forceUpdate) {

        var _ = this,
            breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false;
        var sliderWidth = _.$slider.width();
        var windowWidth = window.innerWidth || $(window).width();

        if (_.respondTo === 'window') {
            respondToWidth = windowWidth;
        } else if (_.respondTo === 'slider') {
            respondToWidth = sliderWidth;
        } else if (_.respondTo === 'min') {
            respondToWidth = Math.min(windowWidth, sliderWidth);
        }

        if (_.options.responsive &&
            _.options.responsive.length &&
            _.options.responsive !== null) {

            targetBreakpoint = null;

            for (breakpoint in _.breakpoints) {
                if (_.breakpoints.hasOwnProperty(breakpoint)) {
                    if (_.originalSettings.mobileFirst === false) {
                        if (respondToWidth < _.breakpoints[breakpoint]) {
                            targetBreakpoint = _.breakpoints[breakpoint];
                        }
                    } else {
                        if (respondToWidth > _.breakpoints[breakpoint]) {
                            targetBreakpoint = _.breakpoints[breakpoint];
                        }
                    }
                }
            }

            if (targetBreakpoint !== null) {
                if (_.activeBreakpoint !== null) {
                    if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) {
                        _.activeBreakpoint =
                            targetBreakpoint;
                        if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
                            _.unslick(targetBreakpoint);
                        } else {
                            _.options = $.extend({}, _.originalSettings,
                                _.breakpointSettings[
                                    targetBreakpoint]);
                            if (initial === true) {
                                _.currentSlide = _.options.initialSlide;
                            }
                            _.refresh(initial);
                        }
                        triggerBreakpoint = targetBreakpoint;
                    }
                } else {
                    _.activeBreakpoint = targetBreakpoint;
                    if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
                        _.unslick(targetBreakpoint);
                    } else {
                        _.options = $.extend({}, _.originalSettings,
                            _.breakpointSettings[
                                targetBreakpoint]);
                        if (initial === true) {
                            _.currentSlide = _.options.initialSlide;
                        }
                        _.refresh(initial);
                    }
                    triggerBreakpoint = targetBreakpoint;
                }
            } else {
                if (_.activeBreakpoint !== null) {
                    _.activeBreakpoint = null;
                    _.options = _.originalSettings;
                    if (initial === true) {
                        _.currentSlide = _.options.initialSlide;
                    }
                    _.refresh(initial);
                    triggerBreakpoint = targetBreakpoint;
                }
            }

            // only trigger breakpoints during an actual break. not on initialize.
            if (!initial && triggerBreakpoint !== false) {
                _.$slider.trigger('breakpoint', [_, triggerBreakpoint]);
            }
        }

    };

    Slick.prototype.changeSlide = function (event, dontAnimate) {

        var _ = this,
            $target = $(event.currentTarget),
            indexOffset, slideOffset, unevenOffset;

        // If target is a link, prevent default action.
        if ($target.is('a')) {
            event.preventDefault();
        }

        // If target is not the <li> element (ie: a child), find the <li>.
        if (!$target.is('li')) {
            $target = $target.closest('li');
        }

        unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0);
        indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll;

        switch (event.data.message) {

            case 'previous':
                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset;
                if (_.slideCount > _.options.slidesToShow) {
                    _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate);
                }
                break;

            case 'next':
                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset;
                if (_.slideCount > _.options.slidesToShow) {
                    _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate);
                }
                break;

            case 'index':
                var index = event.data.index === 0 ? 0 :
                    event.data.index || $target.index() * _.options.slidesToScroll;

                _.slideHandler(_.checkNavigable(index), false, dontAnimate);
                $target.children().trigger('focus');
                break;

            default:
                return;
        }

    };

    Slick.prototype.checkNavigable = function (index) {

        var _ = this,
            navigables, prevNavigable;

        navigables = _.getNavigableIndexes();
        prevNavigable = 0;
        if (index > navigables[navigables.length - 1]) {
            index = navigables[navigables.length - 1];
        } else {
            for (var n in navigables) {
                if (index < navigables[n]) {
                    index = prevNavigable;
                    break;
                }
                prevNavigable = navigables[n];
            }
        }

        return index;
    };

    Slick.prototype.cleanUpEvents = function () {

        var _ = this;

        if (_.options.dots && _.$dots !== null) {

            $('li', _.$dots)
                .off('click.slick', _.changeSlide)
                .off('mouseenter.slick', $.proxy(_.interrupt, _, true))
                .off('mouseleave.slick', $.proxy(_.interrupt, _, false));

            if (_.options.accessibility === true) {
                _.$dots.off('keydown.slick', _.keyHandler);
            }
        }

        _.$slider.off('focus.slick blur.slick');

        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
            _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide);
            _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide);

            if (_.options.accessibility === true) {
                _.$prevArrow && _.$prevArrow.off('keydown.slick', _.keyHandler);
                _.$nextArrow && _.$nextArrow.off('keydown.slick', _.keyHandler);
            }
        }

        _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler);
        _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler);
        _.$list.off('touchend.slick mouseup.slick', _.swipeHandler);
        _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler);

        _.$list.off('click.slick', _.clickHandler);

        $(document).off(_.visibilityChange, _.visibility);

        _.cleanUpSlideEvents();

        if (_.options.accessibility === true) {
            _.$list.off('keydown.slick', _.keyHandler);
        }

        if (_.options.focusOnSelect === true) {
            $(_.$slideTrack).children().off('click.slick', _.selectHandler);
        }

        $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange);

        $(window).off('resize.slick.slick-' + _.instanceUid, _.resize);

        $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault);

        $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition);

    };

    Slick.prototype.cleanUpSlideEvents = function () {

        var _ = this;

        _.$list.off('mouseenter.slick', $.proxy(_.interrupt, _, true));
        _.$list.off('mouseleave.slick', $.proxy(_.interrupt, _, false));

    };

    Slick.prototype.cleanUpRows = function () {

        var _ = this, originalSlides;

        if (_.options.rows > 0) {
            originalSlides = _.$slides.children().children();
            originalSlides.removeAttr('style');
            _.$slider.empty().append(originalSlides);
        }

    };

    Slick.prototype.clickHandler = function (event) {

        var _ = this;

        if (_.shouldClick === false) {
            event.stopImmediatePropagation();
            event.stopPropagation();
            event.preventDefault();
        }

    };

    Slick.prototype.destroy = function (refresh) {

        var _ = this;

        _.autoPlayClear();

        _.touchObject = {};

        _.cleanUpEvents();

        $('.slick-cloned', _.$slider).detach();

        if (_.$dots) {
            _.$dots.remove();
        }

        if (_.$prevArrow && _.$prevArrow.length) {

            _.$prevArrow
                .removeClass('slick-disabled slick-arrow slick-hidden')
                .removeAttr('aria-hidden aria-disabled tabindex')
                .css('display', '');

            if (_.htmlExpr.test(_.options.prevArrow)) {
                _.$prevArrow.remove();
            }
        }

        if (_.$nextArrow && _.$nextArrow.length) {

            _.$nextArrow
                .removeClass('slick-disabled slick-arrow slick-hidden')
                .removeAttr('aria-hidden aria-disabled tabindex')
                .css('display', '');

            if (_.htmlExpr.test(_.options.nextArrow)) {
                _.$nextArrow.remove();
            }
        }


        if (_.$slides) {

            _.$slides
                .removeClass('slick-slide slick-active slick-center slick-visible slick-current')
                .removeAttr('aria-hidden')
                .removeAttr('data-slick-index')
                .each(function () {
                    $(this).attr('style', $(this).data('originalStyling'));
                });

            _.$slideTrack.children(this.options.slide).detach();

            _.$slideTrack.detach();

            _.$list.detach();

            _.$slider.append(_.$slides);
        }

        _.cleanUpRows();

        _.$slider.removeClass('slick-slider');
        _.$slider.removeClass('slick-initialized');
        _.$slider.removeClass('slick-dotted');

        _.unslicked = true;

        if (!refresh) {
            _.$slider.trigger('destroy', [_]);
        }

    };

    Slick.prototype.disableTransition = function (slide) {

        var _ = this,
            transition = {};

        transition[_.transitionType] = '';

        if (_.options.fade === false) {
            _.$slideTrack.css(transition);
        } else {
            _.$slides.eq(slide).css(transition);
        }

    };

    Slick.prototype.fadeSlide = function (slideIndex, callback) {

        var _ = this;

        if (_.cssTransitions === false) {

            _.$slides.eq(slideIndex).css({
                zIndex: _.options.zIndex
            });

            _.$slides.eq(slideIndex).animate({
                opacity: 1
            }, _.options.speed, _.options.easing, callback);

        } else {

            _.applyTransition(slideIndex);

            _.$slides.eq(slideIndex).css({
                opacity: 1,
                zIndex: _.options.zIndex
            });

            if (callback) {
                setTimeout(function () {

                    _.disableTransition(slideIndex);

                    callback.call();
                }, _.options.speed);
            }

        }

    };

    Slick.prototype.fadeSlideOut = function (slideIndex) {

        var _ = this;

        if (_.cssTransitions === false) {

            _.$slides.eq(slideIndex).animate({
                opacity: 0,
                zIndex: _.options.zIndex - 2
            }, _.options.speed, _.options.easing);

        } else {

            _.applyTransition(slideIndex);

            _.$slides.eq(slideIndex).css({
                opacity: 0,
                zIndex: _.options.zIndex - 2
            });

        }

    };

    Slick.prototype.filterSlides = Slick.prototype.slickFilter = function (filter) {

        var _ = this;

        if (filter !== null) {

            _.$slidesCache = _.$slides;

            _.unload();

            _.$slideTrack.children(this.options.slide).detach();

            _.$slidesCache.filter(filter).appendTo(_.$slideTrack);

            _.reinit();

        }

    };

    Slick.prototype.focusHandler = function () {

        var _ = this;

        _.$slider
            .off('focus.slick blur.slick')
            .on('focus.slick blur.slick', '*', function (event) {

                event.stopImmediatePropagation();
                var $sf = $(this);

                setTimeout(function () {

                    if (_.options.pauseOnFocus) {
                        _.focussed = $sf.is(':focus');
                        _.autoPlay();
                    }

                }, 0);

            });
    };

    Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function () {

        var _ = this;
        return _.currentSlide;

    };

    Slick.prototype.getDotCount = function () {

        var _ = this;

        var breakPoint = 0;
        var counter = 0;
        var pagerQty = 0;

        if (_.options.infinite === true) {
            if (_.slideCount <= _.options.slidesToShow) {
                ++pagerQty;
            } else {
                while (breakPoint < _.slideCount) {
                    ++pagerQty;
                    breakPoint = counter + _.options.slidesToScroll;
                    counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
                }
            }
        } else if (_.options.centerMode === true) {
            pagerQty = _.slideCount;
        } else if (!_.options.asNavFor) {
            pagerQty = 1 + Math.ceil((_.slideCount - _.options.slidesToShow) / _.options.slidesToScroll);
        } else {
            while (breakPoint < _.slideCount) {
                ++pagerQty;
                breakPoint = counter + _.options.slidesToScroll;
                counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
            }
        }

        return pagerQty - 1;

    };

    Slick.prototype.getLeft = function (slideIndex) {

        var _ = this,
            targetLeft,
            verticalHeight,
            verticalOffset = 0,
            targetSlide,
            coef;

        _.slideOffset = 0;
        verticalHeight = _.$slides.first().outerHeight(true);

        if (_.options.infinite === true) {
            if (_.slideCount > _.options.slidesToShow) {
                _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1;
                coef = -1

                if (_.options.vertical === true && _.options.centerMode === true) {
                    if (_.options.slidesToShow === 2) {
                        coef = -1.5;
                    } else if (_.options.slidesToShow === 1) {
                        coef = -2
                    }
                }
                verticalOffset = (verticalHeight * _.options.slidesToShow) * coef;
            }
            if (_.slideCount % _.options.slidesToScroll !== 0) {
                if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) {
                    if (slideIndex > _.slideCount) {
                        _.slideOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * _.slideWidth) * -1;
                        verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1;
                    } else {
                        _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1;
                        verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1;
                    }
                }
            }
        } else {
            if (slideIndex + _.options.slidesToShow > _.slideCount) {
                _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth;
                verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight;
            }
        }

        if (_.slideCount <= _.options.slidesToShow) {
            _.slideOffset = 0;
            verticalOffset = 0;
        }

        if (_.options.centerMode === true && _.slideCount <= _.options.slidesToShow) {
            _.slideOffset = ((_.slideWidth * Math.floor(_.options.slidesToShow)) / 2) - ((_.slideWidth * _.slideCount) / 2);
        } else if (_.options.centerMode === true && _.options.infinite === true) {
            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth;
        } else if (_.options.centerMode === true) {
            _.slideOffset = 0;
            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2);
        }

        if (_.options.vertical === false) {
            targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
        } else {
            targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
        }

        if (_.options.variableWidth === true) {

            if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
            } else {
                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow);
            }

            if (_.options.rtl === true) {
                if (targetSlide[0]) {
                    targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
                } else {
                    targetLeft = 0;
                }
            } else {
                targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
            }

            if (_.options.centerMode === true) {
                if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
                } else {
                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1);
                }

                if (_.options.rtl === true) {
                    if (targetSlide[0]) {
                        targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
                    } else {
                        targetLeft = 0;
                    }
                } else {
                    targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
                }

                targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2;
            }
        }

        return targetLeft;

    };

    Slick.prototype.getOption = Slick.prototype.slickGetOption = function (option) {

        var _ = this;

        return _.options[option];

    };

    Slick.prototype.getNavigableIndexes = function () {

        var _ = this,
            breakPoint = 0,
            counter = 0,
            indexes = [],
            max;

        if (_.options.infinite === false) {
            max = _.slideCount;
        } else {
            breakPoint = _.options.slidesToScroll * -1;
            counter = _.options.slidesToScroll * -1;
            max = _.slideCount * 2;
        }

        while (breakPoint < max) {
            indexes.push(breakPoint);
            breakPoint = counter + _.options.slidesToScroll;
            counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
        }

        return indexes;

    };

    Slick.prototype.getSlick = function () {

        return this;

    };

    Slick.prototype.getSlideCount = function () {

        var _ = this,
            slidesTraversed, swipedSlide, centerOffset;

        centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0;

        if (_.options.swipeToSlide === true) {
            _.$slideTrack.find('.slick-slide').each(function (index, slide) {
                if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) {
                    swipedSlide = slide;
                    return false;
                }
            });

            slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1;

            return slidesTraversed;

        } else {
            return _.options.slidesToScroll;
        }

    };

    Slick.prototype.goTo = Slick.prototype.slickGoTo = function (slide, dontAnimate) {

        var _ = this;

        _.changeSlide({
            data: {
                message: 'index',
                index: parseInt(slide)
            }
        }, dontAnimate);

    };

    Slick.prototype.init = function (creation) {

        var _ = this;

        if (!$(_.$slider).hasClass('slick-initialized')) {

            $(_.$slider).addClass('slick-initialized');

            _.buildRows();
            _.buildOut();
            _.setProps();
            _.startLoad();
            _.loadSlider();
            _.initializeEvents();
            _.updateArrows();
            _.updateDots();
            _.checkResponsive(true);
            _.focusHandler();

        }

        if (creation) {
            _.$slider.trigger('init', [_]);
        }

        if (_.options.accessibility === true) {
            _.initADA();
        }

        if (_.options.autoplay) {

            _.paused = false;
            _.autoPlay();

        }

    };

    Slick.prototype.initADA = function () {
        var _ = this,
                numDotGroups = Math.ceil(_.slideCount / _.options.slidesToShow),
                tabControlIndexes = _.getNavigableIndexes().filter(function (val) {
                    return (val >= 0) && (val < _.slideCount);
                });

        _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({
            'aria-hidden': 'true',
            'tabindex': '-1'
        }).find('a, input, button, select').attr({
            'tabindex': '-1'
        });

        if (_.$dots !== null) {
            _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function (i) {
                var slideControlIndex = tabControlIndexes.indexOf(i);

                $(this).attr({
                    'role': 'tabpanel',
                    'id': 'slick-slide' + _.instanceUid + i,
                    'tabindex': -1
                });

                if (slideControlIndex !== -1) {
                    var ariaButtonControl = 'slick-slide-control' + _.instanceUid + slideControlIndex
                    if ($('#' + ariaButtonControl).length) {
                        $(this).attr({
                            'aria-describedby': ariaButtonControl
                        });
                    }
                }
            });

            _.$dots.attr('role', 'tablist').find('li').each(function (i) {
                var mappedSlideIndex = tabControlIndexes[i];

                $(this).attr({
                    'role': 'presentation'
                });

                $(this).find('button').first().attr({
                    'role': 'tab',
                    'id': 'slick-slide-control' + _.instanceUid + i,
                    'aria-controls': 'slick-slide' + _.instanceUid + mappedSlideIndex,
                    'aria-label': (i + 1) + ' of ' + numDotGroups,
                    'aria-selected': null,
                    'tabindex': '-1'
                });

            }).eq(_.currentSlide).find('button').attr({
                'aria-selected': 'true',
                'tabindex': '0'
            }).end();
        }

        for (var i = _.currentSlide, max = i + _.options.slidesToShow; i < max; i++) {
            if (_.options.focusOnChange) {
                _.$slides.eq(i).attr({ 'tabindex': '0' });
            } else {
                _.$slides.eq(i).removeAttr('tabindex');
            }
        }

        _.activateADA();

    };

    Slick.prototype.initArrowEvents = function () {

        var _ = this;

        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
            _.$prevArrow
               .off('click.slick')
               .on('click.slick', {
                   message: 'previous'
               }, _.changeSlide);
            _.$nextArrow
               .off('click.slick')
               .on('click.slick', {
                   message: 'next'
               }, _.changeSlide);

            if (_.options.accessibility === true) {
                _.$prevArrow.on('keydown.slick', _.keyHandler);
                _.$nextArrow.on('keydown.slick', _.keyHandler);
            }
        }

    };

    Slick.prototype.initDotEvents = function () {

        var _ = this;

        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
            $('li', _.$dots).on('click.slick', {
                message: 'index'
            }, _.changeSlide);

            if (_.options.accessibility === true) {
                _.$dots.on('keydown.slick', _.keyHandler);
            }
        }

        if (_.options.dots === true && _.options.pauseOnDotsHover === true && _.slideCount > _.options.slidesToShow) {

            $('li', _.$dots)
                .on('mouseenter.slick', $.proxy(_.interrupt, _, true))
                .on('mouseleave.slick', $.proxy(_.interrupt, _, false));

        }

    };

    Slick.prototype.initSlideEvents = function () {

        var _ = this;

        if (_.options.pauseOnHover) {

            _.$list.on('mouseenter.slick', $.proxy(_.interrupt, _, true));
            _.$list.on('mouseleave.slick', $.proxy(_.interrupt, _, false));

        }

    };

    Slick.prototype.initializeEvents = function () {

        var _ = this;

        _.initArrowEvents();

        _.initDotEvents();
        _.initSlideEvents();

        _.$list.on('touchstart.slick mousedown.slick', {
            action: 'start'
        }, _.swipeHandler);
        _.$list.on('touchmove.slick mousemove.slick', {
            action: 'move'
        }, _.swipeHandler);
        _.$list.on('touchend.slick mouseup.slick', {
            action: 'end'
        }, _.swipeHandler);
        _.$list.on('touchcancel.slick mouseleave.slick', {
            action: 'end'
        }, _.swipeHandler);

        _.$list.on('click.slick', _.clickHandler);

        $(document).on(_.visibilityChange, $.proxy(_.visibility, _));

        if (_.options.accessibility === true) {
            _.$list.on('keydown.slick', _.keyHandler);
        }

        if (_.options.focusOnSelect === true) {
            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
        }

        $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _));

        $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _));

        $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault);

        $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition);
        $(_.setPosition);

    };

    Slick.prototype.initUI = function () {

        var _ = this;

        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {

            _.$prevArrow.show();
            _.$nextArrow.show();

        }

        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {

            _.$dots.show();

        }

    };

    Slick.prototype.keyHandler = function (event) {

        var _ = this;
        //Dont slide if the cursor is inside the form fields and arrow keys are pressed
        if (!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
            if (event.keyCode === 37 && _.options.accessibility === true) {
                _.changeSlide({
                    data: {
                        message: _.options.rtl === true ? 'next' : 'previous'
                    }
                });
            } else if (event.keyCode === 39 && _.options.accessibility === true) {
                _.changeSlide({
                    data: {
                        message: _.options.rtl === true ? 'previous' : 'next'
                    }
                });
            }
        }

    };

    Slick.prototype.lazyLoad = function () {

        var _ = this,
            loadRange, cloneRange, rangeStart, rangeEnd;

        function loadImages(imagesScope) {

            $('img[data-lazy]', imagesScope).each(function () {

                var image = $(this),
                    imageSource = $(this).attr('data-lazy'),
                    imageSrcSet = $(this).attr('data-srcset'),
                    imageSizes = $(this).attr('data-sizes') || _.$slider.attr('data-sizes'),
                    imageToLoad = document.createElement('img');

                imageToLoad.onload = function () {

                    image
                        .animate({ opacity: 0 }, 100, function () {

                            if (imageSrcSet) {
                                image
                                    .attr('srcset', imageSrcSet);

                                if (imageSizes) {
                                    image
                                        .attr('sizes', imageSizes);
                                }
                            }

                            image
                                .attr('src', imageSource)
                                .animate({ opacity: 1 }, 200, function () {
                                    image
                                        .removeAttr('data-lazy data-srcset data-sizes')
                                        .removeClass('slick-loading');
                                });
                            _.$slider.trigger('lazyLoaded', [_, image, imageSource]);
                        });

                };

                imageToLoad.onerror = function () {

                    image
                        .removeAttr('data-lazy')
                        .removeClass('slick-loading')
                        .addClass('slick-lazyload-error');

                    _.$slider.trigger('lazyLoadError', [_, image, imageSource]);

                };

                imageToLoad.src = imageSource;

            });

        }

        if (_.options.centerMode === true) {
            if (_.options.infinite === true) {
                rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1);
                rangeEnd = rangeStart + _.options.slidesToShow + 2;
            } else {
                rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1));
                rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide;
            }
        } else {
            rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide;
            rangeEnd = Math.ceil(rangeStart + _.options.slidesToShow);
            if (_.options.fade === true) {
                if (rangeStart > 0) rangeStart--;
                if (rangeEnd <= _.slideCount) rangeEnd++;
            }
        }

        loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd);

        if (_.options.lazyLoad === 'anticipated') {
            var prevSlide = rangeStart - 1,
                nextSlide = rangeEnd,
                $slides = _.$slider.find('.slick-slide');

            for (var i = 0; i < _.options.slidesToScroll; i++) {
                if (prevSlide < 0) prevSlide = _.slideCount - 1;
                loadRange = loadRange.add($slides.eq(prevSlide));
                loadRange = loadRange.add($slides.eq(nextSlide));
                prevSlide--;
                nextSlide++;
            }
        }

        loadImages(loadRange);

        if (_.slideCount <= _.options.slidesToShow) {
            cloneRange = _.$slider.find('.slick-slide');
            loadImages(cloneRange);
        } else
            if (_.currentSlide >= _.slideCount - _.options.slidesToShow) {
                cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow);
                loadImages(cloneRange);
            } else if (_.currentSlide === 0) {
                cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1);
                loadImages(cloneRange);
            }

    };

    Slick.prototype.loadSlider = function () {

        var _ = this;

        _.setPosition();

        _.$slideTrack.css({
            opacity: 1
        });

        _.$slider.removeClass('slick-loading');

        _.initUI();

        if (_.options.lazyLoad === 'progressive') {
            _.progressiveLazyLoad();
        }

    };

    Slick.prototype.next = Slick.prototype.slickNext = function () {

        var _ = this;

        _.changeSlide({
            data: {
                message: 'next'
            }
        });

    };

    Slick.prototype.orientationChange = function () {

        var _ = this;

        _.checkResponsive();
        _.setPosition();

    };

    Slick.prototype.pause = Slick.prototype.slickPause = function () {

        var _ = this;

        _.autoPlayClear();
        _.paused = true;

    };

    Slick.prototype.play = Slick.prototype.slickPlay = function () {

        var _ = this;

        _.autoPlay();
        _.options.autoplay = true;
        _.paused = false;
        _.focussed = false;
        _.interrupted = false;

    };

    Slick.prototype.postSlide = function (index) {

        var _ = this;

        if (!_.unslicked) {

            _.$slider.trigger('afterChange', [_, index]);

            _.animating = false;

            if (_.slideCount > _.options.slidesToShow) {
                _.setPosition();
            }

            _.swipeLeft = null;

            if (_.options.autoplay) {
                _.autoPlay();
            }

            if (_.options.accessibility === true) {
                _.initADA();

                if (_.options.focusOnChange) {
                    var $currentSlide = $(_.$slides.get(_.currentSlide));
                    $currentSlide.attr('tabindex', 0).focus();
                }
            }

        }

    };

    Slick.prototype.prev = Slick.prototype.slickPrev = function () {

        var _ = this;

        _.changeSlide({
            data: {
                message: 'previous'
            }
        });

    };

    Slick.prototype.preventDefault = function (event) {

        event.preventDefault();

    };

    Slick.prototype.progressiveLazyLoad = function (tryCount) {

        tryCount = tryCount || 1;

        var _ = this,
            $imgsToLoad = $('img[data-lazy]', _.$slider),
            image,
            imageSource,
            imageSrcSet,
            imageSizes,
            imageToLoad;

        if ($imgsToLoad.length) {

            image = $imgsToLoad.first();
            imageSource = image.attr('data-lazy');
            imageSrcSet = image.attr('data-srcset');
            imageSizes = image.attr('data-sizes') || _.$slider.attr('data-sizes');
            imageToLoad = document.createElement('img');

            imageToLoad.onload = function () {

                if (imageSrcSet) {
                    image
                        .attr('srcset', imageSrcSet);

                    if (imageSizes) {
                        image
                            .attr('sizes', imageSizes);
                    }
                }

                image
                    .attr('src', imageSource)
                    .removeAttr('data-lazy data-srcset data-sizes')
                    .removeClass('slick-loading');

                if (_.options.adaptiveHeight === true) {
                    _.setPosition();
                }

                _.$slider.trigger('lazyLoaded', [_, image, imageSource]);
                _.progressiveLazyLoad();

            };

            imageToLoad.onerror = function () {

                if (tryCount < 3) {

                    /**
                     * try to load the image 3 times,
                     * leave a slight delay so we don't get
                     * servers blocking the request.
                     */
                    setTimeout(function () {
                        _.progressiveLazyLoad(tryCount + 1);
                    }, 500);

                } else {

                    image
                        .removeAttr('data-lazy')
                        .removeClass('slick-loading')
                        .addClass('slick-lazyload-error');

                    _.$slider.trigger('lazyLoadError', [_, image, imageSource]);

                    _.progressiveLazyLoad();

                }

            };

            imageToLoad.src = imageSource;

        } else {

            _.$slider.trigger('allImagesLoaded', [_]);

        }

    };

    Slick.prototype.refresh = function (initializing) {

        var _ = this, currentSlide, lastVisibleIndex;

        lastVisibleIndex = _.slideCount - _.options.slidesToShow;

        // in non-infinite sliders, we don't want to go past the
        // last visible index.
        if (!_.options.infinite && (_.currentSlide > lastVisibleIndex)) {
            _.currentSlide = lastVisibleIndex;
        }

        // if less slides than to show, go to start.
        if (_.slideCount <= _.options.slidesToShow) {
            _.currentSlide = 0;

        }

        currentSlide = _.currentSlide;

        _.destroy(true);

        $.extend(_, _.initials, { currentSlide: currentSlide });

        _.init();

        if (!initializing) {

            _.changeSlide({
                data: {
                    message: 'index',
                    index: currentSlide
                }
            }, false);

        }

    };

    Slick.prototype.registerBreakpoints = function () {

        var _ = this, breakpoint, currentBreakpoint, l,
            responsiveSettings = _.options.responsive || null;

        if ($.type(responsiveSettings) === 'array' && responsiveSettings.length) {

            _.respondTo = _.options.respondTo || 'window';

            for (breakpoint in responsiveSettings) {

                l = _.breakpoints.length - 1;

                if (responsiveSettings.hasOwnProperty(breakpoint)) {
                    currentBreakpoint = responsiveSettings[breakpoint].breakpoint;

                    // loop through the breakpoints and cut out any existing
                    // ones with the same breakpoint number, we don't want dupes.
                    while (l >= 0) {
                        if (_.breakpoints[l] && _.breakpoints[l] === currentBreakpoint) {
                            _.breakpoints.splice(l, 1);
                        }
                        l--;
                    }

                    _.breakpoints.push(currentBreakpoint);
                    _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings;

                }

            }

            _.breakpoints.sort(function (a, b) {
                return (_.options.mobileFirst) ? a - b : b - a;
            });

        }

    };

    Slick.prototype.reinit = function () {

        var _ = this;

        _.$slides =
            _.$slideTrack
                .children(_.options.slide)
                .addClass('slick-slide');

        _.slideCount = _.$slides.length;

        if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) {
            _.currentSlide = _.currentSlide - _.options.slidesToScroll;
        }

        if (_.slideCount <= _.options.slidesToShow) {
            _.currentSlide = 0;
        }

        _.registerBreakpoints();

        _.setProps();
        _.setupInfinite();
        _.buildArrows();
        _.updateArrows();
        _.initArrowEvents();
        _.buildDots();
        _.updateDots();
        _.initDotEvents();
        _.cleanUpSlideEvents();
        _.initSlideEvents();

        _.checkResponsive(false, true);

        if (_.options.focusOnSelect === true) {
            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
        }

        _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);

        _.setPosition();
        _.focusHandler();

        _.paused = !_.options.autoplay;
        _.autoPlay();

        _.$slider.trigger('reInit', [_]);

    };

    Slick.prototype.resize = function () {

        var _ = this;

        if ($(window).width() !== _.windowWidth) {
            clearTimeout(_.windowDelay);
            _.windowDelay = window.setTimeout(function () {
                _.windowWidth = $(window).width();
                _.checkResponsive();
                if (!_.unslicked) { _.setPosition(); }
            }, 50);
        }
    };

    Slick.prototype.removeSlide = Slick.prototype.slickRemove = function (index, removeBefore, removeAll) {

        var _ = this;

        if (typeof (index) === 'boolean') {
            removeBefore = index;
            index = removeBefore === true ? 0 : _.slideCount - 1;
        } else {
            index = removeBefore === true ? --index : index;
        }

        if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
            return false;
        }

        _.unload();

        if (removeAll === true) {
            _.$slideTrack.children().remove();
        } else {
            _.$slideTrack.children(this.options.slide).eq(index).remove();
        }

        _.$slides = _.$slideTrack.children(this.options.slide);

        _.$slideTrack.children(this.options.slide).detach();

        _.$slideTrack.append(_.$slides);

        _.$slidesCache = _.$slides;

        _.reinit();

    };

    Slick.prototype.setCSS = function (position) {

        var _ = this,
            positionProps = {},
            x, y;

        if (_.options.rtl === true) {
            position = -position;
        }
        x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px';
        y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px';

        positionProps[_.positionProp] = position;

        if (_.transformsEnabled === false) {
            _.$slideTrack.css(positionProps);
        } else {
            positionProps = {};
            if (_.cssTransitions === false) {
                positionProps[_.animType] = 'translate(' + x + ', ' + y + ')';
                _.$slideTrack.css(positionProps);
            } else {
                positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)';
                _.$slideTrack.css(positionProps);
            }
        }

    };

    Slick.prototype.setDimensions = function () {

        var _ = this;

        if (_.options.vertical === false) {
            if (_.options.centerMode === true) {
                _.$list.css({
                    padding: ('0px ' + _.options.centerPadding)
                });
            }
        } else {
            _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow);
            if (_.options.centerMode === true) {
                _.$list.css({
                    padding: (_.options.centerPadding + ' 0px')
                });
            }
        }

        _.listWidth = _.$list.width();
        _.listHeight = _.$list.height();


        if (_.options.vertical === false && _.options.variableWidth === false) {
            _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
            _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length)));

        } else if (_.options.variableWidth === true) {
            _.$slideTrack.width(5000 * _.slideCount);
        } else {
            _.slideWidth = Math.ceil(_.listWidth);
            _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length)));
        }

        var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width();
        if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset);

    };

    Slick.prototype.setFade = function () {

        var _ = this,
            targetLeft;

        _.$slides.each(function (index, element) {
            targetLeft = (_.slideWidth * index) * -1;
            if (_.options.rtl === true) {
                $(element).css({
                    position: 'relative',
                    right: targetLeft,
                    top: 0,
                    zIndex: _.options.zIndex - 2,
                    opacity: 0
                });
            } else {
                $(element).css({
                    position: 'relative',
                    left: targetLeft,
                    top: 0,
                    zIndex: _.options.zIndex - 2,
                    opacity: 0
                });
            }
        });

        _.$slides.eq(_.currentSlide).css({
            zIndex: _.options.zIndex - 1,
            opacity: 1
        });

    };

    Slick.prototype.setHeight = function () {

        var _ = this;

        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
            _.$list.css('height', targetHeight);
        }

    };

    Slick.prototype.setOption =
    Slick.prototype.slickSetOption = function () {

        /**
         * accepts arguments in format of:
         *
         *  - for changing a single option's value:
         *     .slick("setOption", option, value, refresh )
         *
         *  - for changing a set of responsive options:
         *     .slick("setOption", 'responsive', [{}, ...], refresh )
         *
         *  - for updating multiple values at once (not responsive)
         *     .slick("setOption", { 'option': value, ... }, refresh )
         */

        var _ = this, l, item, option, value, refresh = false, type;

        if ($.type(arguments[0]) === 'object') {

            option = arguments[0];
            refresh = arguments[1];
            type = 'multiple';

        } else if ($.type(arguments[0]) === 'string') {

            option = arguments[0];
            value = arguments[1];
            refresh = arguments[2];

            if (arguments[0] === 'responsive' && $.type(arguments[1]) === 'array') {

                type = 'responsive';

            } else if (typeof arguments[1] !== 'undefined') {

                type = 'single';

            }

        }

        if (type === 'single') {

            _.options[option] = value;


        } else if (type === 'multiple') {

            $.each(option, function (opt, val) {

                _.options[opt] = val;

            });


        } else if (type === 'responsive') {

            for (item in value) {

                if ($.type(_.options.responsive) !== 'array') {

                    _.options.responsive = [value[item]];

                } else {

                    l = _.options.responsive.length - 1;

                    // loop through the responsive object and splice out duplicates.
                    while (l >= 0) {

                        if (_.options.responsive[l].breakpoint === value[item].breakpoint) {

                            _.options.responsive.splice(l, 1);

                        }

                        l--;

                    }

                    _.options.responsive.push(value[item]);

                }

            }

        }

        if (refresh) {

            _.unload();
            _.reinit();

        }

    };

    Slick.prototype.setPosition = function () {

        var _ = this;

        _.setDimensions();

        _.setHeight();

        if (_.options.fade === false) {
            _.setCSS(_.getLeft(_.currentSlide));
        } else {
            _.setFade();
        }

        _.$slider.trigger('setPosition', [_]);

    };

    Slick.prototype.setProps = function () {

        var _ = this,
            bodyStyle = document.body.style;

        _.positionProp = _.options.vertical === true ? 'top' : 'left';

        if (_.positionProp === 'top') {
            _.$slider.addClass('slick-vertical');
        } else {
            _.$slider.removeClass('slick-vertical');
        }

        if (bodyStyle.WebkitTransition !== undefined ||
            bodyStyle.MozTransition !== undefined ||
            bodyStyle.msTransition !== undefined) {
            if (_.options.useCSS === true) {
                _.cssTransitions = true;
            }
        }

        if (_.options.fade) {
            if (typeof _.options.zIndex === 'number') {
                if (_.options.zIndex < 3) {
                    _.options.zIndex = 3;
                }
            } else {
                _.options.zIndex = _.defaults.zIndex;
            }
        }

        if (bodyStyle.OTransform !== undefined) {
            _.animType = 'OTransform';
            _.transformType = '-o-transform';
            _.transitionType = 'OTransition';
            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
        }
        if (bodyStyle.MozTransform !== undefined) {
            _.animType = 'MozTransform';
            _.transformType = '-moz-transform';
            _.transitionType = 'MozTransition';
            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false;
        }
        if (bodyStyle.webkitTransform !== undefined) {
            _.animType = 'webkitTransform';
            _.transformType = '-webkit-transform';
            _.transitionType = 'webkitTransition';
            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
        }
        if (bodyStyle.msTransform !== undefined) {
            _.animType = 'msTransform';
            _.transformType = '-ms-transform';
            _.transitionType = 'msTransition';
            if (bodyStyle.msTransform === undefined) _.animType = false;
        }
        if (bodyStyle.transform !== undefined && _.animType !== false) {
            _.animType = 'transform';
            _.transformType = 'transform';
            _.transitionType = 'transition';
        }
        _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false);
    };


    Slick.prototype.setSlideClasses = function (index) {

        var _ = this,
            centerOffset, allSlides, indexOffset, remainder;

        allSlides = _.$slider
            .find('.slick-slide')
            .removeClass('slick-active slick-center slick-current')
            .attr('aria-hidden', 'true');

        _.$slides
            .eq(index)
            .addClass('slick-current');

        if (_.options.centerMode === true) {

            var evenCoef = _.options.slidesToShow % 2 === 0 ? 1 : 0;

            centerOffset = Math.floor(_.options.slidesToShow / 2);

            if (_.options.infinite === true) {

                if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) {
                    _.$slides
                        .slice(index - centerOffset + evenCoef, index + centerOffset + 1)
                        .addClass('slick-active')
                        .attr('aria-hidden', 'false');

                } else {

                    indexOffset = _.options.slidesToShow + index;
                    allSlides
                        .slice(indexOffset - centerOffset + 1 + evenCoef, indexOffset + centerOffset + 2)
                        .addClass('slick-active')
                        .attr('aria-hidden', 'false');

                }

                if (index === 0) {

                    allSlides
                        .eq(allSlides.length - 1 - _.options.slidesToShow)
                        .addClass('slick-center');

                } else if (index === _.slideCount - 1) {

                    allSlides
                        .eq(_.options.slidesToShow)
                        .addClass('slick-center');

                }

            }

            _.$slides
                .eq(index)
                .addClass('slick-center');

        } else {

            if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) {

                _.$slides
                    .slice(index, index + _.options.slidesToShow)
                    .addClass('slick-active')
                    .attr('aria-hidden', 'false');

            } else if (allSlides.length <= _.options.slidesToShow) {

                allSlides
                    .addClass('slick-active')
                    .attr('aria-hidden', 'false');

            } else {

                remainder = _.slideCount % _.options.slidesToShow;
                indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index;

                if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) {

                    allSlides
                        .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder)
                        .addClass('slick-active')
                        .attr('aria-hidden', 'false');

                } else {

                    allSlides
                        .slice(indexOffset, indexOffset + _.options.slidesToShow)
                        .addClass('slick-active')
                        .attr('aria-hidden', 'false');

                }

            }

        }

        if (_.options.lazyLoad === 'ondemand' || _.options.lazyLoad === 'anticipated') {
            _.lazyLoad();
        }
    };

    Slick.prototype.setupInfinite = function () {

        var _ = this,
            i, slideIndex, infiniteCount;

        if (_.options.fade === true) {
            _.options.centerMode = false;
        }

        if (_.options.infinite === true && _.options.fade === false) {

            slideIndex = null;

            if (_.slideCount > _.options.slidesToShow) {

                if (_.options.centerMode === true) {
                    infiniteCount = _.options.slidesToShow + 1;
                } else {
                    infiniteCount = _.options.slidesToShow;
                }

                for (i = _.slideCount; i > (_.slideCount -
                        infiniteCount) ; i -= 1) {
                    slideIndex = i - 1;
                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
                        .attr('data-slick-index', slideIndex - _.slideCount)
                        .prependTo(_.$slideTrack).addClass('slick-cloned');
                }
                for (i = 0; i < infiniteCount + _.slideCount; i += 1) {
                    slideIndex = i;
                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
                        .attr('data-slick-index', slideIndex + _.slideCount)
                        .appendTo(_.$slideTrack).addClass('slick-cloned');
                }
                _.$slideTrack.find('.slick-cloned').find('[id]').each(function () {
                    $(this).attr('id', '');
                });

            }

        }

    };

    Slick.prototype.interrupt = function (toggle) {

        var _ = this;

        if (!toggle) {
            _.autoPlay();
        }
        _.interrupted = toggle;

    };

    Slick.prototype.selectHandler = function (event) {

        var _ = this;

        var targetElement =
            $(event.target).is('.slick-slide') ?
                $(event.target) :
                $(event.target).parents('.slick-slide');

        var index = parseInt(targetElement.attr('data-slick-index'));

        if (!index) index = 0;

        if (_.slideCount <= _.options.slidesToShow) {

            _.slideHandler(index, false, true);
            return;

        }

        _.slideHandler(index);

    };

    Slick.prototype.slideHandler = function (index, sync, dontAnimate) {

        var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null,
            _ = this, navTarget;

        sync = sync || false;

        if (_.animating === true && _.options.waitForAnimate === true) {
            return;
        }

        if (_.options.fade === true && _.currentSlide === index) {
            return;
        }

        if (sync === false) {
            _.asNavFor(index);
        }

        targetSlide = index;
        targetLeft = _.getLeft(targetSlide);
        slideLeft = _.getLeft(_.currentSlide);

        _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft;

        if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) {
            if (_.options.fade === false) {
                targetSlide = _.currentSlide;
                if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
                    _.animateSlide(slideLeft, function () {
                        _.postSlide(targetSlide);
                    });
                } else {
                    _.postSlide(targetSlide);
                }
            }
            return;
        } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) {
            if (_.options.fade === false) {
                targetSlide = _.currentSlide;
                if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
                    _.animateSlide(slideLeft, function () {
                        _.postSlide(targetSlide);
                    });
                } else {
                    _.postSlide(targetSlide);
                }
            }
            return;
        }

        if (_.options.autoplay) {
            clearInterval(_.autoPlayTimer);
        }

        if (targetSlide < 0) {
            if (_.slideCount % _.options.slidesToScroll !== 0) {
                animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll);
            } else {
                animSlide = _.slideCount + targetSlide;
            }
        } else if (targetSlide >= _.slideCount) {
            if (_.slideCount % _.options.slidesToScroll !== 0) {
                animSlide = 0;
            } else {
                animSlide = targetSlide - _.slideCount;
            }
        } else {
            animSlide = targetSlide;
        }

        _.animating = true;

        _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]);

        oldSlide = _.currentSlide;
        _.currentSlide = animSlide;

        _.setSlideClasses(_.currentSlide);

        if (_.options.asNavFor) {

            navTarget = _.getNavTarget();
            navTarget = navTarget.slick('getSlick');

            if (navTarget.slideCount <= navTarget.options.slidesToShow) {
                navTarget.setSlideClasses(_.currentSlide);
            }

        }

        _.updateDots();
        _.updateArrows();

        if (_.options.fade === true) {
            if (dontAnimate !== true) {

                _.fadeSlideOut(oldSlide);

                _.fadeSlide(animSlide, function () {
                    _.postSlide(animSlide);
                });

            } else {
                _.postSlide(animSlide);
            }
            _.animateHeight();
            return;
        }

        if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
            _.animateSlide(targetLeft, function () {
                _.postSlide(animSlide);
            });
        } else {
            _.postSlide(animSlide);
        }

    };

    Slick.prototype.startLoad = function () {

        var _ = this;

        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {

            _.$prevArrow.hide();
            _.$nextArrow.hide();

        }

        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {

            _.$dots.hide();

        }

        _.$slider.addClass('slick-loading');

    };

    Slick.prototype.swipeDirection = function () {

        var xDist, yDist, r, swipeAngle, _ = this;

        xDist = _.touchObject.startX - _.touchObject.curX;
        yDist = _.touchObject.startY - _.touchObject.curY;
        r = Math.atan2(yDist, xDist);

        swipeAngle = Math.round(r * 180 / Math.PI);
        if (swipeAngle < 0) {
            swipeAngle = 360 - Math.abs(swipeAngle);
        }

        if ((swipeAngle <= 45) && (swipeAngle >= 0)) {
            return (_.options.rtl === false ? 'left' : 'right');
        }
        if ((swipeAngle <= 360) && (swipeAngle >= 315)) {
            return (_.options.rtl === false ? 'left' : 'right');
        }
        if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
            return (_.options.rtl === false ? 'right' : 'left');
        }
        if (_.options.verticalSwiping === true) {
            if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
                return 'down';
            } else {
                return 'up';
            }
        }

        return 'vertical';

    };

    Slick.prototype.swipeEnd = function (event) {

        var _ = this,
            slideCount,
            direction;

        _.dragging = false;
        _.swiping = false;

        if (_.scrolling) {
            _.scrolling = false;
            return false;
        }

        _.interrupted = false;
        _.shouldClick = (_.touchObject.swipeLength > 10) ? false : true;

        if (_.touchObject.curX === undefined) {
            return false;
        }

        if (_.touchObject.edgeHit === true) {
            _.$slider.trigger('edge', [_, _.swipeDirection()]);
        }

        if (_.touchObject.swipeLength >= _.touchObject.minSwipe) {

            direction = _.swipeDirection();

            switch (direction) {

                case 'left':
                case 'down':

                    slideCount =
                        _.options.swipeToSlide ?
                            _.checkNavigable(_.currentSlide + _.getSlideCount()) :
                            _.currentSlide + _.getSlideCount();

                    _.currentDirection = 0;

                    break;

                case 'right':
                case 'up':

                    slideCount =
                        _.options.swipeToSlide ?
                            _.checkNavigable(_.currentSlide - _.getSlideCount()) :
                            _.currentSlide - _.getSlideCount();

                    _.currentDirection = 1;

                    break;

                default:


            }

            if (direction != 'vertical') {

                _.slideHandler(slideCount);
                _.touchObject = {};
                _.$slider.trigger('swipe', [_, direction]);

            }

        } else {

            if (_.touchObject.startX !== _.touchObject.curX) {

                _.slideHandler(_.currentSlide);
                _.touchObject = {};

            }

        }

    };

    Slick.prototype.swipeHandler = function (event) {

        var _ = this;

        if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) {
            return;
        } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) {
            return;
        }

        _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
            event.originalEvent.touches.length : 1;

        _.touchObject.minSwipe = _.listWidth / _.options
            .touchThreshold;

        if (_.options.verticalSwiping === true) {
            _.touchObject.minSwipe = _.listHeight / _.options
                .touchThreshold;
        }

        switch (event.data.action) {

            case 'start':
                _.swipeStart(event);
                break;

            case 'move':
                _.swipeMove(event);
                break;

            case 'end':
                _.swipeEnd(event);
                break;

        }

    };

    Slick.prototype.swipeMove = function (event) {

        var _ = this,
            edgeWasHit = false,
            curLeft, swipeDirection, swipeLength, positionOffset, touches, verticalSwipeLength;

        touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;

        if (!_.dragging || _.scrolling || touches && touches.length !== 1) {
            return false;
        }

        curLeft = _.getLeft(_.currentSlide);

        _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
        _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;

        _.touchObject.swipeLength = Math.round(Math.sqrt(
            Math.pow(_.touchObject.curX - _.touchObject.startX, 2)));

        verticalSwipeLength = Math.round(Math.sqrt(
            Math.pow(_.touchObject.curY - _.touchObject.startY, 2)));

        if (!_.options.verticalSwiping && !_.swiping && verticalSwipeLength > 4) {
            _.scrolling = true;
            return false;
        }

        if (_.options.verticalSwiping === true) {
            _.touchObject.swipeLength = verticalSwipeLength;
        }

        swipeDirection = _.swipeDirection();

        if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) {
            _.swiping = true;
            event.preventDefault();
        }

        positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1);
        if (_.options.verticalSwiping === true) {
            positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1;
        }


        swipeLength = _.touchObject.swipeLength;

        _.touchObject.edgeHit = false;

        if (_.options.infinite === false) {
            if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) {
                swipeLength = _.touchObject.swipeLength * _.options.edgeFriction;
                _.touchObject.edgeHit = true;
            }
        }

        if (_.options.vertical === false) {
            _.swipeLeft = curLeft + swipeLength * positionOffset;
        } else {
            _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset;
        }
        if (_.options.verticalSwiping === true) {
            _.swipeLeft = curLeft + swipeLength * positionOffset;
        }

        if (_.options.fade === true || _.options.touchMove === false) {
            return false;
        }

        if (_.animating === true) {
            _.swipeLeft = null;
            return false;
        }

        _.setCSS(_.swipeLeft);

    };

    Slick.prototype.swipeStart = function (event) {

        var _ = this,
            touches;

        _.interrupted = true;

        if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) {
            _.touchObject = {};
            return false;
        }

        if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) {
            touches = event.originalEvent.touches[0];
        }

        _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX;
        _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY;

        _.dragging = true;

    };

    Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function () {

        var _ = this;

        if (_.$slidesCache !== null) {

            _.unload();

            _.$slideTrack.children(this.options.slide).detach();

            _.$slidesCache.appendTo(_.$slideTrack);

            _.reinit();

        }

    };

    Slick.prototype.unload = function () {

        var _ = this;

        $('.slick-cloned', _.$slider).remove();

        if (_.$dots) {
            _.$dots.remove();
        }

        if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) {
            _.$prevArrow.remove();
        }

        if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) {
            _.$nextArrow.remove();
        }

        _.$slides
            .removeClass('slick-slide slick-active slick-visible slick-current')
            .attr('aria-hidden', 'true')
            .css('width', '');

    };

    Slick.prototype.unslick = function (fromBreakpoint) {

        var _ = this;
        _.$slider.trigger('unslick', [_, fromBreakpoint]);
        _.destroy();

    };

    Slick.prototype.updateArrows = function () {

        var _ = this,
            centerOffset;

        centerOffset = Math.floor(_.options.slidesToShow / 2);

        if (_.options.arrows === true &&
            _.slideCount > _.options.slidesToShow &&
            !_.options.infinite) {

            _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
            _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');

            if (_.currentSlide === 0) {

                _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
                _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');

            } else if (_.currentSlide >= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) {

                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');

            } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) {

                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');

            }

        }

    };

    Slick.prototype.updateDots = function () {

        var _ = this;

        if (_.$dots !== null) {

            _.$dots
                .find('li')
                    .removeClass('slick-active')
                    .end();

            _.$dots
                .find('li')
                .eq(Math.floor(_.currentSlide / _.options.slidesToScroll))
                .addClass('slick-active');

        }

    };

    Slick.prototype.visibility = function () {

        var _ = this;

        if (_.options.autoplay) {

            if (document[_.hidden]) {

                _.interrupted = true;

            } else {

                _.interrupted = false;

            }

        }

    };

    $.fn.slick = function () {
        var _ = this,
            opt = arguments[0],
            args = Array.prototype.slice.call(arguments, 1),
            l = _.length,
            i,
            ret;
        for (i = 0; i < l; i++) {
            if (typeof opt == 'object' || typeof opt == 'undefined')
                _[i].slick = new Slick(_[i], opt);
            else
                ret = _[i].slick[opt].apply(_[i].slick, args);
            if (typeof ret != 'undefined') return ret;
        }
        return _;
    };

})(jQuery);;
/*!
 * imagesLoaded PACKAGED v4.1.0
 * JavaScript is all like "You images are done yet or what?"
 * MIT License
 */

/**
 * EvEmitter v1.0.1
 * Lil' event emitter
 * MIT License
 */

/* jshint unused: true, undef: true, strict: true */

(function (global, factory) {
  // universal module definition
    // Browser globals
    global.EvEmitter = factory();
}(this, function () {



  function EvEmitter() { }

  var proto = EvEmitter.prototype;

  proto.on = function (eventName, listener) {
    if (!eventName || !listener) {
      return;
    }
    // set events hash
    var events = this._events = this._events || {};
    // set listeners array
    var listeners = events[eventName] = events[eventName] || [];
    // only add once
    if (listeners.indexOf(listener) == -1) {
      listeners.push(listener);
    }

    return this;
  };

  proto.once = function (eventName, listener) {
    if (!eventName || !listener) {
      return;
    }
    // add event
    this.on(eventName, listener);
    // set once flag
    // set onceEvents hash
    var onceEvents = this._onceEvents = this._onceEvents || {};
    // set onceListeners array
    var onceListeners = onceEvents[eventName] = onceEvents[eventName] || [];
    // set flag
    onceListeners[listener] = true;

    return this;
  };

  proto.off = function (eventName, listener) {
    var listeners = this._events && this._events[eventName];
    if (!listeners || !listeners.length) {
      return;
    }
    var index = listeners.indexOf(listener);
    if (index != -1) {
      listeners.splice(index, 1);
    }

    return this;
  };

  proto.emitEvent = function (eventName, args) {
    var listeners = this._events && this._events[eventName];
    if (!listeners || !listeners.length) {
      return;
    }
    var i = 0;
    var listener = listeners[i];
    args = args || [];
    // once stuff
    var onceListeners = this._onceEvents && this._onceEvents[eventName];

    while (listener) {
      var isOnce = onceListeners && onceListeners[listener];
      if (isOnce) {
        // remove listener
        // remove before trigger to prevent recursion
        this.off(eventName, listener);
        // unset once flag
        delete onceListeners[listener];
      }
      // trigger listener
      listener.apply(this, args);
      // get next listener
      i += isOnce ? 0 : 1;
      listener = listeners[i];
    }

    return this;
  };

  return EvEmitter;

}));

/*!
 * imagesLoaded v4.1.0
 * JavaScript is all like "You images are done yet or what?"
 * MIT License
 */

(function (window, factory) {
  'use strict';
  // universal module definition

    // browser global
    window.imagesLoaded = factory(
      window,
      window.EvEmitter
    );


})(window,

// --------------------------  factory -------------------------- //

function factory(window, EvEmitter) {



  var $ = window.jQuery;
  var console = window.console;

  // -------------------------- helpers -------------------------- //

  // extend objects
  function extend(a, b) {
    for (var prop in b) {
      a[prop] = b[prop];
    }
    return a;
  }

  // turn element or nodeList into an array
  function makeArray(obj) {
    var ary = [];
    if (Array.isArray(obj)) {
      // use object if already an array
      ary = obj;
    } else if (typeof obj.length == 'number') {
      // convert nodeList to array
      for (var i = 0; i < obj.length; i++) {
        ary.push(obj[i]);
      }
    } else {
      // array of single index
      ary.push(obj);
    }
    return ary;
  }

  // -------------------------- imagesLoaded -------------------------- //

  /**
   * @param {Array, Element, NodeList, String} elem
   * @param {Object or Function} options - if function, use as callback
   * @param {Function} onAlways - callback function
   */
  function ImagesLoaded(elem, options, onAlways) {
    // coerce ImagesLoaded() without new, to be new ImagesLoaded()
    if (!(this instanceof ImagesLoaded)) {
      return new ImagesLoaded(elem, options, onAlways);
    }
    // use elem as selector string
    if (typeof elem == 'string') {
      elem = document.querySelectorAll(elem);
    }

    this.elements = makeArray(elem);
    this.options = extend({}, this.options);

    if (typeof options == 'function') {
      onAlways = options;
    } else {
      extend(this.options, options);
    }

    if (onAlways) {
      this.on('always', onAlways);
    }

    this.getImages();

    if ($) {
      // add jQuery Deferred object
      this.jqDeferred = new $.Deferred();
    }

    // HACK check async to allow time to bind listeners
    setTimeout(function () {
      this.check();
    }.bind(this));
  }

  ImagesLoaded.prototype = Object.create(EvEmitter.prototype);

  ImagesLoaded.prototype.options = {};

  ImagesLoaded.prototype.getImages = function () {
    this.images = [];

    // filter & find items if we have an item selector
    this.elements.forEach(this.addElementImages, this);
  };

  /**
   * @param {Node} element
   */
  ImagesLoaded.prototype.addElementImages = function (elem) {
    // filter siblings
    if (elem.nodeName == 'IMG') {
      this.addImage(elem);
    }
    // get background image on element
    if (this.options.background === true) {
      this.addElementBackgroundImages(elem);
    }

    // find children
    // no non-element nodes, #143
    var nodeType = elem.nodeType;
    if (!nodeType || !elementNodeTypes[nodeType]) {
      return;
    }
    var childImgs = elem.querySelectorAll('img');
    // concat childElems to filterFound array
    for (var i = 0; i < childImgs.length; i++) {
      var img = childImgs[i];
      this.addImage(img);
    }

    // get child background images
    if (typeof this.options.background == 'string') {
      var children = elem.querySelectorAll(this.options.background);
      for (i = 0; i < children.length; i++) {
        var child = children[i];
        this.addElementBackgroundImages(child);
      }
    }
  };

  var elementNodeTypes = {
    1: true,
    9: true,
    11: true
  };

  ImagesLoaded.prototype.addElementBackgroundImages = function (elem) {
    var style = getComputedStyle(elem);
    if (!style) {
      // Firefox returns null if in a hidden iframe https://bugzil.la/548397
      return;
    }
    // get url inside url("...")
    var reURL = /url\((['"])?(.*?)\1\)/gi;
    var matches = reURL.exec(style.backgroundImage);
    while (matches !== null) {
      var url = matches && matches[2];
      if (url) {
        this.addBackground(url, elem);
      }
      matches = reURL.exec(style.backgroundImage);
    }
  };

  /**
   * @param {Image} img
   */
  ImagesLoaded.prototype.addImage = function (img) {
    var loadingImage = new LoadingImage(img);
    this.images.push(loadingImage);
  };

  ImagesLoaded.prototype.addBackground = function (url, elem) {
    var background = new Background(url, elem);
    this.images.push(background);
  };

  ImagesLoaded.prototype.check = function () {
    var _this = this;
    this.progressedCount = 0;
    this.hasAnyBroken = false;
    // complete if no images
    if (!this.images.length) {
      this.complete();
      return;
    }

    function onProgress(image, elem, message) {
      // HACK - Chrome triggers event before object properties have changed. #83
      setTimeout(function () {
        _this.progress(image, elem, message);
      });
    }

    this.images.forEach(function (loadingImage) {
      loadingImage.once('progress', onProgress);
      loadingImage.check();
    });
  };

  ImagesLoaded.prototype.progress = function (image, elem, message) {
    this.progressedCount++;
    this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
    // progress event
    this.emitEvent('progress', [this, image, elem]);
    if (this.jqDeferred && this.jqDeferred.notify) {
      this.jqDeferred.notify(this, image);
    }
    // check if completed
    if (this.progressedCount == this.images.length) {
      this.complete();
    }

    if (this.options.debug && console) {
      console.log('progress: ' + message, image, elem);
    }
  };

  ImagesLoaded.prototype.complete = function () {
    var eventName = this.hasAnyBroken ? 'fail' : 'done';
    this.isComplete = true;
    this.emitEvent(eventName, [this]);
    this.emitEvent('always', [this]);
    if (this.jqDeferred) {
      var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
      this.jqDeferred[jqMethod](this);
    }
  };

  // --------------------------  -------------------------- //

  function LoadingImage(img) {
    this.img = img;
  }

  LoadingImage.prototype = Object.create(EvEmitter.prototype);

  LoadingImage.prototype.check = function () {
    // If complete is true and browser supports natural sizes,
    // try to check for image status manually.
    var isComplete = this.getIsImageComplete();
    if (isComplete) {
      // report based on naturalWidth
      this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
      return;
    }

    // If none of the checks above matched, simulate loading on detached element.
    this.proxyImage = new Image();
    this.proxyImage.addEventListener('load', this);
    this.proxyImage.addEventListener('error', this);
    // bind to image as well for Firefox. #191
    this.img.addEventListener('load', this);
    this.img.addEventListener('error', this);
    this.proxyImage.src = this.img.src;
  };

  LoadingImage.prototype.getIsImageComplete = function () {
    return this.img.complete && this.img.naturalWidth !== undefined;
  };

  LoadingImage.prototype.confirm = function (isLoaded, message) {
    this.isLoaded = isLoaded;
    this.emitEvent('progress', [this, this.img, message]);
  };

  // ----- events ----- //

  // trigger specified handler for event type
  LoadingImage.prototype.handleEvent = function (event) {
    var method = 'on' + event.type;
    if (this[method]) {
      this[method](event);
    }
  };

  LoadingImage.prototype.onload = function () {
    this.confirm(true, 'onload');
    this.unbindEvents();
  };

  LoadingImage.prototype.onerror = function () {
    this.confirm(false, 'onerror');
    this.unbindEvents();
  };

  LoadingImage.prototype.unbindEvents = function () {
    this.proxyImage.removeEventListener('load', this);
    this.proxyImage.removeEventListener('error', this);
    this.img.removeEventListener('load', this);
    this.img.removeEventListener('error', this);
  };

  // -------------------------- Background -------------------------- //

  function Background(url, element) {
    this.url = url;
    this.element = element;
    this.img = new Image();
  }

  // inherit LoadingImage prototype
  Background.prototype = Object.create(LoadingImage.prototype);

  Background.prototype.check = function () {
    this.img.addEventListener('load', this);
    this.img.addEventListener('error', this);
    this.img.src = this.url;
    // check if image is already complete
    var isComplete = this.getIsImageComplete();
    if (isComplete) {
      this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
      this.unbindEvents();
    }
  };

  Background.prototype.unbindEvents = function () {
    this.img.removeEventListener('load', this);
    this.img.removeEventListener('error', this);
  };

  Background.prototype.confirm = function (isLoaded, message) {
    this.isLoaded = isLoaded;
    this.emitEvent('progress', [this, this.element, message]);
  };

  // -------------------------- jQuery -------------------------- //

  ImagesLoaded.makeJQueryPlugin = function (jQuery) {
    jQuery = jQuery || window.jQuery;
    if (!jQuery) {
      return;
    }
    // set local variable
    $ = jQuery;
    // $().imagesLoaded()
    $.fn.imagesLoaded = function (options, callback) {
      var instance = new ImagesLoaded(this, options, callback);
      return instance.jqDeferred.promise($(this));
    };
  };
  // try making plugin
  ImagesLoaded.makeJQueryPlugin();

  // --------------------------  -------------------------- //

  return ImagesLoaded;

});
;
(function ($) {
    $(document).ready(function () {
        var accordionElement = $('.accordion-item__head');

        if (accordionElement.length === 0) {
            return;
        }

        accordionElement.on("click", function () {
            accordionElement.not(this).attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
        });
    });
})(jQuery);;
(function ($) {
  // hero ads handled in slider.js

  // check we have adPlacement data
  //if (typeof adPlacement === 'undefined') {
  //  return;
  //}

    var clientWidth =  document.documentElement.clientWidth,
        isMobile = clientWidth < 768,
        isTablet = clientWidth > 767 && clientWidth < 980,
        isDesktop = clientWidth > 919,
        adverts = {},
        template = '<div class="adCol"><a href="{{link}}"><img src="{{url}}" alt="{{alt}}"></a></div>',
        multipleTemplate = '<div class="gridCol-l-4 gridCol-m-4 gridCol-s-12"><a href="{{link}}"><img src="{{url}}" alt="{{alt}}"></a></div></div>',
        multipleAdvertSection = '',
        multiplaAdPlacement = false;

    adverts.adLeaderboardLarge = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };

    adverts.adLeaderboardSmall = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };

    adverts.adShowtimesInfoMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesInfoMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesInfoMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesInfoMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesInfoMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adShowtimesInfoMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatresMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatresMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatresMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMovieInfoMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMovieInfoMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMovieInfoMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMoviesMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMoviesMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adMoviesMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatreInfoMPU1 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatreInfoMPU2 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatreInfoMPU3 = function (data) {
        multipleAdvertSection += Mustache.render(multipleTemplate, data);
        if (!multiplaAdPlacement) {
            multiplaAdPlacement = data.placement;
        }
    };

    adverts.adTheatreInfoBanner = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn').addClass('gridRow adRow');
    };

    adverts.adHomePromo = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn').addClass('gridRow adRow');
    };

    adverts.adHomeTakeover = function (data) {

        var $ad = $('[data-ad*="' + data.placement + '"]'),
            prompt = docCookies.getItem('PCC.HomeTakeover') || false,
            $adImage,
            takeoverTemplate = '<div class="adHomeTakeoverCell"><div class="adHomeTakeoverImg"><a href="{{link}}"><img src="{{url}}" alt="{{alt}}"></a><div class="adHomeTakeoverClose"><span class="far fa-times-circle"></span></div></div></div>';

        $('<img/>').attr('src', data.url).on('load', function () {  

            if (!prompt) {
                pc.disableScroll()
                $ad.html(Mustache.render(takeoverTemplate, data)).removeClass('dn');
                docCookies.setItem('PCC.HomeTakeover', '1', 'infinity'); 
            }

            $('.adHomeTakeoverClose').click(function () {
                pc.enableScroll()
                $ad.html('').addClass('dn');
            });

        });

    };

    adverts.adMPU = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };

    adverts.adInsider1 = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };

    adverts.adInsider2 = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };

    adverts.adInsiderHero = function (data) {
        $('[data-ad*="' + data.placement + '"]').html(Mustache.render(template, data)).removeClass('dn');
    };


    adverts.setup = function () {
        // loop adPlacement data
        for (var a = 0, aLen = adPlacement.length; a < aLen; a++) {
            
            // check placement is an image and placement function exists
            if (adPlacement[a]['type'] === 'image' && typeof adverts[adPlacement[a]['placement']] !== 'undefined') {
                // call placement function
                adverts[adPlacement[a]['placement']](adPlacement[a]);
            }

        }

        if (multiplaAdPlacement) {
            $('[data-ad*="' + multiplaAdPlacement + '"]').html(multipleAdvertSection).removeClass('dn').addClass('gridRow adContainer');
        }
    };


  var $adScripts = $('[data-ad-script]');

  if ($adScripts.length > 0) {
      var $filtered,
          adScriptsLen = 0,
          adCounter = 0,
          size;

      if (isMobile) {
          $filtered = $adScripts.filter('[data-ad-script*="s"]');
      }
      else if (isTablet) {
          $filtered = $adScripts.filter('[data-ad-script*="m"]');
      }
      else if (isDesktop) {
          $filtered = $adScripts.filter('[data-ad-script*="l"]');
      }

      if (typeof $filtered !== 'undefined') {
          adScriptsLen = $filtered.length;
      }

      function adScriptLoaded() {
          adCounter++

          if (adCounter === adScriptsLen) {

              if (typeof adPlacement !== 'undefined') {
                  adverts.setup();
              }

              if (typeof pc !== 'undefined' && typeof pc.sliderSetup !== 'undefined') {
                  pc.sliderSetup();
              }
          }
      }

      if (adScriptsLen > 0) {
          
          $filtered.each(function () {
              var $script = $(this),
                  scriptType = $script.attr('data-ad-script');
              if (
                (isMobile && scriptType.indexOf('s') > -1)
                || (isTablet && scriptType.indexOf('m') > -1)
                || (isDesktop && scriptType.indexOf('l') > -1)
              ) {
                  this.onload = adScriptLoaded;
                  this.src = $(this).attr('data-ad-src');
              }
          });
      }

  }
  else if (typeof adPlacement !== 'undefined') {
      
      adverts.setup();

      if (typeof pc !== 'undefined' && typeof pc.sliderSetup !== 'undefined') {
          pc.sliderSetup();
      }
  }
  else {
      if (typeof pc !== 'undefined' && typeof pc.sliderSetup !== 'undefined') {
          pc.sliderSetup();
      }
  }

})(jQuery);

// admanager tracking
var pc = pc || {};

(function () {

    pc.admanagerTrack = function (amount, ref) {
        // amount = decimal grand total without currency symbol eg 12.39
        // ref = unique order ref

        if (adm_cookies()) {
            if (adm_GetCookie("adm_source") != null && adm_GetCookie("adm_source") != "" && adm_GetCookie("adm_source") == "admanager") {
                var adm_trackingurl = pc.api.admanager + 'Conversion.aspx?adm_source=' + adm_GetCookie("adm_source") + '&adm_b=' + adm_GetCookie("adm_b") + '&adm_amount=' + amount + '&adm_ref=' + ref + '&adm_c=' + adm_GetCookie("adm_c");

                var adm_script = document.createElement('script');

                adm_script.setAttribute('src', adm_trackingurl);

                document.body.appendChild(adm_script);

                adm_DeleteCookie("adm_source");
                adm_DeleteCookie("adm_b");
                adm_DeleteCookie("adm_c");
            }
        }
    };

    function adm_SetCookie(name, value, exp_y, exp_m, exp_d, path, domain, secure) {
        var cookie_string = name + "=" + escape(value);

        if (exp_y) {
            var expires = new Date(exp_y, exp_m, exp_d);
            cookie_string += "; expires=" + expires.toGMTString();
        }

        if (path)
            cookie_string += "; path=" + escape(path);

        if (domain)
            cookie_string += "; domain=" + escape(domain);

        cookie_string += "; secure";

        cookie_string += "; SameSite=Lax";

        document.cookie = cookie_string;
    }

    function adm_DeleteCookie(name) {
        adm_SetCookie(name, "", 1970, 0, 1, "/", null);
    }

    function adm_ParseQuery() {
        var query = window.location.search.substring(1);
        var pairs = query.split("&");
        for (var i = 0; i < pairs.length; i++) {
            var pos = pairs[i].indexOf('=');
            if (pos >= 0) {
                var argname = pairs[i].substring(0, pos);
                var value = pairs[i].substring(pos + 1);
                adm_keys[adm_keys.length] = argname;
                adm_values[adm_values.length] = value;
            }
        }
    }

    function adm_cookies() {
        document.cookie = "adm_test=1; secure; SameSite=Lax";
        return document.cookie.indexOf("adm_test") > -1
    }

    function adm_GetCookie(cookie_name) {
        var results = document.cookie.match('(^|;) ?' + cookie_name + '=([^;]*)(;|$)');

        if (results)
            return (unescape(results[2]));
        else
            return null;
    }

    function adm_Query(key) {
        var value = null;
        for (var i = 0; i < adm_keys.length; i++) {
            if (adm_keys[i] == key) {
                value = adm_values[i];
                break;
            }
        }
        return value;
    }

    var adm_keys = new Array();
    var adm_values = new Array();

    function InitTracking(domain) {
        if (adm_cookies()) {

            adm_ParseQuery();
            if (adm_Query("adm_source") == "admanager") {
                var today = new Date();
                today.setDate(today.getDate() + 30);
                var y = today.getFullYear();
                var m = today.getMonth();
                var d = today.getDay();
                if (adm_Query("adm_source") != null || adm_Query("adm_source") != "") adm_SetCookie("adm_source", adm_Query("adm_source"), y, m, d, "/", domain);
                if (adm_Query("adm_b") != null || adm_Query("adm_b") != "") adm_SetCookie("adm_b", adm_Query("adm_b"), y, m, d, "/", domain);
                if (adm_Query("adm_c") != null || adm_Query("adm_c") != "") adm_SetCookie("adm_c", adm_Query("adm_c"), y, m, d, "/", domain);
                //if (adm_Query("adm_d") != null || adm_Query("adm_d") != "") adm_SetCookie ( "adm_d", adm_Query("adm_d"), y, m, d, "/", domain );
            }

        }

    }

    InitTracking(null);

})(jQuery);

// /admanager tracking;

var pc = pc || {};

(function ($) {
    pc.clientWidth = pc.clientWidth || document.documentElement.clientWidth;
    pc.clientHeight = pc.clientHeight || document.documentElement.clientHeight;

    $(window).on('resize', function () {
        pc.clientWidth = document.documentElement.clientWidth;
        pc.clientHeight = document.documentElement.clientHeight;
    });
})(jQuery);

(function ($) {
    pc.labels = pc.labels || {};

    pc.labels = $.extend(pc.labels, {
        dayShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
        dayFull: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
        monthShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
        monthFull: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        ordinal: function (d) {
            if (d > 3 && d < 21) return 'th';
            switch (d % 10) {
                case 1: return "st";
                case 2: return "nd";
                case 3: return "rd";
                default: return "th";
            }
        }
    });
})(jQuery);

(function ($) {
    var scrollDiv = document.createElement('div');
    var style = document.createElement('style');
    var scrollbarWidth;

    scrollDiv.className = 'scrollbarMeasure';
    document.body.appendChild(scrollDiv);
    scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
    document.body.removeChild(scrollDiv);

    style.appendChild(document.createTextNode(''));
    document.head.appendChild(style);

    if (scrollbarWidth > 0) {
        style.sheet.insertRule('.noScroll{overflow:hidden;height:100%;padding-right:' + scrollbarWidth + 'px;}', 0);
        style.sheet.insertRule('.spaceRight{right:' + scrollbarWidth + 'px;}', 1);
    }

    pc.scrollDisabled = false;

    //pc.disableScroll = function () {
    //    $('body').addClass('noScroll');
    //    $('.adTakeover, [data-header]').addClass('noTransition').addClass('spaceRight');

    //    pc.scrollDisabled = true;
    //};

    pc.disableScroll = function () {
        // Get the top vertical offset.
        var topVerticalOffset = (typeof window.pageYOffset != 'undefined') ?
            window.pageYOffset : (document.documentElement.scrollTop ?
                document.documentElement.scrollTop : 0);
        // Set the document to fixed position (this is the only way around IOS' overscroll "feature").
        document.documentElement.style.zIndex = '0';
        document.documentElement.style.width = '100%';
        document.documentElement.style.position = 'fixed';
        // Set back the offset position by user negative margin on the fixed document.
        document.documentElement.style.marginTop = '-' + topVerticalOffset + 'px';

        $('body').addClass('noScroll');
        $('.adTakeover, [data-header]').addClass('noTransition').addClass('spaceRight');

        pc.scrollDisabled = true;
    };

    pc.enableScroll = function () {
        // Remove the fixed position on the document.
        document.documentElement.style.position = '';
        document.documentElement.style.width = '';
        document.documentElement.style.zIndex = '';
        //// Calculate back the original position of the non-fixed document.
        var scrollPosition = -1 * parseFloat(document.documentElement.style.marginTop);
        //// Remove fixed document negative margin.
        document.documentElement.style.marginTop = '';
        //// Scroll to the original position of the non-fixed document.
        window.scrollTo(0, scrollPosition);

        $('body').removeClass('noScroll');
        $('.adTakeover, [data-header]').removeClass('spaceRight');
        //Once the QB transition has ended move the noTransition class
        setTimeout(function () {
            $('.adTakeover, [data-header]').removeClass('noTransition');
        }, 100)
        pc.scrollDisabled = false;
    };

    pc.enableScrollFromTop = function () {
        // Remove the fixed position on the document.
        document.documentElement.style.position = '';
        document.documentElement.style.width = '';
        document.documentElement.style.zIndex = '';
        //// Calculate back the original position of the non-fixed document.
        //var scrollPosition = -1 * parseFloat(document.documentElement.style.marginTop);
        //// Remove fixed document negative margin.
        document.documentElement.style.marginTop = '';
        //// Scroll to the original position of the non-fixed document.
        //window.scrollTo(0, scrollPosition);

        $('body').removeClass('noScroll');
        $('.adTakeover, [data-header]').removeClass('spaceRight');
        //Once the QB transition has ended move the noTransition class
        setTimeout(function () {
            $('.adTakeover, [data-header]').removeClass('noTransition');
        }, 100)
        pc.scrollDisabled = false;
    };

})(jQuery);

(function ($) {
    $(document).on('click', '.session-link', function () {
        $(this).addClass('active');
    });
})(jQuery);

function convertTo24Hour(time) {
    var hours = parseInt(time.substr(0, 2));
    if (time.indexOf('AM') != -1 && hours == 12) {
        time = time.replace('12', '0');
    }
    if (time.indexOf('PM') != -1 && hours < 12) {
        time = time.replace(hours, (hours + 12));
    }
    return time.replace(/( AM| PM)/, '');
}

(function ($) {
    var header = $(".header");

    $(window).scroll(function () {
        var scroll = $(window).scrollTop();

        if (scroll >= 32) {
            header.addClass("scroll");
        } else {
            header.removeClass("scroll");
        }
    });
})(jQuery);

(function ($) {

    var $basketColumn = $('.booking-basket-column'),
        $basketContent = $('.basket-column-content');

    if ($basketColumn.length === 0 || $basketContent.length === 0 || typeof requestAnimationFrame === 'undefined') {
        return;
    }

    function bookingScroll() {
        var scrollTop = $(this).scrollTop() || 0,
            basketHeight = $basketColumn.height(),
            basketContentHeight = $basketContent.height(),
            diff = basketHeight - basketContentHeight;

        if (pc.clientWidth > 1099 && diff > 100) {
            // tablet / desktop && height difference
            if (scrollTop > diff) {
                $basketContent.addClass('fixed-bottom');
            }
            else {
                $basketContent.removeClass('fixed-bottom');
            }
        }
    }

    $(window).on('scroll', function () {
        window.requestAnimationFrame(bookingScroll);
    });

})(jQuery);

(function ($) {
    if (window.location.hash) scroll(0, 0);
    setTimeout(function () { scroll(0, 0); }, 1);
    $(function () {

        if (window.location.hash) {
            $(document).ready(function () {
                $('html, body').animate({
                    scrollTop: ($(window.location.hash).offset().top - 120) + 'px'
                },
                    800,
                    'swing');
            });
        }

    });
})(jQuery);

(function ($) {
    $(document).ready(function () {
        $('.smooth-scroll')
            .click(function (event) {
                if (
                    location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
                    &&
                    location.hostname == this.hostname
                ) {
                    var target = $(this.hash);
                    target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
                    if (target.length) {
                        event.preventDefault();
                        $('html, body').animate({
                            scrollTop: target.offset().top - 140
                        }, 1000, function () {
                            var $target = $(target);
                            $target.focus();
                            if ($target.is(":focus")) { // Checking if the target was focused
                                return false;
                            } else {
                                $target.attr('tabindex', '-1'); // Adding tabindex for elements not focusable
                                $target.focus(); // Set focus again
                            };
                        });
                    }
                }
            });
    });
})(jQuery);

(function ($) {
    let barcode = $('[data-barcode]');

    if (barcode.length > 0) {
        let ref = barcode.data('booking-ref');
        JsBarcode("#booking-barcode", ref, {
            width: 4,
            height: 180,
            displayValue: false
        });
    }

})(jQuery);

(function ($) {
    $(window).scroll(function () {
        $(".site-header").addClass("sticky");
        // get the amount the window has scrolled
        var scroll = $(window).scrollTop();
        // add the 'active' class to the correct id based on the scroll amount
        if (scroll <= 100) {
            $(".site-header").removeClass("sticky");
        }
    });
})(jQuery);

(function ($) {
    let $cinemaSelector = $("#sharedCinemaSelectorPortal");

    if ($cinemaSelector.length === 0) {
        return;
    }
    $(window).scroll(function () {
        // find the id with class 'active' and remove it
        $cinemaSelector.removeClass("sticky");
        // get the amount the window has scrolled
        var scroll = $(window).scrollTop(),
            selector = $cinemaSelector.offset().top +
                $cinemaSelector.innerHeight();

        // add the 'active' class to the correct id based on the scroll amount
        if (scroll >= selector) {
            $cinemaSelector.addClass("sticky");
        }
    });

})(jQuery);


if (typeof svg4everybody !== 'undefined' && svg4everybody !== null) {
    svg4everybody();
}

(function ($) {
    let isApp = (pc.source.toLowerCase() === 'app');

    if (isApp) {
        $('#loyalty-trigger, #quickbuy-trigger, #menu li, #nav-trigger, .site-footer__column, .social-icon').hide();
        $('.site-header__logo').attr("href", "").css("pointer-events", "none");
        $('.site-footer__logo a').attr("href", "").css("pointer-events", "none");
        
        if ($('[data-loyalty-about], [data-loyalty-your-rewards]').length > 0) {
            $('a').attr('target', '_blank');
        }
    }
})(jQuery);

(function ($) {
	$(document).ready(function () {
		// Target your .container, .wrapper, .post, etc.
        $(".container").fitVids();
	});
})(jQuery);


(function ($) {
	$('.film-info__collapse-toggle').click(function() {
		$('.film-info__collapse').toggleClass('isOpen');
        $('.film-info__collapse-toggle').toggleClass('isOpen');
	});
})(jQuery);

(function () {
    var el = document.querySelectorAll('[data-changeurl]');

    if (
        el.length === 0 ||
        typeof pc === 'undefined' ||
        pc === null ||
        typeof pc.cinemas === 'undefined' ||
        pc.cinemas === null ||
        pc.cinemas.length === 0
    ) {
        return;
    }

    for (var i = 0; i < el.length; i++)
    {
        var current = el[i].dataset.changeurl;
        for (var c = 0; c < pc.cinemas.length; c++)
        {
            if (pc.cinemas[c].CinemaNodeId.toString() === current)
            {
                el[i].href = '/' + pc.cinemas[c].CinemaUrlFriendlyName + el[i].pathname + el[i].search + el[i].hash;
                break;
            }
        }
    }
})();;
var pc = pc || {};

(function ($) {
    if (pc.captcha && pc.captcha.enabled) {

        window.onloadCaptchaCallback = function () {
            var $gReCaptha = $("#g-recaptcha"),
                captchaSiteKey = $gReCaptha.attr("data-sitekey"),
                captchaType = $gReCaptha.attr("data-type"),
                captchaTheme = $gReCaptha.attr("data-theme");

            grecaptcha.render("g-recaptcha", {
                "sitekey": captchaSiteKey,
                "theme": captchaTheme,
                "type": captchaType,
                "expired-callback": pc.captcha.onExpired
            });
        };

        pc.captcha.onExpired = function () {
            grecaptcha.reset();
        };

        pc.captcha.hasCaptchaResponse = function () {
            pc.captcha.response = $('#g-recaptcha-response').val() || '';

            if (pc.captcha.response.length > 0) {
                $('[data-form-validate-captcha-message]').addClass('dn');
                return true;
            }

            $('[data-form-validate-captcha-message]').removeClass('dn');

            pc.loyalty.hideLoad();
            return false;
        }
    }
})(jQuery);;
var pc = pc || {};

pc.errorMessage = {};

// peach error codes

// NoError = 0

// UnknownError = 1
pc.errorMessage['default'] = pc.errorMessage['1'] = 'There has been an error with your order, please contact us to resolve the issue.';

// PaymentDeclined = 2
pc.errorMessage['2'] = 'The payment has been declined. Please ensure you have entered the correct details.';

// PaymentTakenWithError = 3
pc.errorMessage['3'] = 'There has been an error with your payment. Your card may have been charged, please contact our customer service.';

// OrderHasBeenProcessed = 4
pc.errorMessage['4'] = 'Your order has already been submitted for processing. Please check your email for confirmation.';

// NoTicketReturn = 5

// ProviderNotAvailable = 6 //Provider Vista/Radiant problem

// SessionExpired = 7

// NoConcessionsReturn = 8

// GeneralError = 9

// ProviderNoReturnData = 10 //Vista call problem

// LanguageNotDefinedForThisCircuit = 11

// InvalidExternalData = 12 //Problem to transform external data to provider request

// SeatsUnavailable = 13

// ProviderInternalError = 14 //The error returned by vista/Radiant is not Unexpected ERROR and vista/Radiant has a problem internally(well ok it's always true)

// TicketsNotAvailableForThisLanguage = 15

// InvalidOrder = 16

// PaymentError = 17

// UserCancelled = 18

// SecurityIssue = 19

// PaymentAuthorisationNotKnow = 20 //A technical problem arose during the authorisation,payment process, giving an unpredictable result.

// PaymentInvalid = 21

// NoConcessionsAvailable = 22

// CodeThirdPartyPaymentTicketNotValid = 23

// ThirdPartyPaymentTicketQuantityIsInvalid = 24

// SessionSoldOut = 25

// MemberNotActivated = 26

// MembershipServiceUnvailable = 27

// LoyaltyConnectError = 28

// MemberEmailIncorrect = 29

// MemberNotFound = 30

// MemberPasswordIncorrect = 31

// InsufficientPointsToAddThisTicket = 32

// LoyaltyTimeout = 33

// LoyaltyUserNameAlreadyExists = 34

// LoyaltyNotSupportedAtCinema = 35

// MemberLoginResetDisallowed = 36

// VoucherCodeInvalid = 37
pc.errorMessage['voucher'] = pc.errorMessage['37'] = 'Sorry, this voucher isn\'t valid.';

// VoucherCodeAlreadyUsed = 38
pc.errorMessage['voucherAlreadyUsed'] = pc.errorMessage['38'] = 'Sorry, this voucher has already been used.';

// VistaBookingTimeout = 39

// HostedPaymentUserCancelled = 40

// HostedPaymentPaymentDeclined = 41

// HostedPaymentGeneralError = 42

// HostedPaymentInvalidData = 43

// HostedPaymentInvalidSecurityHash = 44

// MemberNotRefreshed = 45 //Problem to refresh login

// ExpiredLoyaltyMember = 46

// MemberDetailsIncorrect = 47

// PrePaymentIssue = 48

// LoyaltyCinemasNotDefined = 49

// NotImplemented = 50

// InvalidGiftCard = 51

// ProblemGiftCardProvider = 52

// InvalidGiftCardTransaction = 53

// InvalidGiftCardRequest = 54

// OrderHasTimeout = 55

// LoyaltyResetPasswordInvalidEmail = 56

// LoyaltyResetPasswordInvalidResetCode = 57

// InvalidResetPassword = 58

// LoyaltyMemberLoginFailed = 59

// LoyaltyMemberAlreadyExists = 60

// InvalidTicket = 61

// Refunded=64

// RefundFailed = 65

// /peach error codes

// tickets

pc.errorMessage['noTicketsSelected'] = 'Please select a ticket.';
pc.errorMessage['needOtherTickets'] = 'Please select more tickets.';

// / tickets

// seating error codes

pc.errorMessage['seatMissing'] = 'Please check your seat selection.';
pc.errorMessage['seatGap'] = 'Please ensure that you do not leave a single gap between seats.';
pc.errorMessage['seatGapSold'] = 'Please ensure that you do not leave a gap between your chosen seats and a sold seat.';
pc.errorMessage['seatGapAisle'] = 'Please ensure that you do not leave a gap between your chosen seats and the aisle.';
pc.errorMessage['sofaPart'] = 'Please ensure that you select the whole sofa.';

// /seating error codes

// token

pc.errorMessage['tokenRemove'] = 'issue removing saved card';

// /token

// timeout

pc.errorMessage['timeout'] = 'Your booking session has timed out. Please try again.';

// /timeout

// giftcard redemption

pc.errorMessage['gcFail'] = 'Sorry, this card number isn\'t valid or there is a no available balance.';
pc.errorMessage['gcNoBalance'] = 'Sorry, this card number isn\'t valid or there is a no available balance.';
pc.errorMessage['gcSuccess'] = 'You have {{balance}} remaining after this purchase.';
pc.errorMessage['gcPartPayment'] = 'Please pay remaining {{balance}}.';
pc.errorMessage['gcAddFail'] = 'We could not process your details. Please ensure all the information above is correct.';

// /giftcard redemption

// form

pc.errorMessage['form'] = 'Please check and complete all highlighted fields.';

// /form
;
var pc = pc || {};

(function ($) {

    $("[data-form-field]").not("[data-book] [data-form-field]").on("click change",
        function (e) {
            // hide field error messages
            $(this).closest(".form-item, div").removeClass("invalid");
        });

    $('[data-form-field="number"]').on("keydown",
        function (e) {
            // only allow numbers
            this.value = this.value.replace(/\D/g, "");
        });

    if ($(".phonenumber").length > 0) {

        $(".phonenumber").on("input",
            function (e) {
                $(this).val($(this).val().replace(/[^0-9]/gi, ""));
            });
    }

    pc.formValidate = function (field, hideError) {
        var isValid = true,
            isDateValid = true,
            $field = $(field),
            fieldType = $field.attr("type") || "",
            fieldName = $field.attr("name"),
            fieldVal = $field.val() || "",
            regExEmail =
                /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
            regExNum = /^\d+$/,
            $fieldParent = $field.closest(".form-item") || $field.closest("div"),
            $fieldGrandparent = $field.parent().parent("div"),
            validateType = fieldType || "",
            validateConfirm = $field.attr("data-form-confirm") || "",
            validateDoesNotMatch = $field.attr("data-form-does-not-match") || "",
            validateDate = $field.attr("data-form-date-day") ||
                $field.attr("data-form-date-month") ||
                $field.attr("data-form-date-year") ||
                "",
            minLength = parseInt($field.attr("minlength") || 1),
            validateStrongPassword = $field.attr("data-form-strong-password") || false,
            validateLoyaltyCardNumber = $field.attr("data-form-loyalty-card-number") || false,
            regEx = $field.data("regex") || "";
        if ($field.is(":visible")) { /* Free pass for invisible fields. */

            // check for value
            if (fieldVal.length < minLength) {
                isValid = false;
            }
            // check value not = '-1' e.g. selects
            else if (fieldVal === "-1") {
                isValid = false;
            }
            // check email
            else if (fieldType === "email" && regExEmail.test(fieldVal) === false) {
                isValid = false;
            }
            // check number
            else if (validateType === "number" && regExNum.test(fieldVal) === false) {
                isValid = false;
            }
            // check tel
            else if (validateType === "tel") {
                var numb = (fieldVal.match(/\d/g));
                if (numb !== null) {
                    if (numb.join("").length < 10) {
                        isValid = false;
                    }
                } else {
                    isValid = false;
                }
            }
            // check for loyalty card number
            else if (validateLoyaltyCardNumber && pc.loyaltyCardNumberValidate(fieldVal) === false) {
                isValid = false;
            }
            // check for strong password
            else if (validateStrongPassword && pc.passwordStrengthValidate(fieldVal) === false) {
                isValid = false;
            }
            // check confirm fields match original
            else if (validateConfirm !== "" && fieldVal !== $('[name="' + validateConfirm + '"]').val()) {
                isValid = false;
            }
            // check field doesnt match
            else if (validateDoesNotMatch !== "" && fieldVal === $('[name="' + validateDoesNotMatch + '"]').val()) {
                isValid = false;
            }
            // check checkbox is checked e.g. terms
            else if (fieldType === "checkbox" && $('[name="' + fieldName + '"]:checked').length === 0) {
                isValid = false;
            }
            // check date
            else if (validateDate !== "") {
                var day = parseInt($('[data-form-date-day="' + validateDate + '"]').val() || 0),
                    month = parseInt($('[data-form-date-month="' + validateDate + '"]').val() || 0),
                    year = parseInt($('[data-form-date-year="' + validateDate + '"]').val() || 0);

                if (day === 0 || month === 0 || year === 0) {
                    isValid = false;
                    isDateValid = false;
                } else {
                    var testDate = new Date(year, month - 1, day);

                    if (testDate === "Invalid Date" || isNaN(testDate) || testDate.getMonth() + 1 !== month) {
                        isValid = false;
                        isDateValid = false;
                    }
                }
            }
            // check regex
            else if (regEx !== "" && new RegExp(regEx).test(fieldVal) === false) {
                isValid = false;
            } else if (validateType === "expirymonth" || validateType === "expiryyear") {
                var today = new Date(),
                    expDate = new Date(),
                    $expMonth = $('[data-form-field="expirymonth"]'),
                    expMonth,
                    $expYear = $('[data-form-field="expiryyear"]'),
                    expYear;

                if ($expYear.length > 0 && $expMonth.length > 0) {
                    expMonth = $expMonth.val();
                    expYear = $expYear.val();

                    expDate.setFullYear(expYear, (parseInt(expMonth) - 1));

                    if (today.getTime() > expDate.getTime()) {
                        isValid = false;
                    }
                } else {
                    isValid = false;
                }
            }
        }

        if (typeof hideError === "undefined") {

            if (isValid === false) {
                // field not valid, show error
                $fieldParent.addClass("invalid");
            } else {
                // field valid, hide error
                $fieldParent.removeClass("invalid");
            }
        }

        return { isValid: isValid, isDateValid: isDateValid };
    };

    pc.loyaltyCardNumberValidate = function (loyaltyCardNumber) {
        var regEx = /^\d{10}$/;

        if (regEx.test(loyaltyCardNumber)) {
            return true;
        }

        return false;
    };

    pc.passwordStrengthValidate = function (password) {
        var minMaxLength = /^[\s\S]{8,}$/, // The string must be 8 characters or longer
            upper = /[A-Z]/, // The string must contain at least 1 uppercase alphabetical character
            lower = /[a-z]/, // The string must contain at least 1 lowercase alphabetical character
            number = /[0-9]/, // The string must contain at least 1 numeric character
            special = /[£!#$%&*?@^_~]/, // The string must contain at least one special character
            count = 0;

        if (minMaxLength.test(password)) {
            // Need 3 out of 4 of these to match.
            // Criteria for project -> min 8 chars, min 1 number, min 1 special char
            // if (upper.test(password)) count++;
            // if (lower.test(password)) count++;
            if (minMaxLength.test(password)) count++;
            if (number.test(password)) count++;
            if (special.test(password)) count++;
        }

        return count >= 3;
    };


    // Handle focus styles in IE11 and Edge
    $("form :input").focus(function () {

        $("label[for='" + this.id + "']").addClass("labelFocus");

        var labelId = (this.id).toLowerCase();

        if (labelId.indexOf("radio") >= 0 ||
            labelId.indexOf("day") >= 0 ||
            labelId.indexOf("month") >= 0 ||
            labelId.indexOf("year") >= 0) {
            $(this).parent().parent().find("label").addClass("labelFocus");
        }
    })
        .blur(function () {
            $("label").removeClass("labelFocus");
        });

})(jQuery);;
(function ($) {
    // slides
    var $slider = $('[data-hero-scroll]'),
        slideshow = true,
        selectedCinemaId = null,
        players = {},
        templateHeroItem = $('#templateHeroItem').html(),
        templateNoHeroItems = $('#templateNoHeroItems').html();

    function getNewSlides(payload) {
        if (payload !== null
            && typeof (payload) !== 'undefined'
            && payload.selectedCinemaId !== null
            && typeof (payload.selectedCinemaId) !== 'undefined') {
            selectedCinemaId = payload.selectedCinemaId;
        }

        if (selectedCinemaId) {
            var $heroItems = $('.hero-panel'),
                hasHeroItems = $heroItems.length > 0 ? true : false;

            if (hasHeroItems) {
                $slider.removeClass('hero-carousel--has-multiple')
                $slider.addClass('loading');
                $slider.off('init');
                $slider.flickity('destroy');
                $slider.html(Mustache.render(templateNoHeroItems));

                $.ajax({
                    url: "/Umbraco/Api/StkContentApi/GetHeroCarouselPanelItemsByCinema?cinemaCookieId=" + selectedCinemaId + '&nodeId=' + pc.currentNodeId,
                    type: "GET",
                    contentType: "application/json; charset=utf-8",
                    xhrFields: {
                        withCredentials: true
                    }
                }).done(function (data) {


                    if (typeof data !== 'undefined' && data !== null && data.length > 0) {
                        var innerHtml = "";

                        if (data.length > 1) {
                            $slider.addClass('hero-carousel--has-multiple');
                        }

                        $.each(data, function (idx, itm) {
                            innerHtml += Mustache.render(templateHeroItem, itm);
                        });

                        $slider.html(innerHtml);
                    }

                    $slider.flickity({
                        // options

                        autoPlay: 5000,
                        pauseAutoPlayOnHover: false,
                        wrapAround: true
                    });
                    $slider.removeClass('loading');

                });
            }
        }
    }

    // check we have slides
    if ($slider.length > 0) {
        let slides = $('.hero-panel');
        $slider.flickity({
            // options
            wrapAround: true,
            autoPlay: 5000,
            pauseAutoPlayOnHover: false,
            prevNextButtons: slides.length > 1 ? true : false,
            pageDots: slides.length > 1 ? true : false
        });
    }

    $(document).ready(function () {
        EventEmitterClient.on('UpdatedSelectedCinema', () => {
            if (location.pathname === '/') {
                window.location.reload();
            }
        });
    });

    //function showSliderItems($slider) {
    //    $slider.find('[data-hero-control]').fadeIn(500);
    //    $('[data-header]').fadeIn(500);
    //    $(window).off('scroll.hero');
    //}

    //function hideSliderItems($slider) {
    //    $slider.find('[data-hero-control]').fadeOut(500);

    //    if (typeof pc.clientWidth !== 'undefined' && pc.clientWidth >= 768 && $(window).scrollTop() < $slider.height()) {
    //        $('[data-header]').fadeOut(500);

    //        $(window).on('scroll.hero', function () {
    //            if (typeof pc.clientWidth !== 'undefined' && pc.clientWidth >= 768 && $(window).scrollTop() < $slider.height()) {
    //                $('[data-header]').fadeOut(500);
    //            }
    //            else {
    //                $('[data-header]').fadeIn(500);
    //            }
    //        });
    //    }
    //}

    //function getYTId(url) {
    //    var regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,
    //        match = url.match(regExp);

    //    if (match && match[2].length == 11) {
    //        return match[2];
    //    } else {
    //        return undefined;
    //    }
    //}
})(jQuery);;
/*!
 * jQuery Accordion 0.0.1
 * (c) 2014 Victor Fernandez <victor@vctrfrnndz.com>
 * MIT Licensed.
 */

;(function ( $, window, document, undefined ) {

    var pluginName = 'accordion',
        defaults = {
            transitionSpeed: 300,
            transitionEasing: 'ease',
            controlElement: '[data-control]',
            contentElement: '[data-content]',
            groupElement: '[data-accordion-group]',
            singleOpen: true
        };

    function Accordion(element, options) {
        this.element = element;
        this.options = $.extend({}, defaults, options);
        this._defaults = defaults;
        this._name = pluginName;
        this.init();
    }

    Accordion.prototype.init = function () {
        var self = this,
            opts = self.options;

        var $accordion = $(self.element),
            $controls = $accordion.find('> ' + opts.controlElement),
            $content =  $accordion.find('> ' + opts.contentElement);

        var accordionParentsQty = $accordion.parents('[data-accordion]').length,
            accordionHasParent = accordionParentsQty > 0;

        var closedCSS = { 'max-height': 0, 'overflow': 'hidden' };

        var CSStransitions = supportsTransitions();

        function debounce(func, threshold, execAsap) {
            var timeout;

            return function debounced() {
                var obj = this,
                    args = arguments;

                function delayed() {
                    if (!execAsap) func.apply(obj, args);
                    timeout = null;
                };

                if (timeout) clearTimeout(timeout);
                else if (execAsap) func.apply(obj, args);

                timeout = setTimeout(delayed, threshold || 100);
            };
        }

        function supportsTransitions() {
            var b = document.body || document.documentElement,
                s = b.style,
                p = 'transition';

            if (typeof s[p] == 'string') {
                return true;
            }

            var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];

            p = 'Transition';

            for (var i=0; i<v.length; i++) {
                if (typeof s[v[i] + p] == 'string') {
                    return true;
                }
            }

            return false;
        }

        function requestAnimFrame(cb) {
            if(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame) {
                return  requestAnimationFrame(cb) ||
                        webkitRequestAnimationFrame(cb) ||
                        mozRequestAnimationFrame(cb);
            } else {
                return setTimeout(cb, 1000 / 60);
            }
        }

        function toggleTransition($el, remove) {
            if(!remove) {
                $content.css({
                    '-webkit-transition': 'max-height ' + opts.transitionSpeed + 'ms ' + opts.transitionEasing,
                    'transition': 'max-height ' + opts.transitionSpeed + 'ms ' + opts.transitionEasing
                });
            } else {
                $content.css({
                    '-webkit-transition': '',
                    'transition': ''
                });
            }
        }

        function calculateHeight($el) {
            var height = 0;

            $el.children().each(function() {
                height = height + $(this).outerHeight(true);
            });

            $el.data('oHeight', height);
        }

        function updateParentHeight($parentAccordion, $currentAccordion, qty, operation) {
            var $content = $parentAccordion.filter('.open').find('> [data-content]'),
                $childs = $content.find('[data-accordion].open > [data-content]'),
                $matched;

            if(!opts.singleOpen) {
                $childs = $childs.not($currentAccordion.siblings('[data-accordion].open').find('> [data-content]'));
            }

            $matched = $content.add($childs);

            if($parentAccordion.hasClass('open')) {
                $matched.each(function() {
                    var currentHeight = $(this).data('oHeight');

                    switch (operation) {
                        case '+':
                            $(this).data('oHeight', currentHeight + qty);
                            break;
                        case '-':
                            $(this).data('oHeight', currentHeight - qty);
                            break;
                        default:
                            throw 'updateParentHeight method needs an operation';
                    }

                    $(this).css('max-height', $(this).data('oHeight'));
                });
            }
        }

        function refreshHeight($accordion) {
            if($accordion.hasClass('open')) {
                var $content = $accordion.find('> [data-content]'),
                    $childs = $content.find('[data-accordion].open > [data-content]'),
                    $matched = $content.add($childs);

                calculateHeight($matched);

                $matched.css('max-height', $matched.data('oHeight'));
            }
        }

        function closeAccordion($accordion, $content) {
            $accordion.trigger('accordion.close');
            
            if(CSStransitions) {
                if(accordionHasParent) {
                    var $parentAccordions = $accordion.parents('[data-accordion]');

                    updateParentHeight($parentAccordions, $accordion, $content.data('oHeight'), '-');
                }

                $content.css(closedCSS);

                $accordion.removeClass('open');
            } else {
                $content.css('max-height', $content.data('oHeight'));

                $content.animate(closedCSS, opts.transitionSpeed);

                $accordion.removeClass('open');
            }
        }

        function openAccordion($accordion, $content) {
            $accordion.trigger('accordion.open');
            if(CSStransitions) {
                toggleTransition($content);

                if(accordionHasParent) {
                    var $parentAccordions = $accordion.parents('[data-accordion]');

                    updateParentHeight($parentAccordions, $accordion, $content.data('oHeight'), '+');
                }

                requestAnimFrame(function() {
                    $content.css('max-height', $content.data('oHeight'));
                });

                $accordion.addClass('open');
            } else {
                $content.animate({
                    'max-height': $content.data('oHeight')
                }, opts.transitionSpeed, function() {
                    $content.css({'max-height': 'none'});
                });

                $accordion.addClass('open');
            }
        }

        function closeSiblingAccordions($accordion) {
            var $accordionGroup = $accordion.closest(opts.groupElement);

            var $siblings = $accordion.siblings('[data-accordion]').filter('.open'),
                $siblingsChildren = $siblings.find('[data-accordion]').filter('.open');

            var $otherAccordions = $siblings.add($siblingsChildren);

            $otherAccordions.each(function() {
                var $accordion = $(this),
                    $content = $accordion.find(opts.contentElement);

                closeAccordion($accordion, $content);
            });

            $otherAccordions.removeClass('open');
        }

        function toggleAccordion() {
            var isAccordionGroup = (opts.singleOpen) ? $accordion.parents(opts.groupElement).length > 0 : false;

            calculateHeight($content);

            if(isAccordionGroup) {
                closeSiblingAccordions($accordion);
            }

            if($accordion.hasClass('open')) {
                closeAccordion($accordion, $content);
            } else {
                openAccordion($accordion, $content);
            }
        }

        function addEventListeners() {
            $controls.on('click', toggleAccordion);
            
            $controls.on('accordion.toggle', function() {
                if(opts.singleOpen && $controls.length > 1) {
                    return false;
                }
                
                toggleAccordion();
            });
            
            $controls.on('accordion.refresh', function() {
                refreshHeight($accordion);
            });

            $(window).on('resize', debounce(function() {
                refreshHeight($accordion);
            }));
        }

        function setup() {
            $content.each(function() {
                var $curr = $(this);

                if($curr.css('max-height') != 0) {
                    if(!$curr.closest('[data-accordion]').hasClass('open')) {
                        $curr.css({ 'max-height': 0, 'overflow': 'hidden' });
                    } else {
                        toggleTransition($curr);
                        calculateHeight($curr);

                        $curr.css('max-height', $curr.data('oHeight'));
                    }
                }
            });


            if(!$accordion.attr('data-accordion')) {
                $accordion.attr('data-accordion', '');
                $accordion.find(opts.controlElement).attr('data-control', '');
                $accordion.find(opts.contentElement).attr('data-content', '');
            }
        }

        setup();
        addEventListeners();
    };

    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName,
                new Accordion( this, options ));
            }
        });
    }

})( jQuery, window, document );
;
var pc = pc || {};
pc.loyalty = pc.loyalty || {};

pc.loyalty.showLoad = function () {
    $("[data-loadHook]").addClass("loading");
};

pc.loyalty.hideLoad = function () {
    $("[data-loadHook]").removeClass("loading");
};

// Rewards Overlay Section
(function ($) {

    var $loyaltyOverlay = $("[data-loyalty-overlay]");
    if ($loyaltyOverlay.length === 0) {
        return;
    }

    var $loginForm = $('[data-form="LoyaltyLogin"]'),
        $loginError = $('[data-form-error]'),
        $loginPassword = $("[data-loyalty-password]"),
        $loginUsername = $("[data-loyalty-username]"),
        loyaltyOverlay = {};


    loyaltyOverlay.SetupLogin = function () {
        $loginForm.on("submit",
            function (e) {

                e.preventDefault();

                $loginError.addClass("dn");

                // Validate required form fields
                var isUsernameValid = false,
                    isPasswordValid = false;

                if (typeof pc.formValidate !== "undefined") {
                    $loginUsername.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isUsernameValid = true;
                        }
                    });
                    $loginPassword.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isPasswordValid = true;
                        }
                    });
                }

                if (!isUsernameValid || !isPasswordValid) {
                    $loginError.removeClass("dn");
                    pc.loyalty.hideLoad();
                    return false;
                }

                pc.loyalty.showLoad();

                // Build the json data from the form fields
                var jsonData = {
                    'MemberCredentialsRequest': {
                        'Username': $loginUsername.val(),
                        'Password': $loginPassword.val()
                    }
                };

                // Call the umbraco loyalty login method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.MemberCredentialsRequest),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {

                        if (typeof data !== "undefined" && data !== null)
                            if (data.ResultCode === 0) {
                                // Success
                                setTimeout(function () {
                                    if (typeof pc.movioTrack !== 'undefined' && typeof pc.movioTrack.login !== 'undefined') {
                                        pc.movioTrack.login();
                                    }
                                    window.location = pc.loyalty.loginLandingUrl;
                                },
                                    1000);
                                return;
                            }

                        $loginError.removeClass("dn");

                        if ($loginError.text(data.ResultCode) == 1002 || 1000) {
                            $loginError.html(data.ResultMessage + "<a href=\"https://www.bbtheatres.com/backstage-help/\">Backstage Help</a>");
                        } else {
                            $loginError.text(data.ResultMessage);
                        }

                        pc.loyalty.hideLoad();
                    })
                    .fail(function (jqXhr, status, err) {
                        $loginError.removeClass("dn");
                        pc.loyalty.hideLoad();
                    });
            });
    };

    loyaltyOverlay.SetupLogin();

})(jQuery);

// Rewards SignIn Panel
(function ($) {

    var $loyaltyLoginPanel = $("[data-loyalty-login-panel]");
    if ($loyaltyLoginPanel.length === 0) {
        return;
    }

    var $loginForm = $('[data-form="LoyaltyLoginPanel"]'),
        $loginErrorApi = $('[data-loyalty-panel-login-error="api"]'),
        $loginErrorForm = $('[data-loyalty-panel-login-error="form"]'),
        $loginErrorGeneral = $('[data-loyalty-panel-login-error="general"]'),
        $loginSuccess = $('[data-loyalty-panel-login-success="form"]'),
        $loginPassword = $("[data-loyalty-panel-password]"),
        $loginUsername = $("[data-loyalty-panel-username]"),
        loyaltyLoginPanel = {};

    loyaltyLoginPanel.SetupLogin = function () {
        $loginForm.on("submit",
            function (e) {
                e.preventDefault();

                // Hide errors
                $loginErrorGeneral.addClass("dn");
                $loginErrorForm.addClass("dn");

                // Validate required form fields
                var isUsernameValid = false,
                    isPasswordValid = false;

                if (typeof pc.formValidate !== "undefined") {
                    $loginUsername.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isUsernameValid = true;
                        }
                    });
                    $loginPassword.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isPasswordValid = true;
                        }
                    });
                }

                if (!isUsernameValid || !isPasswordValid) {
                    $loginErrorForm.removeClass("dn");
                    pc.loyalty.hideLoad();
                    return false;
                }

                pc.loyalty.showLoad();

                // Build the json data from the form fields
                var jsonData = {
                    'MemberCredentialsRequest': {
                        'Username': $loginUsername.val(),
                        'Password': $loginPassword.val()
                    }
                };

                // Call the umbraco loyalty login method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.MemberCredentialsRequest),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {

                        if (typeof data !== "undefined" && data !== null)
                            if (data.ResultCode === 0) {
                                // Success
                                setTimeout(function () {
                                    if (typeof pc.movioTrack !== 'undefined' && typeof pc.movioTrack.login !== 'undefined') {
                                        pc.movioTrack.login();
                                    }
                                    
                                    window.location = pc.loyalty.loginLandingUrl;
                                },
                                    1000);
                                return;
                            }

                        $loginErrorApi.removeClass("dn");
                        $loginErrorApi.text(data.ResultMessage);
                        pc.loyalty.hideLoad();
                    })
                    .fail(function (jqXhr, status, err) {
                        $loginErrorGeneral.removeClass("dn");
                    })
                    .always(function () {
                        pc.loyalty.hideLoad();
                    });
            });
    };

    loyaltyLoginPanel.SetupLogin();

})(jQuery);

// landingpage SignIn section
(function ($) {

    var $loyaltyLoginSection = $("[data-loyalty-login-section]");
    if ($loyaltyLoginSection.length === 0) {
        return;
    }

    var $loginForm = $('[data-form="LoyaltyLoginSection"]'),
        $loginErrorApi = $('[data-loyalty-section-login-error="api"]'),
        $loginErrorForm = $('[data-loyalty-section-login-error="form"]'),
        $loginErrorGeneral = $('[data-loyalty-section-login-error="general"]'),
        $loginSuccess = $('[data-loyalty-section-login-success="form"]'),
        $loginPassword = $("[data-loyalty-section-password]"),
        $loginUsername = $("[data-loyalty-section-username]");

    $loginForm.on("submit",
        function (e) {
            e.preventDefault();
            
            // Hide errors
            $loginErrorGeneral.addClass("dn");
            $loginErrorForm.addClass("dn");
            $loginForm.find('.invalid').removeClass('invalid');

            // Validate required form fields
            var isUsernameValid = false,
                isPasswordValid = false;

            if (typeof pc.formValidate !== "undefined") {
                $loginUsername.each(function () {
                    if (pc.formValidate(this).isValid === true) {
                        isUsernameValid = true;
                    }
                    else {
                        $(this).parent().addClass('invalid');
                    }
                });
                $loginPassword.each(function () {
                    if (pc.formValidate(this).isValid === true) {
                        isPasswordValid = true;
                    }
                    else {
                        $(this).parent().addClass('invalid');
                    }
                });
            }

            if (!isUsernameValid || !isPasswordValid) {
                $loginErrorForm.removeClass("dn");
                pc.loyalty.hideLoad();
                return false;
            }

            pc.loyalty.showLoad();

            // Build the json data from the form fields
            var jsonData = {
                'MemberCredentialsRequest': {
                    'Username': $loginUsername.val(),
                    'Password': $loginPassword.val()
                }
            };

            // Call the umbraco loyalty login method
            $.ajax({
                url: this.action,
                type: "POST",
                dataType: "json",
                data: JSON.stringify(jsonData.MemberCredentialsRequest),
                contentType: "application/json; charset=utf-8"
            })
                .done(function (data) {

                    if (typeof data !== "undefined" && data !== null)
                        if (data.ResultCode === 0) {
                            // Success
                            setTimeout(function () {
                                if (typeof pc.movioTrack !== 'undefined' && typeof pc.movioTrack.login !== 'undefined') {
                                    pc.movioTrack.login();
                                }

                                window.location = pc.loyalty.loginLandingUrl;
                            },
                                1000);
                            return;
                        }

                    $loginErrorApi.removeClass("dn");

                    if ($loginErrorApi.text(data.ResultCode) == 1002 || 1000) {
                        $loginErrorApi.html(data.ResultMessage + "<a href=\"https://www.bbtheatres.com/backstage-help/\">Backstage Help</a>");
                    } else {
                        $loginErrorApi.text(data.ResultMessage);
                    }

                    pc.loyalty.hideLoad();
                })
                .fail(function (jqXhr, status, err) {
                    $loginErrorGeneral.removeClass("dn");
                })
                .always(function () {
                    pc.loyalty.hideLoad();
                });
        });

})(jQuery);

// Booking SignIn Panel
(function ($) {

    var $loyaltyBookingLoginPanel = $("[data-book-login-section]");
    if ($loyaltyBookingLoginPanel.length === 0) {
        return;
    }

    var $loginErrorApi = $('[data-loyalty-panel-login-error="api"]'),
        $loginErrorForm = $('[data-loyalty-panel-login-error="form"]'),
        $loginForm = $('[data-form="LoyaltyBookingLogin"]'),
        $loginPassword = $("[data-booking-loyalty-password]"),
        $loginUsername = $("[data-booking-loyalty-username]"),
        loyaltyBookingLoginPanel = {};

    loyaltyBookingLoginPanel.SetupLogin = function () {
        $loginForm.on("submit",
            function (e) {
                e.preventDefault();

                // Hide errors
                $loginErrorForm.addClass("dn");
                $loginErrorApi.addClass("dn");

                var isValid = false;
                if (typeof pc.formValidate !== "undefined") {
                    $loginUsername.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isValid = true;
                        }
                    });
                    $loginPassword.each(function () {
                        if (pc.formValidate(this).isValid === true) {
                            isValid = true;
                        }
                    });
                }

                if (!isValid) {
                    return false;
                }

                pc.loyalty.showLoad();

                // Build the json data from the form fields
                var jsonData = {
                    'MemberCredentialsRequest': {
                        'Username': $loginUsername.val(),
                        'Password': $loginPassword.val()
                    }
                };

                // Call the umbraco loyalty login method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.MemberCredentialsRequest),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (typeof data !== "undefined" && data !== null && data.PeachCode === 0) {
                            //console.log('Loyalty Login DONE');

                            // Redirect to itself
                            setTimeout(function () {
                                if (typeof pc.movioTrack !== 'undefined' && typeof pc.movioTrack.login !== 'undefined') {
                                    pc.movioTrack.login();
                                }

                                //console.log('END setTimeout');
                                window.location = window.location.href;
                            },
                                1000);
                            return;
                        }

                        // Always display the error if the code gets here.
                        $("[data-login-error]").removeClass("dn");
                    })
                    .fail(function (jqXhr, status, err) {
                        //console.log('Loyalty Login FAIL');
                        $("[data-login-error]").removeClass("dn");
                        pc.loyalty.hideLoad();
                    })
                    .always(function () {

                    });
            });
    };

    loyaltyBookingLoginPanel.SetupLogin();

})(jQuery);


// Rewards Start Recover Username
(function ($) {

    var $loyaltyStartRecover = $("[data-loyalty-start-reset]");
    if ($loyaltyStartRecover.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyStartRecover"]'),
        $formApiError = $("[data-loyalty-start-recover-api-error]"),
        $formEmail = $("#RecoverUsername-Email"),
        $formEmailEmpty = $("[data-loyalty-start-recover-empty-error]"),
        $formSuccess = $("[data-loyalty-start-recover-success]"),
        $formUnknownError = $("[data-loyalty-start-recover-unknown-error]"),
        loyaltyStartRecover = {};

    loyaltyStartRecover.Setup = function () {
        $form.on("submit",
            function (e) {
                e.preventDefault();

                // Ensure error and success hidden
                $formEmailEmpty.addClass("dn");
                $formUnknownError.addClass("dn");
                $formSuccess.addClass("dn");
                $formApiError.empty();

                // Validate required form fields
                var isValid = true;
                if (typeof pc.formValidate !== "undefined") {
                    //$formEmail.each(function() {
                    $form.find("[data-form-field][required]").each(function () {
                        if (pc.formValidate(this).isValid === false) {
                            isValid = false;
                        }
                    });
                }

                if (!isValid) {
                    $formEmailEmpty.removeClass("dn");
                    return false;
                }

                // Build the json data from the form fields
                var jsonData = {
                    'LoyaltyRecoverPassword': {
                        'Email': $formEmail.val()
                    }
                };

                pc.loyalty.showLoad();

                // Call the umbraco loyalty recover password method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.LoyaltyRecoverPassword),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (typeof data !== "undefined" && data !== null) {
                            if (data.ResultCode === 0) {
                                // Hide the form
                                $form.addClass("dn");
                                // Show success message
                                $formSuccess.removeClass("dn");
                                $(document).scrollTop(0);
                                pc.loyalty.hideLoad();
                            } else {
                                // Show error message from API
                                $formApiError.text(data.ResultMessage);
                            }
                        }
                    })
                    .fail(function (jqXhr, status, err) {
                        $formUnknownError.removeClass("dn");
                    })
                    .always(function () {
                        pc.loyalty.hideLoad();
                    });
            });
    };

    loyaltyStartRecover.Setup();

})(jQuery);


// Rewards Start Password Reset Page
(function ($) {

    var $loyaltyStartReset = $("[data-loyalty-start-reset]");
    if ($loyaltyStartReset.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyStartReset"]'),
        $formApiError = $("[data-loyalty-start-reset-api-error]"),
        $formEmail = $("#ResetPassword-Email"),
        $formEmailEmpty = $("[data-loyalty-start-reset-empty-error]"),
        $formSuccess = $("[data-loyalty-start-reset-success]"),
        $formUnknownError = $("[data-loyalty-start-reset-unknown-error]"),
        $resetPasswordText = $('.reset-password-text'),
        loyaltyStartReset = {};

    loyaltyStartReset.Setup = function () {
        $form.on("submit",
            function (e) {
                e.preventDefault();

                // Ensure error and success hidden
                $formEmailEmpty.addClass("dn");
                $formUnknownError.addClass("dn");
                $formSuccess.addClass("dn");
                $formApiError.empty();

                // Validate required form fields
                var isValid = true;
                if (typeof pc.formValidate !== "undefined") {
                    $form.find("[data-form-field][required]").each(function () {
                        if (pc.formValidate(this).isValid === false) {
                            isValid = false;
                        }
                    });
                }

                if (!isValid) {
                    $formEmailEmpty.removeClass("dn");
                    return false;
                }

                // Build the json data from the form fields
                var jsonData = {
                    'LoyaltyResetPassword': {
                        'Email': $formEmail.val()
                    }
                };

                pc.loyalty.showLoad();

                // Call the umbraco loyalty reset password method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.LoyaltyResetPassword),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (typeof data !== "undefined" && data !== null) {
                            if (data.ResultCode === 0) {
                                // Hide the form
                                $form.addClass("dn");
                                // Show success message
                                $('[data-loyalty-start-reset-email]').html($formEmail.val());
                                $formSuccess.removeClass("dn");
                                pc.loyalty.hideLoad();
                            } else {
                                // Show error message from API
                                $formApiError.text(data.ResultMessage);
                            }
                        }
                    })
                    .fail(function (jqXhr, status, err) {
                        $formUnknownError.removeClass("dn");
                    })
                    .always(function () {
                        pc.loyalty.hideLoad();
                    });
            });
    };

    loyaltyStartReset.Setup();

})(jQuery);

// Rewards Complete Password Reset Page
(function ($) {

    var $loyaltyCompleteReset = $("[data-loyalty-complete-reset]");
    if ($loyaltyCompleteReset.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyCompleteReset"]'),
        $formApiError = $("[data-complete-reset-api]"),
        $formEmpty = $("[data-complete-reset-empty]"),
        $formError = $("[data-complete-reset-error]"),
        loyaltyCompleteReset = {};

    loyaltyCompleteReset.Setup = function () {
        $form.on("submit",
            function (e) {
                e.preventDefault();

                $formApiError.empty();
                $formApiError.addClass("dn");
                $formEmpty.addClass("dn");
                $formError.addClass("dn");

                var isValid = true;
                if (typeof pc.formValidate !== "undefined") {
                    $("#LoyaltyCompleteReset-Password, #LoyaltyCompleteReset-ConfirmPassword").each(function () {
                        if (pc.formValidate(this).isValid === false) {
                            isValid = false;
                        }
                    });
                }

                if (!isValid) {
                    $formEmpty.removeClass("dn");
                    pc.formInvalidScroll();
                    // Exit as not valid
                    return false;
                }

                // Build the json data from the form fields
                var jsonData = {
                    'ResetPasswordRequest': {
                        'MemberId': $("#LoyaltyCompleteReset-MembershipId").val(),
                        'ResetCode': $("#LoyaltyCompleteReset-ResetCode").val(),
                        'Password': $("#LoyaltyCompleteReset-Password").val()
                    }
                };

                pc.loyalty.showLoad();

                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.ResetPasswordRequest),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (data !== undefined && data !== null && data.ResultCode === 0) {
                            // Hide the form
                            $form.addClass("dn");
                            // Show the done message
                            $("[data-complete-reset-done]").removeClass("dn");
                            pc.loyalty.hideLoad();
                        } else {
                            $formApiError.removeClass("dn");
                            $formApiError.text(data.ResultMessage);
                            pc.loyalty.hideLoad();
                        }
                    })
                    .fail(function () {
                        $formError.removeClass("dn");
                        pc.loyalty.hideLoad();
                    });
            });
    };

    loyaltyCompleteReset.Setup();

})(jQuery);

// Rewards Register Page
(function ($) {

    var $loyaltyRegister = $("[data-loyalty-register]");
    if ($loyaltyRegister.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyRegister"]'),
        $formApiError = $("[data-api-error]"),
        $formValidationError = $("[data-validation-error]"),
        $dobValidationError = $("[data-dob-error]"),
        //$formSuccess = $('[data-loyalty-success="LoyaltyRegister"]'),
        loyaltyRegister = {};

    loyaltyRegister.Setup = function () {
        //if (window.location.search.indexOf("action=success") > -1) {
        //  // Hide form
        //  $form.addClass("dn");

        //  // Show success
        //  $formSuccess.removeClass("dn");
        //}

        $form.on("submit",
            function (e) {
                e.preventDefault();





                $formApiError.empty();
                $dobValidationError.empty();
                $formValidationError.addClass('dn');

                pc.loyalty.showLoad();

                // Validate required form fields
                var isValid = true;
                var isDateValid = true;
                if (pc.formValidate !== undefined) {
                    $form.find("[data-form-field][required]").each(function () {
                        if (this.required || this.value !== "") {
                            if (pc.formValidate(this).isValid === false) {
                                isValid = false;
                                if (pc.formValidate(this).isDateValid === false) {
                                    isDateValid = false;
                                }
                                return;
                            }
                        }
                    });
                }

                if (isValid === false) {

                    //Show form fields errors
                    pc.loyalty.hideLoad();
                    $formValidationError.removeClass('dn');
                    //if (isDateValid === false) {
                    //    $dobValidationError.html('<p>Invalid Date Of Birth</p>');
                    //}

                    // scroll the page to the first error
                    var invalidFields = document.getElementsByClassName('invalid'),
                        invalidFirst = invalidFields[0],
                        $invalidFirst = $(invalidFirst),
                        navbar = $('.header'),
                        navbarHeight = navbar.height(),
                        elementOffset = $invalidFirst.offset().top - navbarHeight;

                    //remove the previous click handler to prevent scroll issues
                    $('[data-validation-error]').off("click");

                    $('[data-validation-error]').on('click', function (e) {
                        e.preventDefault();
                        $('html, body').animate({
                            scrollTop: elementOffset + "px"
                        },
                            500,
                            "linear");
                    });
                    return false;
                }

                // captcha response - uncomment once captcha funcionality in place
                //if (pc.captcha.hasCaptchaResponse())
                //{
                // Build the json data from the form fields
                var selectedGenres = $("input[id^=LoyaltyDetails-PreferredGenres]:checked")
                    .map(function (i, e) { return $(e).val(); }).toArray();
                var selectedLocations = $("input[id^=LoyaltyDetails-PreferredCinemaList]:checked")
                    .map(function (i, e) { return $(e).val(); }).toArray();
                var jsonData = {
                    'LoyaltyCreateMember': {
                        //"StackNodeId": $('[data-stack-node-id]'),
                        'FirstName': $("#LoyaltyDetails-FirstName").val(),
                        'LastName': $("#LoyaltyDetails-LastName").val(),
                        'Address1': $("#LoyaltyDetails-AddressLine1").val(),
                        'Address2': $("#LoyaltyDetails-AddressLine2").val(),
                        'City': $("#LoyaltyDetails-City").val(),
                        'State': $("#LoyaltyDetails-State").val(),
                        'ZipCode': $("#LoyaltyDetails-Zip").val(),
                        'Email': $("#LoyaltyDetails-Email").val(),
                        'PhoneNumber': $("#LoyaltyDetails-PhoneNumber").val(),
                        'MobileNumber': $("#LoyaltyDetails-MobileNumber").val(),
                        'MaritalStatus': $("#LoyaltyDetails-MaritalStatus").val(),
                        'NewsletterFrequency': $("#LoyaltyDetails-NewsletterFrequency").val(),
                        'DateOfBirth': null,
                        'Gender': $("#LoyaltyDetails-Gender").val(),
                        'Username': $("#LoyaltyDetails-Username").val(),
                        'Password': $("#LoyaltyDetails-Password").val(),
                        'ContactByThirdParty': null,
                        'SendNewsletter': null,
                        'PreferredGenres': selectedGenres,
                        'PreferredCinemaList': selectedLocations,
                        'PreferredCinemaId': $("#LoyaltyDetails-PreferredCinemaId").val(),
                        'HouseSize': $("#LoyaltyDetails-HouseSize").val()
                        //'CaptchaResponse': pc.captcha.response
                    }
                };

                if ($("#LoyaltyDetails-DOB-Day").val() !== "-1") {
                    jsonData.LoyaltyCreateMember.DateOfBirth = $("#LoyaltyDetails-DOB-Year").val() +
                        "-" +
                        $("#LoyaltyDetails-DOB-Month").val() +
                        "-" +
                        $("#LoyaltyDetails-DOB-Day").val() +
                        "T00:00:00";
                }

                if ($("#LoyaltyDetails-ContactByThirdParty").is(":checked")) {
                    jsonData.LoyaltyCreateMember.ContactByThirdParty = false;
                } else {
                    jsonData.LoyaltyCreateMember.ContactByThirdParty = true;
                }

                if ($("#LoyaltyDetails-SendNewsletter").is(":checked")) {
                    jsonData.LoyaltyCreateMember.SendNewsletter = false;
                }
                else {
                    jsonData.LoyaltyCreateMember.SendNewsletter = true;
                }

                // Call the umbraco loyalty create method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.LoyaltyCreateMember),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (data !== null && data !== undefined) {
                            if (data.ResultCode === 0) {
                                // Login the registered user

                                // Build the json data from the form fields
                                var jsonData = {
                                    'LoyaltyLogin': {
                                        'Username': $("#LoyaltyDetails-Username").val(),
                                        'Password': $("#LoyaltyDetails-Password").val()
                                    }
                                };

                                // Call the umbraco loyalty api login method.
                                $.ajax({
                                    url: pc.loyalty.loginApi,
                                    type: "POST",
                                    dataType: "json",
                                    data: JSON.stringify(jsonData.LoyaltyLogin),
                                    contentType: "application/json; charset=utf-8"
                                })
                                    .always(function (data) {
                                        if (data !== null && typeof data !== "undefined" && data.ResultCode === 0) {
                                            window.location = pc.loyalty.loginLandingUrl;
                                        } else {
                                            // Always display the general error if the code get here
                                            $formValidationError.removeClass("dn");
                                            pc.loyalty.hideLoad();
                                        }
                                    });
                            } else {
                                // Display the API error message
                                $formApiError.html("<p>" + data.ResultMessage + "</p>");
                                pc.loyalty.hideLoad();
                            }
                        }
                    })
                    .fail(function (jqXhr, status, err) {
                        // uncomment when captcha functionality in place
                        //grecaptcha.reset();

                        // Always display the general error if the code get here
                        $formValidationError.removeClass("dn");
                        pc.loyalty.hideLoad();
                    });
                // captcha response end - uncomment when captcha functionality in place
                //}
                //else
                //{
                //    pc.loyalty.hideLoad();
                //    return false;
                //}
            });
    };

    loyaltyRegister.Setup();

})(jQuery);

// Rewards Update Page
(function ($) {

    var $loyaltyUpdate = $("[data-loyalty-update]");
    if ($loyaltyUpdate.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyUpdate"]'),
        $formApiError = $("[data-api-error]"),
        $dobValidationError = $("[data-dob-error]"),
        $formValidationError = $("[data-validation-error]"),
        $formSuccess = $('[data-loyalty-success="LoyaltyUpdate"]'),
        loyaltyUpdate = {};

    loyaltyUpdate.Setup = function () {
        // Get the full member details and populate the form
        $.post(pc.loyalty.getMemberApi +
            "?userSessionId=" +
            pc.loyalty.userSessionId +
            "&includeTransactionHistory=false")
            .always(function (data) {
                if (data !== null && typeof data !== "undefined" && typeof data.Data.MemberDetails !== "undefined") {

                    if (data.Data.MemberDetails.FirstName !== null &&
                        typeof data.Data.MemberDetails.FirstName !== "undefined") {
                        $("#LoyaltyDetails-FirstName").val(data.Data.MemberDetails.FirstName);
                    }

                    if (data.Data.MemberDetails.LastName !== null &&
                        typeof data.Data.MemberDetails.LastName !== "undefined") {
                        $("#LoyaltyDetails-LastName").val(data.Data.MemberDetails.LastName);
                    }

                    // Populate DOB
                    if (data.Data.MemberDetails.DateOfBirth !== null &&
                        typeof data.Data.MemberDetails.DateOfBirth !== "undefined") {
                        var dobSplit = data.Data.MemberDetails.DateOfBirth.split("-");
                        var dobYear = dobSplit[0];
                        var dobMonth = dobSplit[1].substring(0, 2);
                        var dobDay = dobSplit[2].substring(0, 2);

                        $('#LoyaltyDetails-DOB-Day option[value="' + dobDay + '"]').prop("selected", true);
                        $('#LoyaltyDetails-DOB-Month option[value="' + dobMonth + '"]').prop("selected", true);
                        $('#LoyaltyDetails-DOB-Year option[value="' + dobYear + '"]').prop("selected", true);
                    }

                    // Populate gender
                    if (data.Data.MemberDetails.Gender !== null &&
                        typeof data.Data.MemberDetails.Gender !== "undefined") {
                        $('#LoyaltyDetails-Gender option[value="' + data.Data.MemberDetails.Gender + '"]')
                            .prop("selected", true);
                    }

                    if (data.Data.MemberDetails.MaritalStatus !== null &&
                        typeof data.Data.MemberDetails.MaritalStatus !== "undefined") {
                        $('#LoyaltyDetails-MaritalStatus option[value="' + data.Data.MemberDetails.MaritalStatus + '"]')
                            .prop("selected", true);
                    }

                    if (data.Data.MemberDetails.HouseSize !== null &&
                        typeof data.Data.MemberDetails.HouseSize !== "undefined") {
                        $('#LoyaltyDetails-HouseSize option[value="' + data.Data.MemberDetails.HouseSize + '"]')
                            .prop("selected", true);
                    }

                    if (data.Data.MemberDetails.Gender !== null &&
                        typeof data.Data.MemberDetails.Gender !== "undefined") {
                        $('#LoyaltyDetails-Gender option[value="' + data.Data.MemberDetails.Gender + '"]')
                            .prop("selected", true);
                    }

                    // Populate preferred location
                    if (data.Data.MemberDetails.PreferredCinemaId !== null &&
                        typeof data.Data.MemberDetails.PreferredCinemaId !== "undefined") {
                        $('#LoyaltyDetails-PreferredCinemaId option[value="' +
                            data.Data.MemberDetails.PreferredCinemaId +
                            '"]').prop("selected", true);
                    }

                    if (data.Data.MemberDetails.EmailAddress !== null &&
                        typeof data.Data.MemberDetails.EmailAddress !== "undefined") {
                        $("#LoyaltyDetails-Email").val(data.Data.MemberDetails.EmailAddress);
                    }

                    if (data.Data.MemberDetails.PhoneNumber !== null &&
                        typeof data.Data.MemberDetails.PhoneNumber !== "undefined") {
                        $("#LoyaltyDetails-PhoneNumber").val(data.Data.MemberDetails.PhoneNumber);
                    }

                    if (data.Data.MemberDetails.MobileNumber !== null &&
                        typeof data.Data.MemberDetails.MobileNumber !== "undefined") {
                        $("#LoyaltyDetails-MobileNumber").val(data.Data.MemberDetails.MobileNumber);
                    }

                    if (data.Data.MemberDetails.Address1 !== null &&
                        typeof data.Data.MemberDetails.Address1 !== "undefined") {
                        $("#LoyaltyDetails-AddressLine1").val(data.Data.MemberDetails.Address1);
                    }

                    if (data.Data.MemberDetails.Address2 !== null &&
                        typeof data.Data.MemberDetails.Address2 !== "undefined") {
                        $("#LoyaltyDetails-AddressLine2").val(data.Data.MemberDetails.Address2);
                    }

                    if (data.Data.MemberDetails.City !== null && typeof data.Data.MemberDetails.City !== "undefined") {
                        $("#LoyaltyDetails-City").val(data.Data.MemberDetails.City);
                    }

                    if (data.Data.MemberDetails.State !== null &&
                        typeof data.Data.MemberDetails.State !== "undefined") {
                        $("#LoyaltyDetails-State").val(data.Data.MemberDetails.State);
                    }

                    if (data.Data.MemberDetails.ZipCode !== null &&
                        typeof data.Data.MemberDetails.ZipCode !== "undefined") {
                        $("#LoyaltyDetails-Zip").val(data.Data.MemberDetails.ZipCode);
                    }

                    // Populate SendNewsletter
                    if (data.Data.MemberDetails.SendNewsletter !== null &&
                        typeof data.Data.MemberDetails.SendNewsletter !== "undefined" &&
                        !data.Data.MemberDetails.SendNewsletter) {
                        $("#LoyaltyDetails-SendNewsletter").prop("checked", true);
                    }

                    // Populate NewsletterFrequency
                    if (data.Data.MemberDetails.NewsletterFrequency !== null &&
                        typeof data.Data.MemberDetails.NewsletterFrequency !== "undefined") {
                        $("#LoyaltyDetails-NewsletterFrequency").val(data.Data.MemberDetails.NewsletterFrequency);
                    }

                    // Populate ContactByThirdParty
                    if (data.Data.MemberDetails.ContactByThirdParty !== null &&
                        typeof data.Data.MemberDetails.ContactByThirdParty !== "undefined" &&
                        !data.Data.MemberDetails.ContactByThirdParty) {
                        $("#LoyaltyDetails-ContactByThirdParty")
                            .prop("checked", true);
                    }

                    // Populate PreferredGenres
                    if (data.Data.MemberDetails.PreferredCinemaList !== null &&
                        typeof data.Data.MemberDetails.PreferredCinemaList !== "undefined" &&
                        data.Data.MemberDetails.PreferredCinemaList.length > 0) {
                        $.each(data.Data.MemberDetails.PreferredCinemaList,
                            function (i, val) {
                                $("#LoyaltyDetails-PreferredCinemaList\\[" + val + "\\]")
                                    .prop("checked", data.Data.MemberDetails.PreferredCinemaList);
                            });
                    }

                    // Populate PreferredGenres
                    if (data.Data.MemberDetails.PreferredGenres !== null &&
                        typeof data.Data.MemberDetails.PreferredGenres !== "undefined" &&
                        data.Data.MemberDetails.PreferredGenres.length > 0) {
                        $.each(data.Data.MemberDetails.PreferredGenres,
                            function (i, val) {
                                $("#LoyaltyDetails-PreferredGenres\\[" + val + "\\]")
                                    .prop("checked", data.Data.MemberDetails.PreferredGenres);
                            });
                    }

                    //hide newsletter frequency 
                    if ((data.Data.MemberDetails.SendNewsletter !== null &&
                        typeof data.Data.MemberDetails.SendNewsletter !== "undefined" &&
                        !data.Data.MemberDetails.SendNewsletter) &&
                        (data.Data.MemberDetails.ContactByThirdParty !== null &&
                            typeof data.Data.MemberDetails.ContactByThirdParty !== "undefined" &&
                            !data.Data.MemberDetails.ContactByThirdParty)) {
                        $('[data-loyalty-newsletterfrequency-element]').addClass('dn');
                    }
                }

            });

        $form.on("submit",
            function (e) {
                e.preventDefault();

                $formApiError.empty();
                $dobValidationError.empty();
                $formValidationError.addClass('dn');

                pc.loyalty.showLoad();

                // Validate required form fields
                var isValid = true;
                var isDateValid = true;
                if (typeof pc.formValidate !== "undefined") {
                    $form.find("[data-form-field][required]").each(function () {
                        if (this.required || this.value !== "") {
                            if (pc.formValidate(this).isValid === false) {
                                isValid = false;
                                if (pc.formValidate(this).isDateValid === false) {
                                    isDateValid = false;
                                }
                                return;
                            }
                        }
                    });
                }

                if (isValid === false) {
                    //Show form fields errors
                    pc.loyalty.hideLoad();
                    $formValidationError.removeClass('dn');
                    //if (isDateValid === false) {
                    //    $dobValidationError.html('<p>Invalid Date Of Birth</p>');
                    //}

                    // scroll the page to the first error
                    var invalidFields = document.getElementsByClassName('invalid');
                    var invalidFirst = invalidFields[0];
                    var $invalidFirst = $(invalidFirst);
                    var navbar = $('.header');
                    var navbarHeight = navbar.height();
                    var elementOffset = $invalidFirst.offset().top - navbarHeight;

                    //remove the previous click handler to prevent scroll issues
                    $('[data-validation-error]').off("click");

                    $('[data-validation-error]').on('click', function (e) {
                        e.preventDefault();
                        $('html, body').animate({
                            scrollTop: elementOffset + "px"
                        },
                            500,
                            "linear");
                    });

                    return false;
                }

                // uncomment once captcha in place
                //if (pc.captcha.hasCaptchaResponse())
                //{

                // Build the json data from the form fields
                var selectedGenres = $("input[id^=LoyaltyDetails-PreferredGenres]:checked")
                    .map(function (i, e) { return $(e).val(); }).toArray();
                var selectedLocations = $("input[id^=LoyaltyDetails-PreferredCinemaList]:checked")
                    .map(function (i, e) { return $(e).val(); }).toArray();
                var jsonData = {
                    'MemberDetailsRequest': {
                        'MemberId': $("#LoyaltyDetails-MemberId").val(),
                        'UserSessionId': pc.loyalty.userSessionId,
                        'FirstName': $("#LoyaltyDetails-FirstName").val(),
                        'LastName': $("#LoyaltyDetails-LastName").val(),
                        'Address1': $("#LoyaltyDetails-AddressLine1").val(),
                        'Address2': $("#LoyaltyDetails-AddressLine2").val(),
                        'City': $("#LoyaltyDetails-City").val(),
                        'State': $("#LoyaltyDetails-State").val(),
                        'ZipCode': $("#LoyaltyDetails-Zip").val(),
                        'Email': $("#LoyaltyDetails-Email").val(),
                        'PhoneNumber': $("#LoyaltyDetails-PhoneNumber").val(),
                        'MobileNumber': $("#LoyaltyDetails-MobileNumber").val(),
                        'MaritalStatus': $("#LoyaltyDetails-MaritalStatus").val(),
                        'NewsletterFrequency': $("#LoyaltyDetails-NewsletterFrequency").val(),
                        'DateOfBirth': null,
                        'Gender': $("#LoyaltyDetails-Gender").val(),
                        'ContactByThirdParty': null,
                        'SendNewsletter': null,
                        'PreferredCinemaList': selectedLocations,
                        'PreferredCinemaId': $("#LoyaltyDetails-PreferredCinemaId").val(),
                        'HouseSize ': $("#LoyaltyDetails-HouseSize").val(),
                        'PreferredGenres': selectedGenres
                        //'CaptchaResponse': pc.captcha.response
                    }
                };



                if ($("#LoyaltyDetails-DOB-Day").val() !== "-1") {
                    jsonData.MemberDetailsRequest.DateOfBirth = $("#LoyaltyDetails-DOB-Year").val() +
                        "-" +
                        $("#LoyaltyDetails-DOB-Month").val() +
                        "-" +
                        $("#LoyaltyDetails-DOB-Day").val() +
                        "T00:00:00";
                }

                if ($("#LoyaltyDetails-ContactByThirdParty").is(":checked")) {
                    jsonData.MemberDetailsRequest.ContactByThirdParty = false;
                } else {
                    jsonData.MemberDetailsRequest.ContactByThirdParty = true;
                }

                if ($("#LoyaltyDetails-SendNewsletter").is(":checked")) {
                    jsonData.MemberDetailsRequest.SendNewsletter = false;
                }
                else {
                    jsonData.MemberDetailsRequest.SendNewsletter = true;
                }

                // Call the umbraco loyalty create method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.MemberDetailsRequest),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (data !== null && typeof data !== "undefined") {
                            if (data.ResultCode === 0) {
                                $form.addClass("dn");
                                $formSuccess.removeClass("dn");
                                $(document).scrollTop(0);
                                pc.loyalty.hideLoad();
                            } else {
                                // Always display the general error if the code get here
                                $formApiError.html("<p>" + data.ResultMessage + "</p>");
                                pc.loyalty.hideLoad();
                            }
                        } else {
                            // Display the API error message
                            $formApiError.html("<p>" + data.ResultMessage + "</p>");
                            pc.loyalty.hideLoad();
                        }
                    })
                    .fail(function (jqXhr, status, err) {

                        //grecaptcha.reset();

                        // Always display the general error if the code get here
                        $formApiError.html("<p>" + data.ResultMessage + "</p>");
                        pc.loyalty.hideLoad();
                    });
                // end captcha
                //}
                //else
                //{
                //    return false;
                //}
            });
    };

    loyaltyUpdate.Setup();

})(jQuery);

// Transaction History page
(function ($) {

    if ($('[data-loyalty-transaction-history]').length === 0) {
        return;
    }

    var transactionHistory = {};

    transactionHistory.Setup = function () {
        // Get the Full Member Details including Transaction History
        $.post(pc.loyalty.getMemberApi +
            '?userSessionId=' +
            pc.loyalty.userSessionId +
            '&includeTransactionHistory=true')
            .always(function (data) {
                if (data !== null && typeof data !== 'undefined') {

                    var transTemplate = $('#transactionItem').html();
                    var transContent = $('[data-loyalty-transaction-history]');

                    if (data.Data.MemberDetails.PointsHistory.TransactionHistory !== null &&
                        typeof data.Data.MemberDetails.PointsHistory.TransactionHistory !== 'undefined' &&
                        data.Data.MemberDetails.PointsHistory.TransactionHistory.length > 0) {

                        var transactions = [];

                        $.each(data.Data.MemberDetails.PointsHistory.TransactionHistory,
                            function (k, v) {
                                var lineItemsArr = [];
                                if (v.LineItems.length > 0) {
                                    $.each(v.LineItems,
                                        function (l, w) {
                                            var sessDateFormat = v.TransactionDate.split('T')[0];
                                            var transactionDate = sessDateFormat.split('-');
                                            var day = transactionDate[2];
                                            var month = transactionDate[1];
                                            var year = transactionDate[0];

                                            transactionDate = month + "/" + day + "/" + year;

                                            var tran = {
                                                sessionDate: transactionDate
                                            };

                                            if (w.SessionTime === null) {
                                                tran.Desc = w.Description;
                                            } else {
                                                tran.Desc = w.Film;
                                            }
                                            tran.Value = w.Amount;
                                            tran.Points = w.PointsAdjustment;
                                            lineItemsArr.push(tran);
                                        });
                                    $(".transactionsTable tfoot").css("display", "table-footer-group");
                                }
                                transactions.push(lineItemsArr);
                            });

                        transContent.html(Mustache.render(transTemplate, transactions));


                        //Pagination
                        var pageSize = 10;
                        var pageCount = $(".transaction-row").length / pageSize;

                        for (var i = 0; i < pageCount; i++) {

                            $("#numbers").append('<li><a href="#">' + (i + 1) + '</a></li> ');
                        }

                        $("#numbers li").first().find("a").addClass("active");

                        var showPage = function (page) {
                            $(".transaction-row").hide();
                            $(".transaction-row").each(function (n) {
                                if (n >= pageSize * (page - 1) && n < pageSize * page)
                                    $(this).show();
                            });
                        };

                        showPage(1);

                        $("#numbers li a").click(function (e) {
                            e.preventDefault();

                            $("#numbers li a").removeClass("active");
                            $(this).addClass("active");
                            showPage(parseInt($(this).text()));
                        });

                    } else {
                        transContent.html(
                            "<tr class=\"no-transactions\"><td colspan=\"4\"><h5>No transactions.</h5></td></tr>");

                    }
                }

            });
    };
    transactionHistory.Setup();

})(jQuery);

// Update Password Page
(function ($) {

    var $loyaltyUpdatePassword = $("[data-loyalty-update-password]");
    if ($loyaltyUpdatePassword.length === 0) {
        return;
    }

    var $form = $('[data-form="LoyaltyUpdatePassword"]'),
        loyaltyUpdatePassword = {},
        $formApiError = $("[data-api-error]"),
        $formValidationError = $("[data-validation-error]"),
        passwordSuccess = $('[data-loyalty-success="PasswordUpdate"]');

    loyaltyUpdatePassword.Setup = function () {
        $form.on("submit",
            function (e) {
                e.preventDefault();

                $formApiError.empty();
                $formValidationError.addClass('dn');

                pc.loyalty.showLoad();

                // Validate required form fields
                var isValid = true;
                if (typeof pc.formValidate !== "undefined") {
                    $form.find("[data-form-field]").each(function () {
                        if (this.required || this.value !== "") {
                            if (pc.formValidate(this).isValid === false) {
                                isValid = false;
                                return;
                            }
                        }
                    });
                }

                if (isValid === false) {
                    //Show form fields errors
                    pc.loyalty.hideLoad();
                    $formValidationError.removeClass('dn');
                    return false;
                }

                // Build the json data from the form fields
                var jsonData = {
                    'LoyaltyUpdatePassword': {
                        'MemberId': $("#LoyaltyDetails-MemberId").val(),
                        'UserSessionId': pc.loyalty.userSessionId,
                        //'Username': $('#LoyaltyDetails-Username').val(),
                        // use email as a username
                        'Username': pc.loyalty.username,
                        'OldPassword': $("#LoyaltyDetails-OldPassword").val(),
                        'Password': $("#LoyaltyDetails-Password").val()
                    }
                };

                // Call the umbraco loyalty create method
                $.ajax({
                    url: this.action,
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify(jsonData.LoyaltyUpdatePassword),
                    contentType: "application/json; charset=utf-8"
                })
                    .done(function (data) {
                        if (data !== null && typeof data !== "undefined") {
                            if (data.ResultCode === 0) {
                                $form.addClass("dn");
                                passwordSuccess.removeClass("dn");
                                $(document).scrollTop(0);
                                pc.loyalty.hideLoad();
                            } else {
                                // Display the API error message
                                $formApiError.html("<p>" + data.ResultMessage + "</p>");
                                pc.loyalty.hideLoad();
                            }
                        }
                    })
                    .fail(function (jqXhr, status, err) {
                        // Always display the general error if the code get here
                        $formValidationError.removeClass("dn");
                        pc.loyalty.hideLoad();
                        return;
                    });
            });
    };

    loyaltyUpdatePassword.Setup();

})(jQuery);

(function ($) {
    var $fields = $('[data-loyalty-newsletterfrequency-field]');
    var $element = $('[data-loyalty-newsletterfrequency-element]');

    if ($fields.length === 0 || $element.length === 0) {
        return;
    }

    $fields.on('change', function () {
        var counter = $fields.filter(function () {
            return this.checked;
        }).length;

        if (counter === $fields.length) {
            $element.addClass('dn');
            $element.find('input').prop('required', false);
        }
        else {
            $element.removeClass('dn');
            $element.find('input').prop('required', true);
        }
    });
})(jQuery);;
var pc = pc || {};

(function ($) {
    var $form = $('[data-form="LoyaltyRegisterInStore"]');

    if ($form.length === 0) {
        return;
    }

    var $formApiError = $('[data-api-error]');
    var $formValidationError = $('[data-validation-error]');

    $form.on('submit', function (e) {
        e.preventDefault();

        $formApiError.empty().addClass('dn');
        $formValidationError.addClass('dn');

        if (typeof pc.loyalty !== 'undefined') {
            pc.loyalty.showLoad();
        }

        var isValid = true;

        if (typeof pc.formValidate !== 'undefined') {
            $form.find('[data-form-field][required]').each(function () {
                if (this.required || this.value !== "") {
                    if (pc.formValidate(this).isValid === false) {
                        isValid = false;
                        if (pc.formValidate(this).isDateValid === false) {
                            isDateValid = false;
                        }
                        return;
                    }
                }
            });
        }

        if (isValid === false) {
            if (typeof pc.loyalty !== 'undefined') {
                pc.loyalty.hideLoad();
            }

            $formValidationError.removeClass('dn');

            return false;
        }

        $.ajax({
            url: '/Umbraco/Api/LoyaltyApi/SearchMember',
            type: "POST",
            dataType: "json",
            data: JSON.stringify({
                Username: $("#LoyaltyDetails-PhoneNumber").val(),
                Email: $("#LoyaltyDetails-Email").val()
            }),
            contentType: "application/json; charset=utf-8"
        }).always(function (searchResponse) {
            //console.log(searchResponse);

            if (typeof searchResponse !== 'undefined' && searchResponse !== null) {
                if (searchResponse.ResultCode === 0) {
                    $.ajax({
                        url: '/Umbraco/Api/LoyaltyApi/RefreshPartialSignedUpMember',
                        type: "POST",
                        dataType: "json",
                        data: JSON.stringify({
                            MemberId: searchResponse.Data.MemberId,
                            Email: $("#LoyaltyDetails-Email").val()
                        }),
                        contentType: "application/json; charset=utf-8"
                    }).always(function (memberResponse) {
                        //console.log(memberResponse);

                        if (typeof memberResponse !== 'undefined' && memberResponse !== null) {
                            if (
                                memberResponse.ResultCode === 0 &&
                                typeof memberResponse.Data !== 'undefined' &&
                                memberResponse.Data !== null &&
                                typeof memberResponse.Data.MemberDetails !== 'undefined' &&
                                memberResponse.Data.MemberDetails !== null
                            ) {
                                memberResponse.Data.MemberDetails.ZipCode = $("#LoyaltyDetails-Zip").val();
                                memberResponse.Data.MemberDetails.Email = $("#LoyaltyDetails-Email").val();
                                memberResponse.Data.MemberDetails.UserName = $("#LoyaltyDetails-PhoneNumberLogin").val();
                                memberResponse.Data.MemberDetails.PhoneNumber = $("#LoyaltyDetails-PhoneNumberLogin").val();
                                memberResponse.Data.MemberDetails.Password = $("#LoyaltyDetails-Password").val();

                                $.ajax({
                                    url: '/Umbraco/Api/LoyaltyApi/ActivateInStoreMember',
                                    type: "POST",
                                    dataType: "json",
                                    data: JSON.stringify(memberResponse.Data.MemberDetails),
                                    contentType: "application/json; charset=utf-8"
                                }).always(function (activateResponse) {
                                    if (typeof activateResponse !== 'undefined' && activateResponse !== null) {
                                        if (activateResponse.ResultCode === 0) {
                                            window.location = pc.loyalty.loginLandingUrl;
                                        }
                                        else {
                                            $formApiError.html("<p>" + activateResponse.ResultMessage + "</p>").removeClass('dn');
                                            if (typeof pc.loyalty !== 'undefined') {
                                                pc.loyalty.hideLoad();
                                            }
                                        }
                                    }
                                });
                            }
                            else {
                                $formApiError.html("<p>" + memberResponse.ResultMessage + "</p>").removeClass('dn');
                                if (typeof pc.loyalty !== 'undefined') {
                                    pc.loyalty.hideLoad();
                                }
                            }
                        }
                    });
                }
                else {
                    $formApiError.html("<p>" + searchResponse.ResultMessage + "</p>").removeClass('dn');
                    if (typeof pc.loyalty !== 'undefined') {
                        pc.loyalty.hideLoad();
                    }
                }
            }
        });
    });


})(jQuery);;
(function ($) {
    $(document).ready(function () {
        var navTrigger = $('#nav-trigger'),
            navMenu = $('#menu'),
            subnavTrigger = $('.site-menu__item .nav-btn[aria-expanded]'),
            searchTrigger = $('#search-trigger'),
            searchBox = $('.search-box'),
            quickbuyTrigger = $('#quickbuy-trigger'),
            quickbuyElement = $('#quickBookAppId'),
            loyaltyTrigger = $('#loyalty-trigger'),
            loyaltyElement = $('#loyaltyOverlay');

        navTrigger.on("click", function (e) {
            if ($(this).attr("aria-expanded") === "true") {
                subnavTrigger.attr("aria-expanded", false);
            }
            searchTrigger.attr("aria-expanded", false);
            searchBox.removeClass("is-open");
            quickbuyElement.removeClass("is-open");
            quickbuyTrigger.attr("aria-expanded", false);
            loyaltyElement.removeClass("is-open");
            loyaltyTrigger.attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
            navMenu.toggleClass("is-open");
        });

        subnavTrigger.on("click", function (e) {
            e.stopPropagation();
            e.preventDefault();
            searchTrigger.attr("aria-expanded", false);
            searchBox.removeClass("is-open");
            quickbuyElement.removeClass("is-open");
            quickbuyTrigger.attr("aria-expanded", false);
            loyaltyElement.removeClass("is-open");
            loyaltyTrigger.attr("aria-expanded", false);
            subnavTrigger.not(this).attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
        });

        searchTrigger.on("click", function (e) {
            e.stopPropagation();
            e.preventDefault();
            navTrigger.attr("aria-expanded", false);
            navMenu.removeClass("is-open");
            quickbuyElement.removeClass("is-open");
            quickbuyTrigger.attr("aria-expanded", false);
            subnavTrigger.attr("aria-expanded", false);
            loyaltyElement.removeClass("is-open");
            loyaltyTrigger.attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
            searchBox.toggleClass("is-open");
        });

        quickbuyTrigger.on("click", function (e) {
            e.stopPropagation();
            e.preventDefault();
            document.body.addEventListener('click', overlayClose, false);
            navTrigger.attr("aria-expanded", false);
            searchTrigger.attr("aria-expanded", false);
            searchBox.removeClass("is-open");
            navMenu.removeClass("is-open");
            subnavTrigger.attr("aria-expanded", false);
            loyaltyElement.removeClass("is-open");
            loyaltyTrigger.attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
            quickbuyElement.toggleClass("is-open");
        });

        loyaltyTrigger.on("click", function (e) {
            e.stopPropagation();
            e.preventDefault();
            document.body.addEventListener('click', overlayClose, false);
            navTrigger.attr("aria-expanded", false);
            searchTrigger.attr("aria-expanded", false);
            searchBox.removeClass("is-open");
            navMenu.removeClass("is-open");
            subnavTrigger.attr("aria-expanded", false);
            quickbuyElement.removeClass("is-open");
            quickbuyTrigger.attr("aria-expanded", false);
            $(this).attr("aria-expanded", $(this).attr("aria-expanded") === "true" ? false : true);
            loyaltyElement.toggleClass("is-open");
        });

        $('html').on("click", function () {
            subnavTrigger.attr("aria-expanded", false);
        });

        function overlayClose(e) {
            let isClosed = false;
            if (!$(e.target).closest('#loyaltyOverlay').length && loyaltyElement.hasClass("is-open")) {
                loyaltyElement.removeClass("is-open");
                loyaltyTrigger.attr("aria-expanded", false);
                isClosed = true;
            }

            if (!$(e.target).closest('#quickBookAppId').length && quickbuyElement.hasClass("is-open")) {
                quickbuyElement.removeClass("is-open");
                quickbuyTrigger.attr("aria-expanded", false);
                isClosed = true;
            }

            if (isClosed) {
                document.body.removeEventListener('click', overlayClose, false);
            }
        }
    });
})(jQuery);;
(function ($) {

    $(document).ready(function () {
        //equalHeight('.promo-banner__content');
        //// Fix heights on window resize
        //var iv = null;
        //$(window).resize(function () {

        //    if (iv !== null) {
        //        window.clearTimeout(iv);
        //    }

        //    // Needs to be a timeout function so it doesn't fire every ms of resize
        //    iv = setTimeout(function () {
        //        equalHeight('.promo-banner__content');
        //    }, 120);
        //});
            $('.image-gallery').flickity({
                cellAlign: 'center',
                wrapAround: true,
                pageDots: true,
                prevNextButtons: true,
                freeScroll: true,
                resize: true,
                imagesLoaded: true
            });
    });
})(jQuery);;
var pc = pc || {};

(function ($) {
    var $formRefund = $('[data-form="Refund"]');

    if ($formRefund.length === 0) {
        return;
    }
    
    // Handle Refund Form
    var $formSuccess = $('[data-refund-success]'),
        $formGeneralError = $('[data-refund-error="GeneralError"]');

    var clearValidationMarkers = function () {
        $formGeneralError.addClass("dn");
    };

    $formRefund.on('submit', function (e) {
        e.preventDefault();
        clearValidationMarkers();

        // Validate
        if (typeof pc.formValidate !== 'undefined') {
            $formRefund.find('[data-form-field]').each(function () {
                if (this.hasAttribute('required') || (this.value !== '' && this.value !== '-1')) {
                    pc.formValidate(this).isValid;
                }
            });
        }

        if ($formRefund.find('.invalid').length > 0) {
            return false;
        }

        var refundOrderRequest = {
            "CinemaId": $('#BookingRefund-CinemaID').val(),
            "EmailAddress": $('#BookingRefund-Email').val(),
            "ProviderOrderReference": $('#BookingRefund-Reference').val()
        };

        $.ajax({
            url: this.action,
            type: 'POST',
            dataType: 'json',
            data: JSON.stringify(refundOrderRequest),
            contentType: 'application/json; charset=utf-8'
        }).done(function (data) {
            if (data.Data.Result === 0) {
                $formGeneralError.addClass("dn");
                $formRefund.addClass("dn");
                $formSuccess.removeClass("dn");
            } else {
                $formGeneralError.removeClass("dn");
            }
        }).fail(function (data) {
            // Unknown/Generic error
            $formGeneralError.removeClass("dn");
        });
    });
})(jQuery);;
(function ($) {
    var $cinemaFilter = $('[data-films-filter-cinema]');
    var cinemaId = $cinemaFilter.val();
    var hasCinemaID = !(cinemaId === '' || cinemaId === '0' || cinemaId === '-1');
    var filmInfoUrl = typeof pc.url !== 'undefined' && typeof pc.url.filminfo !== 'undefined' ? pc.url.filminfo : '';
    var tmpl = "{{#Result}}<li><a href=\"" + filmInfoUrl + "{{FriendlyName}}\">{{Title}}</a></li>{{/Result}}";

    $(function () {

        /* Fetch search results and display them */
        var updateTitleSearchResults = function (query, $results) {
            var url = pc.api.movie + 'TitleSearch/' + pc.circuit + (hasCinemaID ? '/' + cinemaId : '');
            $.get(url + '?q=' + encodeURIComponent(query), function (data) {
                $results.html(Mustache.render(tmpl, data));
            }).fail(function (jqXHR, textStatus, errorThrown) {
                $results.html('<li>No results</li>');
            });
        };

        /* Debounced event handler */
        var onTypeQuery = _.debounce(function (e) {
            var root = $(e.target).closest('.stackedTitleSearchForm');
            var $results = $(root).find('.titleSearchResults');
            var query = ($(e.target).val());
            if (query.length > 1) {
                updateTitleSearchResults(query, $results);
            } else {
                $results.html('');
            }
        }, 300, {
                leading: true,
                trailing: true,
                maxWait: 300
            }
        );

        /* Typing in the search box triggers the debounced event handler */
        $('.titleSearch').keyup(onTypeQuery);

    });
})(jQuery);
;
function AEJSReady(aeJS) {
    console.log("AEJSReady");
    //attach local handlers to events

    aeJS.settings['auth_window'] = true;

    aeJS.events.onLogin.addHandler(loginHandler);
}

//locally defined handlers
function loginHandler(user) {

    $.get(pc.loyalty.getMemberApi + '?userSessionId=' + pc.loyalty.userSessionId + '&includeTransactionHistory=false')
        .always(function (data) {
            var memberId = 0;

            if (data.MemberDetails.MemberId) {
                memberId = data.MemberDetails.MemberId;
            }

            var jsonData = {
                'SocialSigninData': {
                    'memberId': memberId,
                    'socialId': user.data.ID,
                    'service': user.services[0].Service
                }
            };

            $.get('/umbraco/Api/LoyaltyApi/SendSocialData?memberId=' + jsonData.SocialSigninData.memberId + '&socialId=' + jsonData.SocialSigninData.socialId + '&service=' + jsonData.SocialSigninData.service)
                .done(function (data) {
                    console.log('Call Success')
                    console.log(data)
                }).fail(function (jqXhr, status, err) {
                    console.log('Call Error')
                    console.log(err)
                }).always(function () {
                    //console.log("done")
                })
        });

}
;
var pc = pc || {};

(function () {

    // movio tracking
    pc.movioTrack = {};

    pc.movioTrack.abort = function (filmId) {
        // TrackAbortedTicketPurchase
        // track users who has dropped off the ticketing process within their session                     
        if (typeof mt !== 'undefined' && typeof pc.loyalty !== 'undefined' && pc.loyalty !== null && pc.loyalty.hasLogin === true)
        {

            if (typeof filmId === 'undefined') {
                return;
            }

            window.pcTrackAbortedPurchase = false;

            mt('send', 'TrackAbortedPurchase', { 'movieId': filmId, 'abortDateTime': new Date() }, function () {
                window.pcTrackAbortedPurchase = true;
            });

            var start = +new Date;
            while ((+new Date - start) < 2000 && window.pcTrackAbortedPurchase === false);
        }

    };

    function SetUserIdentity() {
        // SetUserIdentity
        if (typeof mt !== 'undefined' && pc.loyalty.hasLogin) {
            var memberId = pc.loyalty.memberId;

            mt('set', 'memberId', { 'id': memberId, 'hashed': true });
        }
    }

    SetUserIdentity();

    pc.movioTrack.login = function (isCheck) {
        // TrackMemberLogin
        // track when a user logs in

        //&& pc.loyalty.hasLogin - this was in the if, see if we need to readd
        if (typeof mt !== 'undefined' && docCookies.getItem('movioLogin') !== null) {
            mt('send', 'TrackMemberLogin', { 'loginDateTime': new Date() });
            docCookies.removeItem('movioLogin', '/');
        }
        else if (typeof isCheck === 'undefined' && pc.loyalty.hasLogin === false) {
            docCookies.setItem('movioLogin', 'true', null, '/');
        }
    };

    pc.movioTrack.login(true);

    pc.movioTrack.filminfo = function (filmId) {
        // TrackMovieDetail
        //Last condition is to ensure that we have stayed on the page for at least 5 seconds
        if (typeof mt !== 'undefined' ||
            typeof pc.loyalty === 'undefined' ||
            pc.loyalty === null ||
            pc.loyalty.hasLogin === false && typeof filmId !== 'undefined' && filmId !== null) {
            mt('send', 'TrackMovieDetail', { 'movieId': filmId, 'viewDuration': 5, 'viewDateTime': new Date() });
        }
    };

    function trackTrailer(video, filmId) {
        // TrackMovieTrailer
        // track users who have watched more than 75% of the trailer 

        if (
            typeof mt === 'undefined' ||
                typeof pc.loyalty === 'undefined' ||
                pc.loyalty === null ||
                pc.loyalty.hasLogin === false ||
                (typeof filmId === 'undefined' && typeof filmInfoData === 'undefined')
        ) {
            return;
        }

        if (typeof filmInfoData !== 'undefined' &&
            filmInfoData !== null) {
            filmId = filmInfoData.FilmCode;
        }
        var progress = (video.currentTime / video.duration) * 100;
        var targetProgress = 75;

        // progress might not always increase by 1
        if (progress >= targetProgress) {

            mt('send', 'TrackMovieTrailer', { 'movieId': filmId, 'viewDateTime': new Date(), 'progress': targetProgress });
        }
    }

    pc.movioTrack.trailerOn = function (video, filmId) {
        if (
            typeof video !== 'undefined' &&
                video !== null
        ) {
            video.addEventListener('timeupdate', trackTrailer(video, filmId));
        }
    };

    pc.movioTrack.trailerOff = function (video, filmId) {
        if (
            typeof video !== 'undefined' &&
                video !== null
        ) {
            video.removeEventListener('timeupdate', trackTrailer(video, filmId));
        }
    };

})();;

var pc = pc || {};

(function ($) {

    function createTrailer() {
        var $trailer = $('[data-trailer]'),
          template = $('#templateTrailerOverlay').html() || '';

        if ($trailer.length === 0 && template !== '') {
            $('body').append(template);

            $trailer = $('[data-trailer]');

            $trailer.on('click', function (e) {
                if (e.target === this) {
                    closeTrailer($trailer);
                }
            });

            $trailer.find('[data-trailer-close]').on('click', function (e) {
                e.preventDefault();
                closeTrailer($trailer);
            });
        }

        setupYT($trailer);
    }

    var filmCode = '';

    function closeTrailer($trailer) {

        if ($trailer.find('[data-trailer-video]:not(.dn)').length > 0) {
            if (
                typeof pc.movioTrack !== 'undefined' &&
                    pc.movioTrack !== null &&
                    typeof pc.movioTrack.trailerOff !== 'undefined' &&
                    pc.movioTrack.trailerOff !== null
            ) {
                pc.movioTrack.trailerOff($trailer.find('video[data-trailer-video]')[0], filmCode);
            }

            if (typeof _V_ !== 'undefined') {
                _V_('trailerVideo').destroy();
                $trailer.find('#trailerVideo').remove();

                if (typeof triggerEnd !== 'undefined') {
                    triggerEnd();
                }
            }
            else if (typeof videojs !== 'undefined') {
                videojs('trailerVideo').dispose();
            }
            else {
                $trailer.find('[data-trailer-video]').addClass('dn');
                $trailer.find('[data-trailer-video]')[0].pause();
                $trailer.find('[data-trailer-video]')[0].src = '';
            }
        }

        if ($trailer.find('[data-trailer-iframe]:not(.dn)').length > 0) {
            $trailer.find('[data-trailer-iframe]').attr('src', '').addClass('dn');
        }

        if (typeof _V_ !== 'undefined' && $trailer.find('#trailerVideo:not(.dn)').length > 0) {
            _V_('trailerVideo').destroy();
            $trailer.find('#trailerVideo').remove();

            if (typeof triggerEnd !== 'undefined') {
                triggerEnd();
            }
        }
        $trailer.removeClass('active');
        pc.enableScroll();
    }

    function openTrailer(button) {
        var $button = $(button),
            $trailer = $('[data-trailer]'),
            buttonHref = $button.attr('href') || $button.attr('data-trailer-btn');

        filmCode = $button.attr('filmCode');

        if (buttonHref.indexOf('mymovies') > -1 && buttonHref.indexOf('|') > 4 && typeof $button.attr('mm_options') === 'undefined') {
            // use mymovie video

            var videoItems = buttonHref.split('|') || [],
              videoSrc = [];

            if (videoItems.length > 5 && typeof _V_ !== 'undefined') {

                window.mid = videoItems[1];
                window.mti = videoItems[2];
                window.fid = videoItems[3];
                window.fti = videoItems[5];
                window.mtid = 'trl';
                window.pid = pc.myMoviesPartnerId || '';

                $.each(videoItems[0].split(','), function (index, value) {
                    var videoType = value.split('.').pop();

                    if (videoType.toLowerCase() === 'ogv') {
                        videoType = 'ogg';
                    }

                    videoSrc.push({
                        type: 'video/' + videoType,
                        src: value
                    });
                });

                if ($trailer.find('#trailerVideo').length === 0) {
                    $trailer.find('[data-trailer-content]').append('<video id="trailerVideo" class="video-js vjs-default-skin" controls data-trailer-video></video>');
                }

                // update video attribute for poster and show
                $trailer.find('[data-trailer-video]').attr({
                    'poster': videoItems[4]
                });

                // hook up to videojs
                _V_('trailerVideo').ready(function () {
                    var myPlayer = this;
                    myPlayer.src(videoSrc);
                    myPlayer.addEvent("play", triggerSDC);
                    myPlayer.addEvent("ended", triggerEnd);
                }).removeClass('dn');

            }
        }
        else if (buttonHref.indexOf('.mp4') > -1) {
            // mp4 file

            var testVideo = document.createElement('video');
            var videoSupported = false;

            if (testVideo.canPlayType && testVideo.canPlayType('video/mp4').replace(/no/, '')) {
                videoSupported = true;
            }

            if (videoSupported) {
                if ($trailer.find('#trailerVideo').length === 0) {
                    $trailer.find('[data-trailer-content]').append('<video id="trailerVideo" class="video-js vjs-default-skin" controls data-trailer-video></video>');
                }

                if (typeof videojs !== 'undefined') {
                    videojs('trailerVideo', null, function () {
                        this.src(buttonHref);
                        this.removeClass('dn');
                        this.play();
                        this.focus();
                        this.el_.querySelector('.vjs-play-control').focus();
                    });
                }
                else {
                    $trailer.find('[data-trailer-video]')[0].src = buttonHref;
                    $trailer.find('[data-trailer-video]').removeClass('dn');
                    $trailer.find('[data-trailer-video]')[0].play();
                    $trailer.find('[data-trailer-video]')[0].focus();
                }

                if (
                    typeof pc.movioTrack !== 'undefined' &&
                        pc.movioTrack !== null &&
                        typeof pc.movioTrack.trailerOn !== 'undefined' &&
                        pc.movioTrack.trailerOn !== null
                ) {
                    pc.movioTrack.trailerOn($trailer.find('video[data-trailer-video]')[0], filmCode);
                }
            }
            else {
                $trailer.find('.trailerContentFrame').addClass('dn');
                $trailer.find('.trailerNoSupport').removeClass('dn');
            }
        }
        else {
            // use iframe
            if (buttonHref.indexOf('youtu') > -1) {
                // check for youtube
                var ytID = buttonHref.replace(/.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/g, '$1');

                if (typeof pc.ytAPIReady !== 'undefined') {
                    var ytHref = '//www.youtube.com/embed/' + ytID + '?rel=0&autoplay=1&enablejsapi=1';

                    $trailer.find('[data-trailer-iframe]').attr('src', ytHref).removeClass('dn');

                    pc.ytPlayer = new YT.Player('trailerIframe', {
                        events: {
                            'onReady': pc.ytOnPlayerReady,
                            'onStateChange': pc.ytOnPlayerStateChange
                        }
                    });

                    buttonHref = ytHref;
                }
            }

            // show iframe
            if ((navigator.userAgent.indexOf("MSIE") != -1) || (!!document.documentMode == true)) //IF IE > 10
            {
                $('.trailer__frame').css('display', 'none');
                $('.trailerNoSupport').css('display', 'block');
            }  
            else {
                console.log("TestingOpenReach");
                $trailer.find('[data-trailer-iframe]').attr('src', buttonHref).removeClass('dn');

            }
        }

        // show trailer
        $trailer.addClass('active');

        console.log($('video'));
        console.log($trailer.find('[data-trailer-iframe]'));
        console.log($('video[name="media"]')[0]);

        pc.disableScroll();
    }

    function setupYT($trailer) {

        var tag = document.createElement('script');
        tag.src = "https://www.youtube.com/iframe_api";
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

        var ytInterval;

        pc.ytOnPlayerReady = function (e) {
            // yt iframe initial load
        };

        pc.ytOnPlayerStateChange = function (e) {
            console.log(['ytlog state change', e]);

            if (typeof e !== 'undefined' && e !== null && typeof e.data !== 'undefined' && e.data !== null) {
                if (typeof pc.movioTrack !== 'undefined' && typeof pc.movioTrack.trailer !== 'undefined') {
                    if (e.data === YT.PlayerState.PLAYING) {
                        var duration = pc.ytPlayer.getDuration();
                        var filmId = $trailer.data('film') || '';

                        ytInterval = setInterval(function () {
                            var curTime = pc.ytPlayer.getCurrentTime();
                            var progress = Math.round(curTime / duration * 100);

                            console.log(['ytlog progress', progress]);

                            //pc.movioTrack.trailer(filmId, progress);

                        }, 1000);
                    }
                    else {
                        if (typeof ytInterval !== 'undefined') {
                            clearInterval(ytInterval);
                        }
                    }
                }
            }
        };

        window.onYouTubeIframeAPIReady = function () {
            pc.ytAPIReady = true;
        };
    }

    createTrailer();

    $(document).on('click', '[data-trailer-btn]', function (e) {
        e.preventDefault();
        openTrailer(this);
    });

})(jQuery);

(function ($) {

    pc.overlay = {};

    pc.overlay.open = function (overlayId, disableClose) {

        if (typeof overlayId === 'undefined' || overlayId === '') {
            // no overlayId, exit
            return;
        }

        var $overlay = $(overlayId);

        if (typeof disableClose === 'undefined') {
            $overlay.off('click').on('click', function (e) {
                if (e.target === this) {
                    pc.overlay.close(overlayId);
                }
            });

            $overlay.find('[data-overlay-close]').off('click').on('click', function (e) {
                e.preventDefault();
                pc.overlay.close(overlayId);
            }).removeClass('dn');
        }

        $overlay.addClass('active');
        pc.disableScroll();
    };

    pc.overlay.close = function (overlayId) {
        $(overlayId).removeClass('active');
        pc.enableScroll();
    };

    $(document).on('click', '[data-overlay-btn]', function (e) {
        e.preventDefault();
        pc.overlay.open($(this).data('overlay-btn'));
    });

})(jQuery);;
(function ($) {
    var $select = $('select[data-jobs-cinemas]');

    if ($select.length === 0) {
        return;
    }

    $select.on('change', function () {
        var active = document.querySelectorAll('[data-jobs-group].is-active');
        var counter = 0;
        var newGroup = document.querySelector('[data-jobs-group="'+this.value+'"]:not(.is-active)');

        if (active !== null && active.length > 0) {
            counter = active.length;
            [].forEach.call(active, function (group) {
                $(group).slideUp(function () {
                    group.className = group.className.replace('is-active', '').trim();
                    counter--;
                    if (counter === 0 && newGroup !== null) {
                        $(newGroup).slideDown();
                        newGroup.className += ' is-active';
                    }
                });
            });
        }
        else if (newGroup !== null) {
            $(newGroup).slideDown();
            newGroup.className += ' is-active';
        }
    });

})(jQuery);;
