Advertisement
goebelmasse

Spammer simulieren Chat und Funktionalität in Javascript

Apr 17th, 2019
1,839
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. 'use strict';
  3.  
  4. var _react = require('react');
  5.  
  6. var _react2 = _interopRequireDefault(_react);
  7.  
  8. var _reactDom = require('react-dom');
  9.  
  10. var _reactDom2 = _interopRequireDefault(_reactDom);
  11.  
  12. require('bootstrap-jquery');
  13.  
  14. var _jquery = require('jquery.backstretch');
  15.  
  16. var _jquery2 = _interopRequireDefault(_jquery);
  17.  
  18. var _lodash = require('lodash');
  19.  
  20. var _lodash2 = _interopRequireDefault(_lodash);
  21.  
  22. var _sweetalert = require('sweetalert');
  23.  
  24. var _sweetalert2 = _interopRequireDefault(_sweetalert);
  25.  
  26. var _Generator = require('./components/Generator.js');
  27.  
  28. var _Generator2 = _interopRequireDefault(_Generator);
  29.  
  30. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  31.  
  32. _reactDom2.default.render(_react2.default.createElement(_Generator2.default, null), document.getElementById('generator'));
  33. // import $ from 'jquery';
  34. // window.$ = window.jQuery = $;
  35.  
  36.  
  37. $(document).ready(function () {
  38.     $.backstretch("http://liftmygram.com/img/background.jpg");
  39.     /*
  40.      * Live Chat
  41.      */
  42.  
  43.     var livechat_name = '';
  44.  
  45.     var livechat_text_area = $('.livechatListArea');
  46.     var livechat_text_list = $('.chatList');
  47.     var livechat_text_area_height = livechat_text_area.height();
  48.  
  49.     var name_colors = ['#d4a112', '#987c2f', '#b02643', '#d72248', '#9d22d7', '#a65fc7', '#2771bc', '#1a82ed', '#28ba4a', '#136b28', '#9bc716'];
  50.  
  51.     var chat_names = ['Richard23', 'Philip', 'Rob001', 'Hill213', 'Prim', 'Grequod', 'Moseeld30', 'Allichere', 'Munplad60', 'Therainged', 'Perseent', 'Wasice59', 'Arrent', 'Quot1991', 'Yourlenis'];
  52.  
  53.     var chat_messages = ["Awesome,its rare to find working generator like this one", "Anyone tried this already?", "Does it work in NA?", "Why this is so easy lol?", "This is incredible, never thought it would work.", "I get Resource in a minute.", "shy i see survey ?", "its to protect from spamming, first try to use, i got no Survey request, but for second try i need to get Finish 1 Survey", "OMG!", "LOL!", "ROFL!", "Real", "gayyyy", "easy", "bro", "What can I do here?", "Shut up man I love this website", "hi guys", "How much resource you've generated so far?", "what about surveys on mobile phone?", "Is this free?", "How long do you have to wait?", "Yea", "No", "I know", "Exactly why this is so good", "uhm", "maybe", "I can imagine this must be annoying for the one who play with skill", "Is this ban secure?", "Thanks man I appreciate this.", "Cool =)", "<message deleted>", "oh god", "damn", "I love this", "Never imagined this would work but damn its so simple", "saw this on forums pretty impressive", "yo guys dont spam okay?", "anyone up for a game?", "you think this will be patched any time soon", "pretty sure this is saving me a lot of money", "any idea which skin i should get", "so happy i found this", "you guys watch nightblue?", "I have seen this generator on hotshot stream i think", "just wow", "When do I get my resource ??", "a friend told me about this", "thanks to whoever spams this website Finish my survey now", "how can finish this survey quickly?", "so far I am cool with this generaor", "can I get off this survey easily?", "bye guys, already finish my survey, and resources generated successfully", "okay i am stacked now with survey", "finished survey is easy, if you fill using valid data", "incredible", "three minutes ago cannot get fast resource, now i have and its works perfectly", "need to go now", "brb", "You should give it a try", "dont regret being here", "fucking generator is real", "first time ever this makes sense", "Does everyone have a different survey ", "got my resource in 5 minutes only :D", "what happen after finish a survey", "after finish a survey you'll get the resiurce ", "today is lucky day", "this is the best generator because we all have more than a chance", "i think everyone can do a survey quickly", "can we get more than one survey ?, first time success, and want to try for my sister account", "yes", "abselutely", "I got all resource for my girlfriend too"];
  54.  
  55.     setInterval(function () {
  56.         add_livechat_msg(chat_names[_lodash2.default.random(0, chat_names.length - 1)], name_colors[_lodash2.default.random(0, name_colors.length - 1)], chat_messages[_lodash2.default.random(0, chat_messages.length - 1)]);
  57.     }, _lodash2.default.random(500, 4500));
  58.  
  59.     $('.livechatSubmtBtn').click(function () {
  60.         if (livechat_name == '') {
  61.             $('.livechatNameBox').show();
  62.         } else {
  63.             add_livechat_msg(livechat_name, '#136b28', $('.livechatMsg').val());
  64.             $('.livechatMsg').val('');
  65.         }
  66.     });
  67.  
  68.     $('.livechatNicknameBtn').click(function () {
  69.         var name_input = $('#livechat_name');
  70.         if (name_input.val() != '') {
  71.             livechat_name = name_input.val();
  72.             $(this).parents('.livechatNameBox').hide();
  73.         } else {
  74.             (0, _sweetalert2.default)("Error", "Please enter a nickname.", "error");
  75.         }
  76.     });
  77.  
  78.     $(".livechatName").on("keypress", function () {
  79.         console.log("Handler for .keypress() called.");
  80.     });
  81.  
  82.     function add_livechat_msg(name, color, msg) {
  83.         var $output_text = $('<li><span class="name" style="color: ' + color + ' !important;">' + name + '</span>: <span class="message">' + msg + '</span></li>');
  84.         $output_text.hide().appendTo(livechat_text_list).fadeIn();
  85.         livechat_text_area.animate({ scrollTop: livechat_text_area_height }, 500);
  86.         livechat_text_area_height += livechat_text_area.height();
  87.     }
  88. });
  89.  
  90. },{"./components/Generator.js":2,"bootstrap-jquery":"bootstrap-jquery","jquery.backstretch":20,"lodash":"lodash","react":"react","react-dom":"react-dom","sweetalert":"sweetalert"}],2:[function(require,module,exports){
  91. 'use strict';
  92.  
  93. Object.defineProperty(exports, "__esModule", {
  94.     value: true
  95. });
  96.  
  97. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  98.  
  99. var _react = require('react');
  100.  
  101. var _react2 = _interopRequireDefault(_react);
  102.  
  103. var _jquery = require('jquery');
  104.  
  105. var _jquery2 = _interopRequireDefault(_jquery);
  106.  
  107. var _bootbox = require('bootbox');
  108.  
  109. var _bootbox2 = _interopRequireDefault(_bootbox);
  110.  
  111. var _sweetalert = require('sweetalert');
  112.  
  113. var _sweetalert2 = _interopRequireDefault(_sweetalert);
  114.  
  115. var _lodash = require('lodash');
  116.  
  117. var _lodash2 = _interopRequireDefault(_lodash);
  118.  
  119. var _flickity = require('flickity');
  120.  
  121. var _flickity2 = _interopRequireDefault(_flickity);
  122.  
  123. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  124.  
  125. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  126.  
  127. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  128.  
  129. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  130.  
  131. window.$ = window.jQuery = _jquery2.default;
  132.  
  133.  
  134. function randomNumber(min, max) {
  135.     return Math.floor(Math.random() * (max - min + 1) + min);
  136. }
  137.  
  138. var Generator = function (_Component) {
  139.     _inherits(Generator, _Component);
  140.  
  141.     function Generator(props) {
  142.         _classCallCheck(this, Generator);
  143.  
  144.         var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Generator).call(this, props));
  145.  
  146.         var self = _this;
  147.         self.state = {
  148.             selected_device: null,
  149.             username: null,
  150.             progress: 0,
  151.             gold: null,
  152.             gems: null,
  153.             loading: false,
  154.             users: _lodash2.default.random(120, 340)
  155.         };
  156.         setInterval(function () {
  157.             self.setState({
  158.                 users: _lodash2.default.random(120, 340)
  159.             });
  160.         }, _lodash2.default.random(1500, 3000));
  161.         return _this;
  162.     }
  163.  
  164.     _createClass(Generator, [{
  165.         key: 'componentDidMount',
  166.         value: function componentDidMount() {
  167.             var self = this;
  168.             var generatorCarousel = new _flickity2.default('#generator-box', {
  169.                 prevNextButtons: false,
  170.                 pageDots: false,
  171.                 draggable: false,
  172.                 accessibility: false,
  173.                 resize: false
  174.             });
  175.             self.setState({
  176.                 generatorCarousel: generatorCarousel
  177.             }, function () {
  178.                 self.fixSliderHeight();
  179.                 self.state.generatorCarousel.on('cellSelect', function () {
  180.                     self.fixSliderHeight();
  181.                 });
  182.             });
  183.         }
  184.     }, {
  185.         key: 'resetGenerator',
  186.         value: function resetGenerator() {
  187.             var self = this;
  188.             self.setState({
  189.                 selected_device: null,
  190.                 username: null,
  191.                 progress: 0,
  192.                 gold: null,
  193.                 gems: null,
  194.                 loading: false
  195.             }, function () {
  196.                 _bootbox2.default.hideAll();
  197.                 self.state.generatorCarousel.select(0, false, true);
  198.             });
  199.         }
  200.     }, {
  201.         key: 'openLoading',
  202.         value: function openLoading(message, callback) {
  203.             var speed = arguments.length <= 2 || arguments[2] === undefined ? 'fast' : arguments[2];
  204.  
  205.             var self = this;
  206.             if (!self.state.loading) {
  207.                 self.setState({
  208.                     progress: 0,
  209.                     loading: true
  210.                 }, function () {
  211.                     var random_timer = 0;
  212.                     if (speed == 'fast') {
  213.                         random_timer = randomNumber(10, 25);
  214.                     } else if (speed == 'med') {
  215.                         random_timer = randomNumber(15, 45);
  216.                     } else if (speed == 'slow') {
  217.                         random_timer = randomNumber(50, 90);
  218.                     }
  219.                     _bootbox2.default.dialog({
  220.                         closeButton: false,
  221.                         title: 'Processing',
  222.                         message: '\n                        <img src="http://liftmygram.com/img/loader-small.gif" />\n                        <p>' + message + '</p>\n                        <div class="progress">\n                            <div id="loadingProgress" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%">\n                                <span class="sr-only">0% Complete</span>\n                            </div>\n                        </div>\n                    '
  223.                     });
  224.                     var loadingInterval = setInterval(function () {
  225.                         if (self.state.progress !== 100) {
  226.                             self.setState({
  227.                                 progress: self.state.progress + 1
  228.                             });
  229.                             (0, _jquery2.default)('#loadingProgress').attr('aria-valuenow', self.state.progress).css('width', self.state.progress + '%');
  230.                         } else {
  231.                             clearInterval(loadingInterval);
  232.                             _lodash2.default.delay(function () {
  233.                                 self.setState({
  234.                                     loading: false
  235.                                 }, function () {
  236.                                     _bootbox2.default.hideAll();
  237.                                     callback();
  238.                                 });
  239.                             }, randomNumber(350, 700));
  240.                         }
  241.                     }, random_timer);
  242.                 });
  243.             }
  244.         }
  245.     }, {
  246.         key: 'openHumanVerification',
  247.         value: function openHumanVerification() {
  248.             var self = this;
  249.             if (!self.state.loading) {
  250.                 // ADD CONTENT LOCKER onClick Code Here
  251.                 // Example: call_locker();
  252.                 // Below this line...
  253.                 letsgo();
  254.             }
  255.         }
  256.     }, {
  257.         key: 'selectDevice',
  258.         value: function selectDevice(device) {
  259.             var self = this;
  260.             if (!self.state.loading) {
  261.                 if (device) {
  262.                     this.setState({
  263.                         selected_device: device
  264.                     }, function () {
  265.                         self.openLoading('<p>Connecting to server...</p>', function () {
  266.                             self.state.generatorCarousel.next();
  267.                         });
  268.                     });
  269.                 }
  270.             }
  271.         }
  272.     }, {
  273.         key: 'changeUsername',
  274.         value: function changeUsername(event) {
  275.             var self = this;
  276.             var username = this.refs.username.value;
  277.             if (!self.state.loading) {
  278.                 if (username) {
  279.                     self.setState({
  280.                         username: username
  281.                     }, function () {
  282.                         if (self.state.username !== null) {
  283.                             self.refs.usernameContinueBtn.disabled = false;
  284.                         }
  285.                     });
  286.                 } else {
  287.                     self.setState({
  288.                         username: null
  289.                     }, function () {
  290.                         self.refs.usernameContinueBtn.disabled = true;
  291.                     });
  292.                 }
  293.             }
  294.         }
  295.     }, {
  296.         key: 'usernameContinue',
  297.         value: function usernameContinue() {
  298.             var self = this;
  299.             if (!self.state.loading) {
  300.                 if (self.state.username !== null) {
  301.                     self.openLoading('<p>Connecting to <strong>' + self.state.username + '</strong>...</p>', function () {
  302.                         self.state.generatorCarousel.next();
  303.                     });
  304.                 }
  305.             }
  306.         }
  307.     }, {
  308.         key: 'itemsContinue',
  309.         value: function itemsContinue() {
  310.             var self = this;
  311.             if (!self.state.loading) {
  312.                 self.openLoading('<p>Encrypting connection (AES-256)...</p>', function () {
  313.                     self.openLoading('<p>Opening configurations file for <strong>' + self.state.username + '</strong>..</p>', function () {
  314.                         self.openLoading('<p>Sending <strong>' + self.refs.followers.value + '</strong> followers to <strong>' + self.state.username + '</strong>..</p>', function () {
  315.                             self.openHumanVerification();
  316.                         });
  317.                     });
  318.                 });
  319.             }
  320.         }
  321.     }, {
  322.         key: 'fixSliderHeight',
  323.         value: function fixSliderHeight() {
  324.             var currentCellHeight = (0, _jquery2.default)('#generator-box').find('.cell.is-selected').height();
  325.             console.log(currentCellHeight);
  326.             (0, _jquery2.default)('#generator-box').find('.flickity-viewport').css({
  327.                 height: currentCellHeight
  328.             });
  329.         }
  330.     }, {
  331.         key: 'render',
  332.         value: function render() {
  333.             return _react2.default.createElement(
  334.                 'div',
  335.                 null,
  336.                 _react2.default.createElement(
  337.                     'div',
  338.                     { className: 'transparent-box' },
  339.                     _react2.default.createElement(
  340.                         'div',
  341.                         { className: 'row' },
  342.                         _react2.default.createElement(
  343.                             'div',
  344.                             { className: 'col-md-12' },
  345.                             _react2.default.createElement('img', { src: 'http://liftmygram.com/img/head-logo.png', className: 'img-responsive head-img' }),
  346.                             _react2.default.createElement(
  347.                                 'h1',
  348.                                 null,
  349.                                 'Followers Generator'
  350.                             ),
  351.                             _react2.default.createElement(
  352.                                 'p',
  353.                                 { className: 'sub-heading' },
  354.                                 'Become a local celebrity. Get unlimited free followers today and impress your friends!'
  355.                             )
  356.                         )
  357.                     ),
  358.                     _react2.default.createElement(
  359.                         'div',
  360.                         { className: 'row' },
  361.                         _react2.default.createElement(
  362.                             'div',
  363.                             { className: 'col-md-6 col-md-offset-3' },
  364.                             _react2.default.createElement(
  365.                                 'div',
  366.                                 { className: 'generator-box', id: 'generator-box' },
  367.                                 _react2.default.createElement(
  368.                                     'div',
  369.                                     { className: 'cell' },
  370.                                     _react2.default.createElement(
  371.                                         'div',
  372.                                         { className: 'row' },
  373.                                         _react2.default.createElement(
  374.                                             'div',
  375.                                             { className: 'col-md-12' },
  376.                                             _react2.default.createElement(
  377.                                                 'h3',
  378.                                                 null,
  379.                                                 '1. Connect to your account'
  380.                                             ),
  381.                                             _react2.default.createElement(
  382.                                                 'div',
  383.                                                 { className: 'username-input' },
  384.                                                 _react2.default.createElement('input', { type: 'text', id: 'username', ref: 'username', placeholder: 'Enter your username...', onChange: this.changeUsername.bind(this) })
  385.                                             ),
  386.                                             _react2.default.createElement(
  387.                                                 'div',
  388.                                                 { onClick: this.usernameContinue.bind(this) },
  389.                                                 _react2.default.createElement(
  390.                                                     'button',
  391.                                                     { className: 'btn btn-success btn-block btn-lg', ref: 'usernameContinueBtn', disabled: true },
  392.                                                     'Connect to account'
  393.                                                 )
  394.                                             ),
  395.                                             _react2.default.createElement(
  396.                                                 'p',
  397.                                                 null,
  398.                                                 'Please make sure that you enter the correct instagram username. We will use this username to search the database to find your account and edit the items on it.'
  399.                                             )
  400.                                         )
  401.                                     )
  402.                                 ),
  403.                                 _react2.default.createElement(
  404.                                     'div',
  405.                                     { className: 'cell' },
  406.                                     _react2.default.createElement(
  407.                                         'div',
  408.                                         { className: 'row' },
  409.                                         _react2.default.createElement(
  410.                                             'div',
  411.                                             { className: 'col-md-12' },
  412.                                             _react2.default.createElement(
  413.                                                 'h3',
  414.                                                 null,
  415.                                                 '2. Choose amount of followers'
  416.                                             ),
  417.                                             _react2.default.createElement(
  418.                                                 'div',
  419.                                                 { className: 'row' },
  420.                                                 _react2.default.createElement(
  421.                                                     'div',
  422.                                                     { className: 'col-md-6 col-md-offset-3' },
  423.                                                     _react2.default.createElement(
  424.                                                         'div',
  425.                                                         { className: 'form-group' },
  426.                                                         _react2.default.createElement(
  427.                                                             'label',
  428.                                                             { 'for': 'followers' },
  429.                                                             _react2.default.createElement('img', { src: 'http://liftmygram.com/img/icon.png', className: 'item-icon' }),
  430.                                                             ' Followers'
  431.                                                         ),
  432.                                                         _react2.default.createElement(
  433.                                                             'select',
  434.                                                             { id: 'followers', ref: 'followers', className: 'form-control' },
  435.                                                             _react2.default.createElement(
  436.                                                                 'option',
  437.                                                                 { value: '1,000' },
  438.                                                                 '1,000'
  439.                                                             ),
  440.                                                             _react2.default.createElement(
  441.                                                                 'option',
  442.                                                                 { value: '2,000' },
  443.                                                                 '2,000'
  444.                                                             ),
  445.                                                             _react2.default.createElement(
  446.                                                                 'option',
  447.                                                                 { value: '3,000' },
  448.                                                                 '3,000'
  449.                                                             ),
  450.                                                             _react2.default.createElement(
  451.                                                                 'option',
  452.                                                                 { value: '5,000' },
  453.                                                                 '5,000'
  454.                                                             ),
  455.                                                             _react2.default.createElement(
  456.                                                                 'option',
  457.                                                                 { value: '10,000' },
  458.                                                                 '10,000'
  459.                                                             ),
  460.                                                             _react2.default.createElement(
  461.                                                                 'option',
  462.                                                                 { value: '15,000' },
  463.                                                                 '15,000'
  464.                                                             ),
  465.                                                             _react2.default.createElement(
  466.                                                                 'option',
  467.                                                                 { value: '20,000' },
  468.                                                                 '20,000'
  469.                                                             ),
  470.                                                             _react2.default.createElement(
  471.                                                                 'option',
  472.                                                                 { value: '30,000' },
  473.                                                                 '30,000'
  474.                                                             )
  475.                                                         )
  476.                                                     )
  477.                                                 )
  478.                                             ),
  479.                                             _react2.default.createElement(
  480.                                                 'div',
  481.                                                 { onClick: this.itemsContinue.bind(this) },
  482.                                                 _react2.default.createElement(
  483.                                                     'button',
  484.                                                     { className: 'btn btn-success btn-block btn-lg', ref: 'itemsContinueBtn' },
  485.                                                     'Generate Followers'
  486.                                                 )
  487.                                             ),
  488.                                             _react2.default.createElement(
  489.                                                 'p',
  490.                                                 null,
  491.                                                 'Please choose the amount of followers would like to add to your account. We would like to note that this tool has been created for educational purposes and should not be abused.'
  492.                                             )
  493.                                         )
  494.                                     )
  495.                                 )
  496.                             )
  497.                         )
  498.                     ),
  499.                     _react2.default.createElement(
  500.                         'div',
  501.                         { className: 'row' },
  502.                         _react2.default.createElement(
  503.                             'div',
  504.                             { className: 'col-md-6 col-md-offset-3' },
  505.                             _react2.default.createElement(
  506.                                 'ul',
  507.                                 { className: 'status-list' },
  508.                                 _react2.default.createElement(
  509.                                     'li',
  510.                                     null,
  511.                                     _react2.default.createElement(
  512.                                         'div',
  513.                                         { className: 'generated-status' },
  514.                                         _react2.default.createElement(
  515.                                             'div',
  516.                                             { className: 'img' },
  517.                                             _react2.default.createElement('img', { src: 'http://liftmygram.com/img/aes-icon.png' })
  518.                                         ),
  519.                                         _react2.default.createElement(
  520.                                             'div',
  521.                                             { className: 'text' },
  522.                                             _react2.default.createElement(
  523.                                                 'h6',
  524.                                                 null,
  525.                                                 'Encryption'
  526.                                             ),
  527.                                             _react2.default.createElement(
  528.                                                 'p',
  529.                                                 { className: 'amount' },
  530.                                                 _react2.default.createElement(
  531.                                                     'span',
  532.                                                     { className: 'label label-info' },
  533.                                                     'AES-256'
  534.                                                 )
  535.                                             )
  536.                                         )
  537.                                     )
  538.                                 ),
  539.                                 _react2.default.createElement(
  540.                                     'li',
  541.                                     null,
  542.                                     _react2.default.createElement(
  543.                                         'div',
  544.                                         { className: 'generated-status' },
  545.                                         _react2.default.createElement(
  546.                                             'div',
  547.                                             { className: 'img' },
  548.                                             _react2.default.createElement('img', { src: 'http://liftmygram.com/img/icon.png' })
  549.                                         ),
  550.                                         _react2.default.createElement(
  551.                                             'div',
  552.                                             { className: 'text' },
  553.                                             _react2.default.createElement(
  554.                                                 'h6',
  555.                                                 null,
  556.                                                 'Users'
  557.                                             ),
  558.                                             _react2.default.createElement(
  559.                                                 'p',
  560.                                                 { className: 'amount' },
  561.                                                 _react2.default.createElement(
  562.                                                     'span',
  563.                                                     { className: 'label label-info' },
  564.                                                     this.state.users
  565.                                                 )
  566.                                             )
  567.                                         )
  568.                                     )
  569.                                 ),
  570.                                 _react2.default.createElement(
  571.                                     'li',
  572.                                     null,
  573.                                     _react2.default.createElement(
  574.                                         'div',
  575.                                         { className: 'generated-status' },
  576.                                         _react2.default.createElement(
  577.                                             'div',
  578.                                             { className: 'img' },
  579.                                             _react2.default.createElement('img', { src: 'http://liftmygram.com/img/server-icon.png' })
  580.                                         ),
  581.                                         _react2.default.createElement(
  582.                                             'div',
  583.                                             { className: 'text' },
  584.                                             _react2.default.createElement(
  585.                                                 'h6',
  586.                                                 null,
  587.                                                 'Server Status'
  588.                                             ),
  589.                                             _react2.default.createElement(
  590.                                                 'p',
  591.                                                 { className: 'amount' },
  592.                                                 _react2.default.createElement(
  593.                                                     'span',
  594.                                                     { className: 'label label-success' },
  595.                                                     'ONLINE'
  596.                                                 )
  597.                                             )
  598.                                         )
  599.                                     )
  600.                                 )
  601.                             )
  602.                         )
  603.                     ),
  604.                     _react2.default.createElement('br', null)
  605.                 )
  606.             );
  607.         }
  608.     }]);
  609.  
  610.     return Generator;
  611. }(_react.Component);
  612.  
  613. exports.default = Generator;
  614.  
  615. },{"bootbox":"bootbox","flickity":14,"jquery":"jquery","lodash":"lodash","react":"react","sweetalert":"sweetalert"}],3:[function(require,module,exports){
  616. /*!
  617.  * classie v1.0.1
  618.  * class helper functions
  619.  * from bonzo https://github.com/ded/bonzo
  620.  * MIT license
  621.  *
  622.  * classie.has( elem, 'my-class' ) -> true/false
  623.  * classie.add( elem, 'my-new-class' )
  624.  * classie.remove( elem, 'my-unwanted-class' )
  625.  * classie.toggle( elem, 'my-class' )
  626.  */
  627.  
  628. /*jshint browser: true, strict: true, undef: true, unused: true */
  629. /*global define: false, module: false */
  630.  
  631. ( function( window ) {
  632.  
  633. 'use strict';
  634.  
  635. // class helper functions from bonzo https://github.com/ded/bonzo
  636.  
  637. function classReg( className ) {
  638.   return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
  639. }
  640.  
  641. // classList support for class management
  642. // altho to be fair, the api sucks because it won't accept multiple classes at once
  643. var hasClass, addClass, removeClass;
  644.  
  645. if ( 'classList' in document.documentElement ) {
  646.   hasClass = function( elem, c ) {
  647.     return elem.classList.contains( c );
  648.   };
  649.   addClass = function( elem, c ) {
  650.     elem.classList.add( c );
  651.   };
  652.   removeClass = function( elem, c ) {
  653.     elem.classList.remove( c );
  654.   };
  655. }
  656. else {
  657.   hasClass = function( elem, c ) {
  658.     return classReg( c ).test( elem.className );
  659.   };
  660.   addClass = function( elem, c ) {
  661.     if ( !hasClass( elem, c ) ) {
  662.       elem.className = elem.className + ' ' + c;
  663.     }
  664.   };
  665.   removeClass = function( elem, c ) {
  666.     elem.className = elem.className.replace( classReg( c ), ' ' );
  667.   };
  668. }
  669.  
  670. function toggleClass( elem, c ) {
  671.   var fn = hasClass( elem, c ) ? removeClass : addClass;
  672.   fn( elem, c );
  673. }
  674.  
  675. var classie = {
  676.   // full names
  677.   hasClass: hasClass,
  678.   addClass: addClass,
  679.   removeClass: removeClass,
  680.   toggleClass: toggleClass,
  681.   // short names
  682.   has: hasClass,
  683.   add: addClass,
  684.   remove: removeClass,
  685.   toggle: toggleClass
  686. };
  687.  
  688. // transport
  689. if ( typeof define === 'function' && define.amd ) {
  690.   // AMD
  691.   define( classie );
  692. } else if ( typeof exports === 'object' ) {
  693.   // CommonJS
  694.   module.exports = classie;
  695. } else {
  696.   // browser global
  697.   window.classie = classie;
  698. }
  699.  
  700. })( window );
  701.  
  702. },{}],4:[function(require,module,exports){
  703. /*!
  704.  * getStyleProperty v1.0.4
  705.  * original by kangax
  706.  * http://perfectionkills.com/feature-testing-css-properties/
  707.  * MIT license
  708.  */
  709.  
  710. /*jshint browser: true, strict: true, undef: true */
  711. /*global define: false, exports: false, module: false */
  712.  
  713. ( function( window ) {
  714.  
  715. 'use strict';
  716.  
  717. var prefixes = 'Webkit Moz ms Ms O'.split(' ');
  718. var docElemStyle = document.documentElement.style;
  719.  
  720. function getStyleProperty( propName ) {
  721.   if ( !propName ) {
  722.     return;
  723.   }
  724.  
  725.   // test standard property first
  726.   if ( typeof docElemStyle[ propName ] === 'string' ) {
  727.     return propName;
  728.   }
  729.  
  730.   // capitalize
  731.   propName = propName.charAt(0).toUpperCase() + propName.slice(1);
  732.  
  733.   // test vendor specific properties
  734.   var prefixed;
  735.   for ( var i=0, len = prefixes.length; i < len; i++ ) {
  736.     prefixed = prefixes[i] + propName;
  737.     if ( typeof docElemStyle[ prefixed ] === 'string' ) {
  738.       return prefixed;
  739.     }
  740.   }
  741. }
  742.  
  743. // transport
  744. if ( typeof define === 'function' && define.amd ) {
  745.   // AMD
  746.   define( function() {
  747.     return getStyleProperty;
  748.   });
  749. } else if ( typeof exports === 'object' ) {
  750.   // CommonJS for Component
  751.   module.exports = getStyleProperty;
  752. } else {
  753.   // browser global
  754.   window.getStyleProperty = getStyleProperty;
  755. }
  756.  
  757. })( window );
  758.  
  759. },{}],5:[function(require,module,exports){
  760. /**
  761.  * matchesSelector v1.0.3
  762.  * matchesSelector( element, '.selector' )
  763.  * MIT license
  764.  */
  765.  
  766. /*jshint browser: true, strict: true, undef: true, unused: true */
  767. /*global define: false, module: false */
  768.  
  769. ( function( ElemProto ) {
  770.  
  771.   'use strict';
  772.  
  773.   var matchesMethod = ( function() {
  774.     // check for the standard method name first
  775.     if ( ElemProto.matches ) {
  776.       return 'matches';
  777.     }
  778.     // check un-prefixed
  779.     if ( ElemProto.matchesSelector ) {
  780.       return 'matchesSelector';
  781.     }
  782.     // check vendor prefixes
  783.     var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
  784.  
  785.     for ( var i=0, len = prefixes.length; i < len; i++ ) {
  786.       var prefix = prefixes[i];
  787.       var method = prefix + 'MatchesSelector';
  788.       if ( ElemProto[ method ] ) {
  789.         return method;
  790.       }
  791.     }
  792.   })();
  793.  
  794.   // ----- match ----- //
  795.  
  796.   function match( elem, selector ) {
  797.     return elem[ matchesMethod ]( selector );
  798.   }
  799.  
  800.   // ----- appendToFragment ----- //
  801.  
  802.   function checkParent( elem ) {
  803.     // not needed if already has parent
  804.     if ( elem.parentNode ) {
  805.       return;
  806.     }
  807.     var fragment = document.createDocumentFragment();
  808.     fragment.appendChild( elem );
  809.   }
  810.  
  811.   // ----- query ----- //
  812.  
  813.   // fall back to using QSA
  814.   // thx @jonathantneal https://gist.github.com/3062955
  815.   function query( elem, selector ) {
  816.     // append to fragment if no parent
  817.     checkParent( elem );
  818.  
  819.     // match elem with all selected elems of parent
  820.     var elems = elem.parentNode.querySelectorAll( selector );
  821.     for ( var i=0, len = elems.length; i < len; i++ ) {
  822.       // return true if match
  823.       if ( elems[i] === elem ) {
  824.         return true;
  825.       }
  826.     }
  827.     // otherwise return false
  828.     return false;
  829.   }
  830.  
  831.   // ----- matchChild ----- //
  832.  
  833.   function matchChild( elem, selector ) {
  834.     checkParent( elem );
  835.     return match( elem, selector );
  836.   }
  837.  
  838.   // ----- matchesSelector ----- //
  839.  
  840.   var matchesSelector;
  841.  
  842.   if ( matchesMethod ) {
  843.     // IE9 supports matchesSelector, but doesn't work on orphaned elems
  844.     // check for that
  845.     var div = document.createElement('div');
  846.     var supportsOrphans = match( div, 'div' );
  847.     matchesSelector = supportsOrphans ? match : matchChild;
  848.   } else {
  849.     matchesSelector = query;
  850.   }
  851.  
  852.   // transport
  853.   if ( typeof define === 'function' && define.amd ) {
  854.     // AMD
  855.     define( function() {
  856.       return matchesSelector;
  857.     });
  858.   } else if ( typeof exports === 'object' ) {
  859.     module.exports = matchesSelector;
  860.   }
  861.   else {
  862.     // browser global
  863.     window.matchesSelector = matchesSelector;
  864.   }
  865.  
  866. })( Element.prototype );
  867.  
  868. },{}],6:[function(require,module,exports){
  869. /*!
  870.  * docReady v1.0.3
  871.  * Cross browser DOMContentLoaded event emitter
  872.  * MIT license
  873.  */
  874.  
  875. /*jshint browser: true, strict: true, undef: true, unused: true*/
  876. /*global define: false, require: false, module: false */
  877.  
  878. ( function( window ) {
  879.  
  880. 'use strict';
  881.  
  882. var document = window.document;
  883. // collection of functions to be triggered on ready
  884. var queue = [];
  885.  
  886. function docReady( fn ) {
  887.   // throw out non-functions
  888.   if ( typeof fn !== 'function' ) {
  889.     return;
  890.   }
  891.  
  892.   if ( docReady.isReady ) {
  893.     // ready now, hit it
  894.     fn();
  895.   } else {
  896.     // queue function when ready
  897.     queue.push( fn );
  898.   }
  899. }
  900.  
  901. docReady.isReady = false;
  902.  
  903. // triggered on various doc ready events
  904. function init( event ) {
  905.   // bail if IE8 document is not ready just yet
  906.   var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
  907.   if ( docReady.isReady || isIE8NotReady ) {
  908.     return;
  909.   }
  910.   docReady.isReady = true;
  911.  
  912.   // process queue
  913.   for ( var i=0, len = queue.length; i < len; i++ ) {
  914.     var fn = queue[i];
  915.     fn();
  916.   }
  917. }
  918.  
  919. function defineDocReady( eventie ) {
  920.   eventie.bind( document, 'DOMContentLoaded', init );
  921.   eventie.bind( document, 'readystatechange', init );
  922.   eventie.bind( window, 'load', init );
  923.  
  924.   return docReady;
  925. }
  926.  
  927. // transport
  928. if ( typeof define === 'function' && define.amd ) {
  929.   // AMD
  930.   // if RequireJS, then doc is already ready
  931.   docReady.isReady = typeof requirejs === 'function';
  932.   define( [ 'eventie/eventie' ], defineDocReady );
  933. } else if ( typeof exports === 'object' ) {
  934.   module.exports = defineDocReady( require('eventie') );
  935. } else {
  936.   // browser global
  937.   window.docReady = defineDocReady( window.eventie );
  938. }
  939.  
  940. })( window );
  941.  
  942. },{"eventie":7}],7:[function(require,module,exports){
  943. /*!
  944.  * eventie v1.0.6
  945.  * event binding helper
  946.  *   eventie.bind( elem, 'click', myFn )
  947.  *   eventie.unbind( elem, 'click', myFn )
  948.  * MIT license
  949.  */
  950.  
  951. /*jshint browser: true, undef: true, unused: true */
  952. /*global define: false, module: false */
  953.  
  954. ( function( window ) {
  955.  
  956. 'use strict';
  957.  
  958. var docElem = document.documentElement;
  959.  
  960. var bind = function() {};
  961.  
  962. function getIEEvent( obj ) {
  963.   var event = window.event;
  964.   // add event.target
  965.   event.target = event.target || event.srcElement || obj;
  966.   return event;
  967. }
  968.  
  969. if ( docElem.addEventListener ) {
  970.   bind = function( obj, type, fn ) {
  971.     obj.addEventListener( type, fn, false );
  972.   };
  973. } else if ( docElem.attachEvent ) {
  974.   bind = function( obj, type, fn ) {
  975.     obj[ type + fn ] = fn.handleEvent ?
  976.       function() {
  977.         var event = getIEEvent( obj );
  978.         fn.handleEvent.call( fn, event );
  979.       } :
  980.       function() {
  981.         var event = getIEEvent( obj );
  982.         fn.call( obj, event );
  983.       };
  984.     obj.attachEvent( "on" + type, obj[ type + fn ] );
  985.   };
  986. }
  987.  
  988. var unbind = function() {};
  989.  
  990. if ( docElem.removeEventListener ) {
  991.   unbind = function( obj, type, fn ) {
  992.     obj.removeEventListener( type, fn, false );
  993.   };
  994. } else if ( docElem.detachEvent ) {
  995.   unbind = function( obj, type, fn ) {
  996.     obj.detachEvent( "on" + type, obj[ type + fn ] );
  997.     try {
  998.       delete obj[ type + fn ];
  999.     } catch ( err ) {
  1000.       // can't delete window object properties
  1001.       obj[ type + fn ] = undefined;
  1002.     }
  1003.   };
  1004. }
  1005.  
  1006. var eventie = {
  1007.   bind: bind,
  1008.   unbind: unbind
  1009. };
  1010.  
  1011. // ----- module definition ----- //
  1012.  
  1013. if ( typeof define === 'function' && define.amd ) {
  1014.   // AMD
  1015.   define( eventie );
  1016. } else if ( typeof exports === 'object' ) {
  1017.   // CommonJS
  1018.   module.exports = eventie;
  1019. } else {
  1020.   // browser global
  1021.   window.eventie = eventie;
  1022. }
  1023.  
  1024. })( window );
  1025.  
  1026. },{}],8:[function(require,module,exports){
  1027. /**
  1028.  * Fizzy UI utils v1.0.1
  1029.  * MIT license
  1030.  */
  1031.  
  1032. /*jshint browser: true, undef: true, unused: true, strict: true */
  1033.  
  1034. ( function( window, factory ) {
  1035.   /*global define: false, module: false, require: false */
  1036.   'use strict';
  1037.   // universal module definition
  1038.  
  1039.   if ( typeof define == 'function' && define.amd ) {
  1040.     // AMD
  1041.     define( [
  1042.       'doc-ready/doc-ready',
  1043.       'matches-selector/matches-selector'
  1044.     ], function( docReady, matchesSelector ) {
  1045.       return factory( window, docReady, matchesSelector );
  1046.     });
  1047.   } else if ( typeof exports == 'object' ) {
  1048.     // CommonJS
  1049.     module.exports = factory(
  1050.       window,
  1051.       require('doc-ready'),
  1052.       require('desandro-matches-selector')
  1053.     );
  1054.   } else {
  1055.     // browser global
  1056.     window.fizzyUIUtils = factory(
  1057.       window,
  1058.       window.docReady,
  1059.       window.matchesSelector
  1060.     );
  1061.   }
  1062.  
  1063. }( window, function factory( window, docReady, matchesSelector ) {
  1064.  
  1065. 'use strict';
  1066.  
  1067. var utils = {};
  1068.  
  1069. // ----- extend ----- //
  1070.  
  1071. // extends objects
  1072. utils.extend = function( a, b ) {
  1073.   for ( var prop in b ) {
  1074.     a[ prop ] = b[ prop ];
  1075.   }
  1076.   return a;
  1077. };
  1078.  
  1079. // ----- modulo ----- //
  1080.  
  1081. utils.modulo = function( num, div ) {
  1082.   return ( ( num % div ) + div ) % div;
  1083. };
  1084.  
  1085. // ----- isArray ----- //
  1086.  
  1087. var objToString = Object.prototype.toString;
  1088. utils.isArray = function( obj ) {
  1089.   return objToString.call( obj ) == '[object Array]';
  1090. };
  1091.  
  1092. // ----- makeArray ----- //
  1093.  
  1094. // turn element or nodeList into an array
  1095. utils.makeArray = function( obj ) {
  1096.   var ary = [];
  1097.   if ( utils.isArray( obj ) ) {
  1098.     // use object if already an array
  1099.     ary = obj;
  1100.   } else if ( obj && typeof obj.length == 'number' ) {
  1101.     // convert nodeList to array
  1102.     for ( var i=0, len = obj.length; i < len; i++ ) {
  1103.       ary.push( obj[i] );
  1104.     }
  1105.   } else {
  1106.     // array of single index
  1107.     ary.push( obj );
  1108.   }
  1109.   return ary;
  1110. };
  1111.  
  1112. // ----- indexOf ----- //
  1113.  
  1114. // index of helper cause IE8
  1115. utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  1116.     return ary.indexOf( obj );
  1117.   } : function( ary, obj ) {
  1118.     for ( var i=0, len = ary.length; i < len; i++ ) {
  1119.       if ( ary[i] === obj ) {
  1120.         return i;
  1121.       }
  1122.     }
  1123.     return -1;
  1124.   };
  1125.  
  1126. // ----- removeFrom ----- //
  1127.  
  1128. utils.removeFrom = function( ary, obj ) {
  1129.   var index = utils.indexOf( ary, obj );
  1130.   if ( index != -1 ) {
  1131.     ary.splice( index, 1 );
  1132.   }
  1133. };
  1134.  
  1135. // ----- isElement ----- //
  1136.  
  1137. // http://stackoverflow.com/a/384380/182183
  1138. utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
  1139.   function isElementDOM2( obj ) {
  1140.     return obj instanceof HTMLElement;
  1141.   } :
  1142.   function isElementQuirky( obj ) {
  1143.     return obj && typeof obj == 'object' &&
  1144.       obj.nodeType == 1 && typeof obj.nodeName == 'string';
  1145.   };
  1146.  
  1147. // ----- setText ----- //
  1148.  
  1149. utils.setText = ( function() {
  1150.   var setTextProperty;
  1151.   function setText( elem, text ) {
  1152.     // only check setTextProperty once
  1153.     setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
  1154.     elem[ setTextProperty ] = text;
  1155.   }
  1156.   return setText;
  1157. })();
  1158.  
  1159. // ----- getParent ----- //
  1160.  
  1161. utils.getParent = function( elem, selector ) {
  1162.   while ( elem != document.body ) {
  1163.     elem = elem.parentNode;
  1164.     if ( matchesSelector( elem, selector ) ) {
  1165.       return elem;
  1166.     }
  1167.   }
  1168. };
  1169.  
  1170. // ----- getQueryElement ----- //
  1171.  
  1172. // use element as selector string
  1173. utils.getQueryElement = function( elem ) {
  1174.   if ( typeof elem == 'string' ) {
  1175.     return document.querySelector( elem );
  1176.   }
  1177.   return elem;
  1178. };
  1179.  
  1180. // ----- handleEvent ----- //
  1181.  
  1182. // enable .ontype to trigger from .addEventListener( elem, 'type' )
  1183. utils.handleEvent = function( event ) {
  1184.   var method = 'on' + event.type;
  1185.   if ( this[ method ] ) {
  1186.     this[ method ]( event );
  1187.   }
  1188. };
  1189.  
  1190. // ----- filterFindElements ----- //
  1191.  
  1192. utils.filterFindElements = function( elems, selector ) {
  1193.   // make array of elems
  1194.   elems = utils.makeArray( elems );
  1195.   var ffElems = [];
  1196.  
  1197.   for ( var i=0, len = elems.length; i < len; i++ ) {
  1198.     var elem = elems[i];
  1199.     // check that elem is an actual element
  1200.     if ( !utils.isElement( elem ) ) {
  1201.       continue;
  1202.     }
  1203.     // filter & find items if we have a selector
  1204.     if ( selector ) {
  1205.       // filter siblings
  1206.       if ( matchesSelector( elem, selector ) ) {
  1207.         ffElems.push( elem );
  1208.       }
  1209.       // find children
  1210.       var childElems = elem.querySelectorAll( selector );
  1211.       // concat childElems to filterFound array
  1212.       for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
  1213.         ffElems.push( childElems[j] );
  1214.       }
  1215.     } else {
  1216.       ffElems.push( elem );
  1217.     }
  1218.   }
  1219.  
  1220.   return ffElems;
  1221. };
  1222.  
  1223. // ----- debounceMethod ----- //
  1224.  
  1225. utils.debounceMethod = function( _class, methodName, threshold ) {
  1226.   // original method
  1227.   var method = _class.prototype[ methodName ];
  1228.   var timeoutName = methodName + 'Timeout';
  1229.  
  1230.   _class.prototype[ methodName ] = function() {
  1231.     var timeout = this[ timeoutName ];
  1232.     if ( timeout ) {
  1233.       clearTimeout( timeout );
  1234.     }
  1235.     var args = arguments;
  1236.  
  1237.     var _this = this;
  1238.     this[ timeoutName ] = setTimeout( function() {
  1239.       method.apply( _this, args );
  1240.       delete _this[ timeoutName ];
  1241.     }, threshold || 100 );
  1242.   };
  1243. };
  1244.  
  1245. // ----- htmlInit ----- //
  1246.  
  1247. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  1248. utils.toDashed = function( str ) {
  1249.   return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  1250.     return $1 + '-' + $2;
  1251.   }).toLowerCase();
  1252. };
  1253.  
  1254. var console = window.console;
  1255. /**
  1256.  * allow user to initialize classes via .js-namespace class
  1257.  * htmlInit( Widget, 'widgetName' )
  1258.  * options are parsed from data-namespace-option attribute
  1259.  */
  1260. utils.htmlInit = function( WidgetClass, namespace ) {
  1261.   docReady( function() {
  1262.     var dashedNamespace = utils.toDashed( namespace );
  1263.     var elems = document.querySelectorAll( '.js-' + dashedNamespace );
  1264.     var dataAttr = 'data-' + dashedNamespace + '-options';
  1265.  
  1266.     for ( var i=0, len = elems.length; i < len; i++ ) {
  1267.       var elem = elems[i];
  1268.       var attr = elem.getAttribute( dataAttr );
  1269.       var options;
  1270.       try {
  1271.         options = attr && JSON.parse( attr );
  1272.       } catch ( error ) {
  1273.         // log error, do not initialize
  1274.         if ( console ) {
  1275.           console.error( 'Error parsing ' + dataAttr + ' on ' +
  1276.             elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
  1277.             error );
  1278.         }
  1279.         continue;
  1280.       }
  1281.       // initialize
  1282.       var instance = new WidgetClass( elem, options );
  1283.       // make available via $().data('layoutname')
  1284.       var jQuery = window.jQuery;
  1285.       if ( jQuery ) {
  1286.         jQuery.data( elem, namespace, instance );
  1287.       }
  1288.     }
  1289.   });
  1290. };
  1291.  
  1292. // -----  ----- //
  1293.  
  1294. return utils;
  1295.  
  1296. }));
  1297.  
  1298. },{"desandro-matches-selector":5,"doc-ready":6}],9:[function(require,module,exports){
  1299. ( function( window, factory ) {
  1300.   'use strict';
  1301.   // universal module definition
  1302.  
  1303.   if ( typeof define == 'function' && define.amd ) {
  1304.     // AMD
  1305.     define( [
  1306.       './flickity',
  1307.       'fizzy-ui-utils/utils'
  1308.     ], function( Flickity, utils ) {
  1309.       return factory( window, Flickity, utils );
  1310.     });
  1311.   } else if ( typeof exports == 'object' ) {
  1312.     // CommonJS
  1313.     module.exports = factory(
  1314.       window,
  1315.       require('./flickity'),
  1316.       require('fizzy-ui-utils')
  1317.     );
  1318.   } else {
  1319.     // browser global
  1320.     factory(
  1321.       window,
  1322.       window.Flickity,
  1323.       window.fizzyUIUtils
  1324.     );
  1325.   }
  1326.  
  1327. }( window, function factory( window, Flickity, utils ) {
  1328.  
  1329. 'use strict';
  1330.  
  1331. // append cells to a document fragment
  1332. function getCellsFragment( cells ) {
  1333.   var fragment = document.createDocumentFragment();
  1334.   for ( var i=0, len = cells.length; i < len; i++ ) {
  1335.     var cell = cells[i];
  1336.     fragment.appendChild( cell.element );
  1337.   }
  1338.   return fragment;
  1339. }
  1340.  
  1341. // -------------------------- add/remove cell prototype -------------------------- //
  1342.  
  1343. /**
  1344.  * Insert, prepend, or append cells
  1345.  * @param {Element, Array, NodeList} elems
  1346.  * @param {Integer} index
  1347.  */
  1348. Flickity.prototype.insert = function( elems, index ) {
  1349.   var cells = this._makeCells( elems );
  1350.   if ( !cells || !cells.length ) {
  1351.     return;
  1352.   }
  1353.   var len = this.cells.length;
  1354.   // default to append
  1355.   index = index === undefined ? len : index;
  1356.   // add cells with document fragment
  1357.   var fragment = getCellsFragment( cells );
  1358.   // append to slider
  1359.   var isAppend = index == len;
  1360.   if ( isAppend ) {
  1361.     this.slider.appendChild( fragment );
  1362.   } else {
  1363.     var insertCellElement = this.cells[ index ].element;
  1364.     this.slider.insertBefore( fragment, insertCellElement );
  1365.   }
  1366.   // add to this.cells
  1367.   if ( index === 0 ) {
  1368.     // prepend, add to start
  1369.     this.cells = cells.concat( this.cells );
  1370.   } else if ( isAppend ) {
  1371.     // append, add to end
  1372.     this.cells = this.cells.concat( cells );
  1373.   } else {
  1374.     // insert in this.cells
  1375.     var endCells = this.cells.splice( index, len - index );
  1376.     this.cells = this.cells.concat( cells ).concat( endCells );
  1377.   }
  1378.  
  1379.   this._sizeCells( cells );
  1380.  
  1381.   var selectedIndexDelta = index > this.selectedIndex ? 0 : cells.length;
  1382.   this._cellAddedRemoved( index, selectedIndexDelta );
  1383. };
  1384.  
  1385. Flickity.prototype.append = function( elems ) {
  1386.   this.insert( elems, this.cells.length );
  1387. };
  1388.  
  1389. Flickity.prototype.prepend = function( elems ) {
  1390.   this.insert( elems, 0 );
  1391. };
  1392.  
  1393. /**
  1394.  * Remove cells
  1395.  * @param {Element, Array, NodeList} elems
  1396.  */
  1397. Flickity.prototype.remove = function( elems ) {
  1398.   var cells = this.getCells( elems );
  1399.   var selectedIndexDelta = 0;
  1400.   var i, len, cell;
  1401.   // calculate selectedIndexDelta, easier if done in seperate loop
  1402.   for ( i=0, len = cells.length; i < len; i++ ) {
  1403.     cell = cells[i];
  1404.     var wasBefore = utils.indexOf( this.cells, cell ) < this.selectedIndex;
  1405.     selectedIndexDelta -= wasBefore ? 1 : 0;
  1406.   }
  1407.  
  1408.   for ( i=0, len = cells.length; i < len; i++ ) {
  1409.     cell = cells[i];
  1410.     cell.remove();
  1411.     // remove item from collection
  1412.     utils.removeFrom( this.cells, cell );
  1413.   }
  1414.  
  1415.   if ( cells.length ) {
  1416.     // update stuff
  1417.     this._cellAddedRemoved( 0, selectedIndexDelta );
  1418.   }
  1419. };
  1420.  
  1421. // updates when cells are added or removed
  1422. Flickity.prototype._cellAddedRemoved = function( changedCellIndex, selectedIndexDelta ) {
  1423.   selectedIndexDelta = selectedIndexDelta || 0;
  1424.   this.selectedIndex += selectedIndexDelta;
  1425.   this.selectedIndex = Math.max( 0, Math.min( this.cells.length - 1, this.selectedIndex ) );
  1426.  
  1427.   this.emitEvent( 'cellAddedRemoved', [ changedCellIndex, selectedIndexDelta ] );
  1428.   this.cellChange( changedCellIndex, true );
  1429. };
  1430.  
  1431. /**
  1432.  * logic to be run after a cell's size changes
  1433.  * @param {Element} elem - cell's element
  1434.  */
  1435. Flickity.prototype.cellSizeChange = function( elem ) {
  1436.   var cell = this.getCell( elem );
  1437.   if ( !cell ) {
  1438.     return;
  1439.   }
  1440.   cell.getSize();
  1441.  
  1442.   var index = utils.indexOf( this.cells, cell );
  1443.   this.cellChange( index );
  1444. };
  1445.  
  1446. /**
  1447.  * logic any time a cell is changed: added, removed, or size changed
  1448.  * @param {Integer} changedCellIndex - index of the changed cell, optional
  1449.  */
  1450. Flickity.prototype.cellChange = function( changedCellIndex, isPositioningSlider ) {
  1451.   var prevSlideableWidth = this.slideableWidth;
  1452.   this._positionCells( changedCellIndex );
  1453.   this._getWrapShiftCells();
  1454.   this.setGallerySize();
  1455.   // position slider
  1456.   if ( this.options.freeScroll ) {
  1457.     // shift x by change in slideableWidth
  1458.     // TODO fix position shifts when prepending w/ freeScroll
  1459.     var deltaX = prevSlideableWidth - this.slideableWidth;
  1460.     this.x += deltaX * this.cellAlign;
  1461.     this.positionSlider();
  1462.   } else {
  1463.     // do not position slider after lazy load
  1464.     if ( isPositioningSlider ) {
  1465.       this.positionSliderAtSelected();
  1466.     }
  1467.     this.select( this.selectedIndex );
  1468.   }
  1469. };
  1470.  
  1471. // -----  ----- //
  1472.  
  1473. return Flickity;
  1474.  
  1475. }));
  1476.  
  1477. },{"./flickity":13,"fizzy-ui-utils":8}],10:[function(require,module,exports){
  1478. ( function( window, factory ) {
  1479.   'use strict';
  1480.   // universal module definition
  1481.  
  1482.   if ( typeof define == 'function' && define.amd ) {
  1483.     // AMD
  1484.     define( [
  1485.       'get-style-property/get-style-property',
  1486.       'fizzy-ui-utils/utils'
  1487.     ], function( getStyleProperty, utils ) {
  1488.       return factory( window, getStyleProperty, utils );
  1489.     });
  1490.   } else if ( typeof exports == 'object' ) {
  1491.     // CommonJS
  1492.     module.exports = factory(
  1493.       window,
  1494.       require('desandro-get-style-property'),
  1495.       require('fizzy-ui-utils')
  1496.     );
  1497.   } else {
  1498.     // browser global
  1499.     window.Flickity = window.Flickity || {};
  1500.     window.Flickity.animatePrototype = factory(
  1501.       window,
  1502.       window.getStyleProperty,
  1503.       window.fizzyUIUtils
  1504.     );
  1505.   }
  1506.  
  1507. }( window, function factory( window, getStyleProperty, utils ) {
  1508.  
  1509. 'use strict';
  1510.  
  1511. // -------------------------- requestAnimationFrame -------------------------- //
  1512.  
  1513. // https://gist.github.com/1866474
  1514.  
  1515. var lastTime = 0;
  1516. var prefixes = 'webkit moz ms o'.split(' ');
  1517. // get unprefixed rAF and cAF, if present
  1518. var requestAnimationFrame = window.requestAnimationFrame;
  1519. var cancelAnimationFrame = window.cancelAnimationFrame;
  1520. // loop through vendor prefixes and get prefixed rAF and cAF
  1521. var prefix;
  1522. for( var i = 0; i < prefixes.length; i++ ) {
  1523.   if ( requestAnimationFrame && cancelAnimationFrame ) {
  1524.     break;
  1525.   }
  1526.   prefix = prefixes[i];
  1527.   requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
  1528.   cancelAnimationFrame  = cancelAnimationFrame  || window[ prefix + 'CancelAnimationFrame' ] ||
  1529.                             window[ prefix + 'CancelRequestAnimationFrame' ];
  1530. }
  1531.  
  1532. // fallback to setTimeout and clearTimeout if either request/cancel is not supported
  1533. if ( !requestAnimationFrame || !cancelAnimationFrame )  {
  1534.   requestAnimationFrame = function( callback ) {
  1535.     var currTime = new Date().getTime();
  1536.     var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
  1537.     var id = window.setTimeout( function() {
  1538.       callback( currTime + timeToCall );
  1539.     }, timeToCall );
  1540.     lastTime = currTime + timeToCall;
  1541.     return id;
  1542.   };
  1543.  
  1544.   cancelAnimationFrame = function( id ) {
  1545.     window.clearTimeout( id );
  1546.   };
  1547. }
  1548.  
  1549. // -------------------------- animate -------------------------- //
  1550.  
  1551. var proto = {};
  1552.  
  1553. proto.startAnimation = function() {
  1554.   if ( this.isAnimating ) {
  1555.     return;
  1556.   }
  1557.  
  1558.   this.isAnimating = true;
  1559.   this.restingFrames = 0;
  1560.   this.animate();
  1561. };
  1562.  
  1563. proto.animate = function() {
  1564.   this.applyDragForce();
  1565.   this.applySelectedAttraction();
  1566.  
  1567.   var previousX = this.x;
  1568.  
  1569.   this.integratePhysics();
  1570.   this.positionSlider();
  1571.   this.settle( previousX );
  1572.   // animate next frame
  1573.   if ( this.isAnimating ) {
  1574.     var _this = this;
  1575.     requestAnimationFrame( function animateFrame() {
  1576.       _this.animate();
  1577.     });
  1578.   }
  1579.  
  1580.   /** /
  1581.   // log animation frame rate
  1582.   var now = new Date();
  1583.   if ( this.then ) {
  1584.     console.log( ~~( 1000 / (now-this.then)) + 'fps' )
  1585.   }
  1586.   this.then = now;
  1587.   /**/
  1588. };
  1589.  
  1590.  
  1591. var transformProperty = getStyleProperty('transform');
  1592. var is3d = !!getStyleProperty('perspective');
  1593.  
  1594. proto.positionSlider = function() {
  1595.   var x = this.x;
  1596.   // wrap position around
  1597.   if ( this.options.wrapAround && this.cells.length > 1 ) {
  1598.     x = utils.modulo( x, this.slideableWidth );
  1599.     x = x - this.slideableWidth;
  1600.     this.shiftWrapCells( x );
  1601.   }
  1602.  
  1603.   x = x + this.cursorPosition;
  1604.  
  1605.   // reverse if right-to-left and using transform
  1606.   x = this.options.rightToLeft && transformProperty ? -x : x;
  1607.  
  1608.   var value = this.getPositionValue( x );
  1609.  
  1610.   if ( transformProperty ) {
  1611.     // use 3D tranforms for hardware acceleration on iOS
  1612.     // but use 2D when settled, for better font-rendering
  1613.     this.slider.style[ transformProperty ] = is3d && this.isAnimating ?
  1614.       'translate3d(' + value + ',0,0)' : 'translateX(' + value + ')';
  1615.   } else {
  1616.     this.slider.style[ this.originSide ] = value;
  1617.   }
  1618. };
  1619.  
  1620. proto.positionSliderAtSelected = function() {
  1621.   if ( !this.cells.length ) {
  1622.     return;
  1623.   }
  1624.   var selectedCell = this.cells[ this.selectedIndex ];
  1625.   this.x = -selectedCell.target;
  1626.   this.positionSlider();
  1627. };
  1628.  
  1629. proto.getPositionValue = function( position ) {
  1630.   if ( this.options.percentPosition ) {
  1631.     // percent position, round to 2 digits, like 12.34%
  1632.     return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 )+ '%';
  1633.   } else {
  1634.     // pixel positioning
  1635.     return Math.round( position ) + 'px';
  1636.   }
  1637. };
  1638.  
  1639. proto.settle = function( previousX ) {
  1640.   // keep track of frames where x hasn't moved
  1641.   if ( !this.isPointerDown && Math.round( this.x * 100 ) == Math.round( previousX * 100 ) ) {
  1642.     this.restingFrames++;
  1643.   }
  1644.   // stop animating if resting for 3 or more frames
  1645.   if ( this.restingFrames > 2 ) {
  1646.     this.isAnimating = false;
  1647.     delete this.isFreeScrolling;
  1648.     // render position with translateX when settled
  1649.     if ( is3d ) {
  1650.       this.positionSlider();
  1651.     }
  1652.     this.dispatchEvent('settle');
  1653.   }
  1654. };
  1655.  
  1656. proto.shiftWrapCells = function( x ) {
  1657.   // shift before cells
  1658.   var beforeGap = this.cursorPosition + x;
  1659.   this._shiftCells( this.beforeShiftCells, beforeGap, -1 );
  1660.   // shift after cells
  1661.   var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );
  1662.   this._shiftCells( this.afterShiftCells, afterGap, 1 );
  1663. };
  1664.  
  1665. proto._shiftCells = function( cells, gap, shift ) {
  1666.   for ( var i=0, len = cells.length; i < len; i++ ) {
  1667.     var cell = cells[i];
  1668.     var cellShift = gap > 0 ? shift : 0;
  1669.     cell.wrapShift( cellShift );
  1670.     gap -= cell.size.outerWidth;
  1671.   }
  1672. };
  1673.  
  1674. proto._unshiftCells = function( cells ) {
  1675.   if ( !cells || !cells.length ) {
  1676.     return;
  1677.   }
  1678.   for ( var i=0, len = cells.length; i < len; i++ ) {
  1679.     cells[i].wrapShift( 0 );
  1680.   }
  1681. };
  1682.  
  1683. // -------------------------- physics -------------------------- //
  1684.  
  1685. proto.integratePhysics = function() {
  1686.   this.velocity += this.accel;
  1687.   this.x += this.velocity;
  1688.   this.velocity *= this.getFrictionFactor();
  1689.   // reset acceleration
  1690.   this.accel = 0;
  1691. };
  1692.  
  1693. proto.applyForce = function( force ) {
  1694.   this.accel += force;
  1695. };
  1696.  
  1697. proto.getFrictionFactor = function() {
  1698.   return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];
  1699. };
  1700.  
  1701.  
  1702. proto.getRestingPosition = function() {
  1703.   // my thanks to Steven Wittens, who simplified this math greatly
  1704.   return this.x + this.velocity / ( 1 - this.getFrictionFactor() );
  1705. };
  1706.  
  1707. proto.applyDragForce = function() {
  1708.   if ( !this.isPointerDown ) {
  1709.     return;
  1710.   }
  1711.   // change the position to drag position by applying force
  1712.   var dragVelocity = this.dragX - this.x;
  1713.   var dragForce = dragVelocity - this.velocity;
  1714.   this.applyForce( dragForce );
  1715. };
  1716.  
  1717. proto.applySelectedAttraction = function() {
  1718.   // do not attract if pointer down or no cells
  1719.   var len = this.cells.length;
  1720.   if ( this.isPointerDown || this.isFreeScrolling || !len ) {
  1721.     return;
  1722.   }
  1723.   var cell = this.cells[ this.selectedIndex ];
  1724.   var wrap = this.options.wrapAround && len > 1 ?
  1725.     this.slideableWidth * Math.floor( this.selectedIndex / len ) : 0;
  1726.   var distance = ( cell.target + wrap ) * -1 - this.x;
  1727.   var force = distance * this.options.selectedAttraction;
  1728.   this.applyForce( force );
  1729. };
  1730.  
  1731. return proto;
  1732.  
  1733. }));
  1734.  
  1735. },{"desandro-get-style-property":4,"fizzy-ui-utils":8}],11:[function(require,module,exports){
  1736. ( function( window, factory ) {
  1737.   'use strict';
  1738.   // universal module definition
  1739.  
  1740.   if ( typeof define == 'function' && define.amd ) {
  1741.     // AMD
  1742.     define( [
  1743.       'get-size/get-size'
  1744.     ], function( getSize ) {
  1745.       return factory( window, getSize );
  1746.     });
  1747.   } else if ( typeof exports == 'object' ) {
  1748.     // CommonJS
  1749.     module.exports = factory(
  1750.       window,
  1751.       require('get-size')
  1752.     );
  1753.   } else {
  1754.     // browser global
  1755.     window.Flickity = window.Flickity || {};
  1756.     window.Flickity.Cell = factory(
  1757.       window,
  1758.       window.getSize
  1759.     );
  1760.   }
  1761.  
  1762. }( window, function factory( window, getSize ) {
  1763.  
  1764. 'use strict';
  1765.  
  1766. function Cell( elem, parent ) {
  1767.   this.element = elem;
  1768.   this.parent = parent;
  1769.  
  1770.   this.create();
  1771. }
  1772.  
  1773. var isIE8 = 'attachEvent' in window;
  1774.  
  1775. Cell.prototype.create = function() {
  1776.   this.element.style.position = 'absolute';
  1777.   // IE8 prevent child from changing focus http://stackoverflow.com/a/17525223/182183
  1778.   if ( isIE8 ) {
  1779.     this.element.setAttribute( 'unselectable', 'on' );
  1780.   }
  1781.   this.x = 0;
  1782.   this.shift = 0;
  1783. };
  1784.  
  1785. Cell.prototype.destroy = function() {
  1786.   // reset style
  1787.   this.element.style.position = '';
  1788.   var side = this.parent.originSide;
  1789.   this.element.style[ side ] = '';
  1790. };
  1791.  
  1792. Cell.prototype.getSize = function() {
  1793.   this.size = getSize( this.element );
  1794. };
  1795.  
  1796. Cell.prototype.setPosition = function( x ) {
  1797.   this.x = x;
  1798.   this.setDefaultTarget();
  1799.   this.renderPosition( x );
  1800. };
  1801.  
  1802. Cell.prototype.setDefaultTarget = function() {
  1803.   var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight';
  1804.   this.target = this.x + this.size[ marginProperty ] +
  1805.     this.size.width * this.parent.cellAlign;
  1806. };
  1807.  
  1808. Cell.prototype.renderPosition = function( x ) {
  1809.   // render position of cell with in slider
  1810.   var side = this.parent.originSide;
  1811.   this.element.style[ side ] = this.parent.getPositionValue( x );
  1812. };
  1813.  
  1814. /**
  1815.  * @param {Integer} factor - 0, 1, or -1
  1816. **/
  1817. Cell.prototype.wrapShift = function( shift ) {
  1818.   this.shift = shift;
  1819.   this.renderPosition( this.x + this.parent.slideableWidth * shift );
  1820. };
  1821.  
  1822. Cell.prototype.remove = function() {
  1823.   this.element.parentNode.removeChild( this.element );
  1824. };
  1825.  
  1826. return Cell;
  1827.  
  1828. }));
  1829.  
  1830. },{"get-size":19}],12:[function(require,module,exports){
  1831. ( function( window, factory ) {
  1832.   'use strict';
  1833.   // universal module definition
  1834.  
  1835.   if ( typeof define == 'function' && define.amd ) {
  1836.     // AMD
  1837.     define( [
  1838.       'classie/classie',
  1839.       'eventie/eventie',
  1840.       './flickity',
  1841.       'unidragger/unidragger',
  1842.       'fizzy-ui-utils/utils'
  1843.     ], function( classie, eventie, Flickity, Unidragger, utils ) {
  1844.       return factory( window, classie, eventie, Flickity, Unidragger, utils );
  1845.     });
  1846.   } else if ( typeof exports == 'object' ) {
  1847.     // CommonJS
  1848.     module.exports = factory(
  1849.       window,
  1850.       require('desandro-classie'),
  1851.       require('eventie'),
  1852.       require('./flickity'),
  1853.       require('unidragger'),
  1854.       require('fizzy-ui-utils')
  1855.     );
  1856.   } else {
  1857.     // browser global
  1858.     window.Flickity = factory(
  1859.       window,
  1860.       window.classie,
  1861.       window.eventie,
  1862.       window.Flickity,
  1863.       window.Unidragger,
  1864.       window.fizzyUIUtils
  1865.     );
  1866.   }
  1867.  
  1868. }( window, function factory( window, classie, eventie, Flickity, Unidragger, utils ) {
  1869.  
  1870. 'use strict';
  1871.  
  1872. // handle IE8 prevent default
  1873. function preventDefaultEvent( event ) {
  1874.   if ( event.preventDefault ) {
  1875.     event.preventDefault();
  1876.   } else {
  1877.     event.returnValue = false;
  1878.   }
  1879. }
  1880.  
  1881. // ----- defaults ----- //
  1882.  
  1883. utils.extend( Flickity.defaults, {
  1884.   draggable: true
  1885. });
  1886.  
  1887. // ----- create ----- //
  1888.  
  1889. Flickity.createMethods.push('_createDrag');
  1890.  
  1891. // -------------------------- drag prototype -------------------------- //
  1892.  
  1893. utils.extend( Flickity.prototype, Unidragger.prototype );
  1894.  
  1895. // --------------------------  -------------------------- //
  1896.  
  1897. Flickity.prototype._createDrag = function() {
  1898.   this.on( 'activate', this.bindDrag );
  1899.   this.on( 'uiChange', this._uiChangeDrag );
  1900.   this.on( 'childUIPointerDown', this._childUIPointerDownDrag );
  1901.   this.on( 'deactivate', this.unbindDrag );
  1902. };
  1903.  
  1904. Flickity.prototype.bindDrag = function() {
  1905.   if ( !this.options.draggable || this.isDragBound ) {
  1906.     return;
  1907.   }
  1908.   classie.add( this.element, 'is-draggable' );
  1909.   this.handles = [ this.viewport ];
  1910.   this.bindHandles();
  1911.   this.isDragBound = true;
  1912. };
  1913.  
  1914. Flickity.prototype.unbindDrag = function() {
  1915.   if ( !this.isDragBound ) {
  1916.     return;
  1917.   }
  1918.   classie.remove( this.element, 'is-draggable' );
  1919.   this.unbindHandles();
  1920.   delete this.isDragBound;
  1921. };
  1922.  
  1923. Flickity.prototype._uiChangeDrag = function() {
  1924.   delete this.isFreeScrolling;
  1925. };
  1926.  
  1927. Flickity.prototype._childUIPointerDownDrag = function( event ) {
  1928.   preventDefaultEvent( event );
  1929.   this.pointerDownFocus( event );
  1930. };
  1931.  
  1932. // -------------------------- pointer events -------------------------- //
  1933.  
  1934. Flickity.prototype.pointerDown = function( event, pointer ) {
  1935.   // dismiss range sliders
  1936.   if ( event.target.nodeName == 'INPUT' && event.target.type == 'range' ) {
  1937.     // reset pointerDown logic
  1938.     this.isPointerDown = false;
  1939.     delete this.pointerIdentifier;
  1940.     return;
  1941.   }
  1942.  
  1943.   this._dragPointerDown( event, pointer );
  1944.  
  1945.   // kludge to blur focused inputs in dragger
  1946.   var focused = document.activeElement;
  1947.   if ( focused && focused.blur && focused != this.element &&
  1948.     // do not blur body for IE9 & 10, #117
  1949.     focused != document.body ) {
  1950.     focused.blur();
  1951.   }
  1952.   this.pointerDownFocus( event );
  1953.   // stop if it was moving
  1954.   this.dragX = this.x;
  1955.   classie.add( this.viewport, 'is-pointer-down' );
  1956.   // bind move and end events
  1957.   this._bindPostStartEvents( event );
  1958.   // track scrolling
  1959.   this.pointerDownScroll = Unidragger.getScrollPosition();
  1960.   eventie.bind( window, 'scroll', this );
  1961.  
  1962.   this.dispatchEvent( 'pointerDown', event, [ pointer ] );
  1963. };
  1964.  
  1965. var touchStartEvents = {
  1966.   touchstart: true,
  1967.   MSPointerDown: true
  1968. };
  1969.  
  1970. var focusNodes = {
  1971.   INPUT: true,
  1972.   SELECT: true
  1973. };
  1974.  
  1975. Flickity.prototype.pointerDownFocus = function( event ) {
  1976.   // focus element, if not touch, and its not an input or select
  1977.   if ( !this.options.accessibility || touchStartEvents[ event.type ] ||
  1978.       focusNodes[ event.target.nodeName ] ) {
  1979.     return;
  1980.   }
  1981.   var prevScrollY = window.pageYOffset;
  1982.   this.element.focus();
  1983.   // hack to fix scroll jump after focus, #76
  1984.   if ( window.pageYOffset != prevScrollY ) {
  1985.     window.scrollTo( window.pageXOffset, prevScrollY );
  1986.   }
  1987. };
  1988.  
  1989. // ----- move ----- //
  1990.  
  1991. Flickity.prototype.hasDragStarted = function( moveVector ) {
  1992.   return Math.abs( moveVector.x ) > 3;
  1993. };
  1994.  
  1995. // ----- up ----- //
  1996.  
  1997. Flickity.prototype.pointerUp = function( event, pointer ) {
  1998.   classie.remove( this.viewport, 'is-pointer-down' );
  1999.   this.dispatchEvent( 'pointerUp', event, [ pointer ] );
  2000.   this._dragPointerUp( event, pointer );
  2001. };
  2002.  
  2003. Flickity.prototype.pointerDone = function() {
  2004.   eventie.unbind( window, 'scroll', this );
  2005.   delete this.pointerDownScroll;
  2006. };
  2007.  
  2008. // -------------------------- dragging -------------------------- //
  2009.  
  2010. Flickity.prototype.dragStart = function( event, pointer ) {
  2011.   this.dragStartPosition = this.x;
  2012.   this.startAnimation();
  2013.   this.dispatchEvent( 'dragStart', event, [ pointer ] );
  2014. };
  2015.  
  2016. Flickity.prototype.dragMove = function( event, pointer, moveVector ) {
  2017.   preventDefaultEvent( event );
  2018.  
  2019.   this.previousDragX = this.dragX;
  2020.   // reverse if right-to-left
  2021.   var direction = this.options.rightToLeft ? -1 : 1;
  2022.   var dragX = this.dragStartPosition + moveVector.x * direction;
  2023.  
  2024.   if ( !this.options.wrapAround && this.cells.length ) {
  2025.     // slow drag
  2026.     var originBound = Math.max( -this.cells[0].target, this.dragStartPosition );
  2027.     dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;
  2028.     var endBound = Math.min( -this.getLastCell().target, this.dragStartPosition );
  2029.     dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;
  2030.   }
  2031.  
  2032.   this.dragX = dragX;
  2033.  
  2034.   this.dragMoveTime = new Date();
  2035.   this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );
  2036. };
  2037.  
  2038. Flickity.prototype.dragEnd = function( event, pointer ) {
  2039.   if ( this.options.freeScroll ) {
  2040.     this.isFreeScrolling = true;
  2041.   }
  2042.   // set selectedIndex based on where flick will end up
  2043.   var index = this.dragEndRestingSelect();
  2044.  
  2045.   if ( this.options.freeScroll && !this.options.wrapAround ) {
  2046.     // if free-scroll & not wrap around
  2047.     // do not free-scroll if going outside of bounding cells
  2048.     // so bounding cells can attract slider, and keep it in bounds
  2049.     var restingX = this.getRestingPosition();
  2050.     this.isFreeScrolling = -restingX > this.cells[0].target &&
  2051.       -restingX < this.getLastCell().target;
  2052.   } else if ( !this.options.freeScroll && index == this.selectedIndex ) {
  2053.     // boost selection if selected index has not changed
  2054.     index += this.dragEndBoostSelect();
  2055.   }
  2056.   delete this.previousDragX;
  2057.   // apply selection
  2058.   // TODO refactor this, selecting here feels weird
  2059.   this.select( index );
  2060.   this.dispatchEvent( 'dragEnd', event, [ pointer ] );
  2061. };
  2062.  
  2063. Flickity.prototype.dragEndRestingSelect = function() {
  2064.   var restingX = this.getRestingPosition();
  2065.   // how far away from selected cell
  2066.   var distance = Math.abs( this.getCellDistance( -restingX, this.selectedIndex ) );
  2067.   // get closet resting going up and going down
  2068.   var positiveResting = this._getClosestResting( restingX, distance, 1 );
  2069.   var negativeResting = this._getClosestResting( restingX, distance, -1 );
  2070.   // use closer resting for wrap-around
  2071.   var index = positiveResting.distance < negativeResting.distance ?
  2072.     positiveResting.index : negativeResting.index;
  2073.   return index;
  2074. };
  2075.  
  2076. /**
  2077.  * given resting X and distance to selected cell
  2078.  * get the distance and index of the closest cell
  2079.  * @param {Number} restingX - estimated post-flick resting position
  2080.  * @param {Number} distance - distance to selected cell
  2081.  * @param {Integer} increment - +1 or -1, going up or down
  2082.  * @returns {Object} - { distance: {Number}, index: {Integer} }
  2083.  */
  2084. Flickity.prototype._getClosestResting = function( restingX, distance, increment ) {
  2085.   var index = this.selectedIndex;
  2086.   var minDistance = Infinity;
  2087.   var condition = this.options.contain && !this.options.wrapAround ?
  2088.     // if contain, keep going if distance is equal to minDistance
  2089.     function( d, md ) { return d <= md; } : function( d, md ) { return d < md; };
  2090.   while ( condition( distance, minDistance ) ) {
  2091.     // measure distance to next cell
  2092.     index += increment;
  2093.     minDistance = distance;
  2094.     distance = this.getCellDistance( -restingX, index );
  2095.     if ( distance === null ) {
  2096.       break;
  2097.     }
  2098.     distance = Math.abs( distance );
  2099.   }
  2100.   return {
  2101.     distance: minDistance,
  2102.     // selected was previous index
  2103.     index: index - increment
  2104.   };
  2105. };
  2106.  
  2107. /**
  2108.  * measure distance between x and a cell target
  2109.  * @param {Number} x
  2110.  * @param {Integer} index - cell index
  2111.  */
  2112. Flickity.prototype.getCellDistance = function( x, index ) {
  2113.   var len = this.cells.length;
  2114.   // wrap around if at least 2 cells
  2115.   var isWrapAround = this.options.wrapAround && len > 1;
  2116.   var cellIndex = isWrapAround ? utils.modulo( index, len ) : index;
  2117.   var cell = this.cells[ cellIndex ];
  2118.   if ( !cell ) {
  2119.     return null;
  2120.   }
  2121.   // add distance for wrap-around cells
  2122.   var wrap = isWrapAround ? this.slideableWidth * Math.floor( index / len ) : 0;
  2123.   return x - ( cell.target + wrap );
  2124. };
  2125.  
  2126. Flickity.prototype.dragEndBoostSelect = function() {
  2127.   // do not boost if no previousDragX or dragMoveTime
  2128.   if ( this.previousDragX === undefined || !this.dragMoveTime ||
  2129.     // or if drag was held for 100 ms
  2130.     new Date() - this.dragMoveTime > 100 ) {
  2131.     return 0;
  2132.   }
  2133.  
  2134.   var distance = this.getCellDistance( -this.dragX, this.selectedIndex );
  2135.   var delta = this.previousDragX - this.dragX;
  2136.   if ( distance > 0 && delta > 0 ) {
  2137.     // boost to next if moving towards the right, and positive velocity
  2138.     return 1;
  2139.   } else if ( distance < 0 && delta < 0 ) {
  2140.     // boost to previous if moving towards the left, and negative velocity
  2141.     return -1;
  2142.   }
  2143.   return 0;
  2144. };
  2145.  
  2146. // ----- staticClick ----- //
  2147.  
  2148. Flickity.prototype.staticClick = function( event, pointer ) {
  2149.   // get clickedCell, if cell was clicked
  2150.   var clickedCell = this.getParentCell( event.target );
  2151.   var cellElem = clickedCell && clickedCell.element;
  2152.   var cellIndex = clickedCell && utils.indexOf( this.cells, clickedCell );
  2153.   this.dispatchEvent( 'staticClick', event, [ pointer, cellElem, cellIndex ] );
  2154. };
  2155.  
  2156. // -----  ----- //
  2157.  
  2158. return Flickity;
  2159.  
  2160. }));
  2161.  
  2162. },{"./flickity":13,"desandro-classie":3,"eventie":7,"fizzy-ui-utils":8,"unidragger":22}],13:[function(require,module,exports){
  2163. /**
  2164.  * Flickity main
  2165.  */
  2166.  
  2167. ( function( window, factory ) {
  2168.   'use strict';
  2169.   // universal module definition
  2170.  
  2171.   if ( typeof define == 'function' && define.amd ) {
  2172.     // AMD
  2173.     define( [
  2174.       'classie/classie',
  2175.       'eventEmitter/EventEmitter',
  2176.       'eventie/eventie',
  2177.       'get-size/get-size',
  2178.       'fizzy-ui-utils/utils',
  2179.       './cell',
  2180.       './animate'
  2181.     ], function( classie, EventEmitter, eventie, getSize, utils, Cell, animatePrototype ) {
  2182.       return factory( window, classie, EventEmitter, eventie, getSize, utils, Cell, animatePrototype );
  2183.     });
  2184.   } else if ( typeof exports == 'object' ) {
  2185.     // CommonJS
  2186.     module.exports = factory(
  2187.       window,
  2188.       require('desandro-classie'),
  2189.       require('wolfy87-eventemitter'),
  2190.       require('eventie'),
  2191.       require('get-size'),
  2192.       require('fizzy-ui-utils'),
  2193.       require('./cell'),
  2194.       require('./animate')
  2195.     );
  2196.   } else {
  2197.     // browser global
  2198.     var _Flickity = window.Flickity;
  2199.  
  2200.     window.Flickity = factory(
  2201.       window,
  2202.       window.classie,
  2203.       window.EventEmitter,
  2204.       window.eventie,
  2205.       window.getSize,
  2206.       window.fizzyUIUtils,
  2207.       _Flickity.Cell,
  2208.       _Flickity.animatePrototype
  2209.     );
  2210.   }
  2211.  
  2212. }( window, function factory( window, classie, EventEmitter, eventie, getSize,
  2213.   utils, Cell, animatePrototype ) {
  2214.  
  2215. 'use strict';
  2216.  
  2217. // vars
  2218. var jQuery = window.jQuery;
  2219. var getComputedStyle = window.getComputedStyle;
  2220. var console = window.console;
  2221.  
  2222. function moveElements( elems, toElem ) {
  2223.   elems = utils.makeArray( elems );
  2224.   while ( elems.length ) {
  2225.     toElem.appendChild( elems.shift() );
  2226.   }
  2227. }
  2228.  
  2229. // -------------------------- Flickity -------------------------- //
  2230.  
  2231. // globally unique identifiers
  2232. var GUID = 0;
  2233. // internal store of all Flickity intances
  2234. var instances = {};
  2235.  
  2236. function Flickity( element, options ) {
  2237.   var queryElement = utils.getQueryElement( element );
  2238.   if ( !queryElement ) {
  2239.     if ( console ) {
  2240.       console.error( 'Bad element for Flickity: ' + ( queryElement || element ) );
  2241.     }
  2242.     return;
  2243.   }
  2244.   this.element = queryElement;
  2245.   // add jQuery
  2246.   if ( jQuery ) {
  2247.     this.$element = jQuery( this.element );
  2248.   }
  2249.   // options
  2250.   this.options = utils.extend( {}, this.constructor.defaults );
  2251.   this.option( options );
  2252.  
  2253.   // kick things off
  2254.   this._create();
  2255. }
  2256.  
  2257. Flickity.defaults = {
  2258.   accessibility: true,
  2259.   cellAlign: 'center',
  2260.   // cellSelector: undefined,
  2261.   // contain: false,
  2262.   freeScrollFriction: 0.075, // friction when free-scrolling
  2263.   friction: 0.28, // friction when selecting
  2264.   // initialIndex: 0,
  2265.   percentPosition: true,
  2266.   resize: true,
  2267.   selectedAttraction: 0.025,
  2268.   setGallerySize: true
  2269.   // watchCSS: false,
  2270.   // wrapAround: false
  2271. };
  2272.  
  2273. // hash of methods triggered on _create()
  2274. Flickity.createMethods = [];
  2275.  
  2276. // inherit EventEmitter
  2277. utils.extend( Flickity.prototype, EventEmitter.prototype );
  2278.  
  2279. Flickity.prototype._create = function() {
  2280.   // add id for Flickity.data
  2281.   var id = this.guid = ++GUID;
  2282.   this.element.flickityGUID = id; // expando
  2283.   instances[ id ] = this; // associate via id
  2284.   // initial properties
  2285.   this.selectedIndex = 0;
  2286.   // how many frames slider has been in same position
  2287.   this.restingFrames = 0;
  2288.   // initial physics properties
  2289.   this.x = 0;
  2290.   this.velocity = 0;
  2291.   this.accel = 0;
  2292.   this.originSide = this.options.rightToLeft ? 'right' : 'left';
  2293.   // create viewport & slider
  2294.   this.viewport = document.createElement('div');
  2295.   this.viewport.className = 'flickity-viewport';
  2296.   Flickity.setUnselectable( this.viewport );
  2297.   this._createSlider();
  2298.  
  2299.   if ( this.options.resize || this.options.watchCSS ) {
  2300.     eventie.bind( window, 'resize', this );
  2301.     this.isResizeBound = true;
  2302.   }
  2303.  
  2304.   for ( var i=0, len = Flickity.createMethods.length; i < len; i++ ) {
  2305.     var method = Flickity.createMethods[i];
  2306.     this[ method ]();
  2307.   }
  2308.  
  2309.   if ( this.options.watchCSS ) {
  2310.     this.watchCSS();
  2311.   } else {
  2312.     this.activate();
  2313.   }
  2314.  
  2315. };
  2316.  
  2317. /**
  2318.  * set options
  2319.  * @param {Object} opts
  2320.  */
  2321. Flickity.prototype.option = function( opts ) {
  2322.   utils.extend( this.options, opts );
  2323. };
  2324.  
  2325. Flickity.prototype.activate = function() {
  2326.   if ( this.isActive ) {
  2327.     return;
  2328.   }
  2329.   this.isActive = true;
  2330.   classie.add( this.element, 'flickity-enabled' );
  2331.   if ( this.options.rightToLeft ) {
  2332.     classie.add( this.element, 'flickity-rtl' );
  2333.   }
  2334.  
  2335.   this.getSize();
  2336.   // move initial cell elements so they can be loaded as cells
  2337.   var cellElems = this._filterFindCellElements( this.element.children );
  2338.   moveElements( cellElems, this.slider );
  2339.   this.viewport.appendChild( this.slider );
  2340.   this.element.appendChild( this.viewport );
  2341.   // get cells from children
  2342.   this.reloadCells();
  2343.  
  2344.   if ( this.options.accessibility ) {
  2345.     // allow element to focusable
  2346.     this.element.tabIndex = 0;
  2347.     // listen for key presses
  2348.     eventie.bind( this.element, 'keydown', this );
  2349.   }
  2350.  
  2351.   this.emit('activate');
  2352.  
  2353.   var index;
  2354.   var initialIndex = this.options.initialIndex;
  2355.   if ( this.isInitActivated ) {
  2356.     index = this.selectedIndex;
  2357.   } else if ( initialIndex !== undefined ) {
  2358.     index = this.cells[ initialIndex ] ? initialIndex : 0;
  2359.   } else {
  2360.     index = 0;
  2361.   }
  2362.   // select instantly
  2363.   this.select( index, false, true );
  2364.   // flag for initial activation, for using initialIndex
  2365.   this.isInitActivated = true;
  2366. };
  2367.  
  2368. // slider positions the cells
  2369. Flickity.prototype._createSlider = function() {
  2370.   // slider element does all the positioning
  2371.   var slider = document.createElement('div');
  2372.   slider.className = 'flickity-slider';
  2373.   slider.style[ this.originSide ] = 0;
  2374.   this.slider = slider;
  2375. };
  2376.  
  2377. Flickity.prototype._filterFindCellElements = function( elems ) {
  2378.   return utils.filterFindElements( elems, this.options.cellSelector );
  2379. };
  2380.  
  2381. // goes through all children
  2382. Flickity.prototype.reloadCells = function() {
  2383.   // collection of item elements
  2384.   this.cells = this._makeCells( this.slider.children );
  2385.   this.positionCells();
  2386.   this._getWrapShiftCells();
  2387.   this.setGallerySize();
  2388. };
  2389.  
  2390. /**
  2391.  * turn elements into Flickity.Cells
  2392.  * @param {Array or NodeList or HTMLElement} elems
  2393.  * @returns {Array} items - collection of new Flickity Cells
  2394.  */
  2395. Flickity.prototype._makeCells = function( elems ) {
  2396.   var cellElems = this._filterFindCellElements( elems );
  2397.  
  2398.   // create new Flickity for collection
  2399.   var cells = [];
  2400.   for ( var i=0, len = cellElems.length; i < len; i++ ) {
  2401.     var elem = cellElems[i];
  2402.     var cell = new Cell( elem, this );
  2403.     cells.push( cell );
  2404.   }
  2405.  
  2406.   return cells;
  2407. };
  2408.  
  2409. Flickity.prototype.getLastCell = function() {
  2410.   return this.cells[ this.cells.length - 1 ];
  2411. };
  2412.  
  2413. // positions all cells
  2414. Flickity.prototype.positionCells = function() {
  2415.   // size all cells
  2416.   this._sizeCells( this.cells );
  2417.   // position all cells
  2418.   this._positionCells( 0 );
  2419. };
  2420.  
  2421. /**
  2422.  * position certain cells
  2423.  * @param {Integer} index - which cell to start with
  2424.  */
  2425. Flickity.prototype._positionCells = function( index ) {
  2426.   index = index || 0;
  2427.   // also measure maxCellHeight
  2428.   // start 0 if positioning all cells
  2429.   this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;
  2430.   var cellX = 0;
  2431.   // get cellX
  2432.   if ( index > 0 ) {
  2433.     var startCell = this.cells[ index - 1 ];
  2434.     cellX = startCell.x + startCell.size.outerWidth;
  2435.   }
  2436.   var cell;
  2437.   for ( var len = this.cells.length, i=index; i < len; i++ ) {
  2438.     cell = this.cells[i];
  2439.     cell.setPosition( cellX );
  2440.     cellX += cell.size.outerWidth;
  2441.     this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );
  2442.   }
  2443.   // keep track of cellX for wrap-around
  2444.   this.slideableWidth = cellX;
  2445.   // contain cell target
  2446.   this._containCells();
  2447. };
  2448.  
  2449. /**
  2450.  * cell.getSize() on multiple cells
  2451.  * @param {Array} cells
  2452.  */
  2453. Flickity.prototype._sizeCells = function( cells ) {
  2454.   for ( var i=0, len = cells.length; i < len; i++ ) {
  2455.     var cell = cells[i];
  2456.     cell.getSize();
  2457.   }
  2458. };
  2459.  
  2460. // alias _init for jQuery plugin .flickity()
  2461. Flickity.prototype._init =
  2462. Flickity.prototype.reposition = function() {
  2463.   this.positionCells();
  2464.   this.positionSliderAtSelected();
  2465. };
  2466.  
  2467. Flickity.prototype.getSize = function() {
  2468.   this.size = getSize( this.element );
  2469.   this.setCellAlign();
  2470.   this.cursorPosition = this.size.innerWidth * this.cellAlign;
  2471. };
  2472.  
  2473. var cellAlignShorthands = {
  2474.   // cell align, then based on origin side
  2475.   center: {
  2476.     left: 0.5,
  2477.     right: 0.5
  2478.   },
  2479.   left: {
  2480.     left: 0,
  2481.     right: 1
  2482.   },
  2483.   right: {
  2484.     right: 0,
  2485.     left: 1
  2486.   }
  2487. };
  2488.  
  2489. Flickity.prototype.setCellAlign = function() {
  2490.   var shorthand = cellAlignShorthands[ this.options.cellAlign ];
  2491.   this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign;
  2492. };
  2493.  
  2494. Flickity.prototype.setGallerySize = function() {
  2495.   if ( this.options.setGallerySize ) {
  2496.     this.viewport.style.height = this.maxCellHeight + 'px';
  2497.   }
  2498. };
  2499.  
  2500. Flickity.prototype._getWrapShiftCells = function() {
  2501.   // only for wrap-around
  2502.   if ( !this.options.wrapAround ) {
  2503.     return;
  2504.   }
  2505.   // unshift previous cells
  2506.   this._unshiftCells( this.beforeShiftCells );
  2507.   this._unshiftCells( this.afterShiftCells );
  2508.   // get before cells
  2509.   // initial gap
  2510.   var gapX = this.cursorPosition;
  2511.   var cellIndex = this.cells.length - 1;
  2512.   this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 );
  2513.   // get after cells
  2514.   // ending gap between last cell and end of gallery viewport
  2515.   gapX = this.size.innerWidth - this.cursorPosition;
  2516.   // start cloning at first cell, working forwards
  2517.   this.afterShiftCells = this._getGapCells( gapX, 0, 1 );
  2518. };
  2519.  
  2520. Flickity.prototype._getGapCells = function( gapX, cellIndex, increment ) {
  2521.   // keep adding cells until the cover the initial gap
  2522.   var cells = [];
  2523.   while ( gapX > 0 ) {
  2524.     var cell = this.cells[ cellIndex ];
  2525.     if ( !cell ) {
  2526.       break;
  2527.     }
  2528.     cells.push( cell );
  2529.     cellIndex += increment;
  2530.     gapX -= cell.size.outerWidth;
  2531.   }
  2532.   return cells;
  2533. };
  2534.  
  2535. // ----- contain ----- //
  2536.  
  2537. // contain cell targets so no excess sliding
  2538. Flickity.prototype._containCells = function() {
  2539.   if ( !this.options.contain || this.options.wrapAround || !this.cells.length ) {
  2540.     return;
  2541.   }
  2542.   var startMargin = this.options.rightToLeft ? 'marginRight' : 'marginLeft';
  2543.   var endMargin = this.options.rightToLeft ? 'marginLeft' : 'marginRight';
  2544.   var firstCellStartMargin = this.cells[0].size[ startMargin ];
  2545.   var lastCell = this.getLastCell();
  2546.   var contentWidth = this.slideableWidth - lastCell.size[ endMargin ];
  2547.   var endLimit = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );
  2548.   // content is less than gallery size
  2549.   var isContentSmaller = contentWidth < this.size.innerWidth;
  2550.   // contain each cell target
  2551.   for ( var i=0, len = this.cells.length; i < len; i++ ) {
  2552.     var cell = this.cells[i];
  2553.     // reset default target
  2554.     cell.setDefaultTarget();
  2555.     if ( isContentSmaller ) {
  2556.       // all cells fit inside gallery
  2557.       cell.target = contentWidth * this.cellAlign;
  2558.     } else {
  2559.       // contain to bounds
  2560.       cell.target = Math.max( cell.target, this.cursorPosition + firstCellStartMargin );
  2561.       cell.target = Math.min( cell.target, endLimit );
  2562.     }
  2563.   }
  2564. };
  2565.  
  2566. // -----  ----- //
  2567.  
  2568. /**
  2569.  * emits events via eventEmitter and jQuery events
  2570.  * @param {String} type - name of event
  2571.  * @param {Event} event - original event
  2572.  * @param {Array} args - extra arguments
  2573.  */
  2574. Flickity.prototype.dispatchEvent = function( type, event, args ) {
  2575.   var emitArgs = [ event ].concat( args );
  2576.   this.emitEvent( type, emitArgs );
  2577.  
  2578.   if ( jQuery && this.$element ) {
  2579.     if ( event ) {
  2580.       // create jQuery event
  2581.       var $event = jQuery.Event( event );
  2582.       $event.type = type;
  2583.       this.$element.trigger( $event, args );
  2584.     } else {
  2585.       // just trigger with type if no event available
  2586.       this.$element.trigger( type, args );
  2587.     }
  2588.   }
  2589. };
  2590.  
  2591. // -------------------------- select -------------------------- //
  2592.  
  2593. /**
  2594.  * @param {Integer} index - index of the cell
  2595.  * @param {Boolean} isWrap - will wrap-around to last/first if at the end
  2596.  * @param {Boolean} isInstant - will immediately set position at selected cell
  2597.  */
  2598. Flickity.prototype.select = function( index, isWrap, isInstant ) {
  2599.   if ( !this.isActive ) {
  2600.     return;
  2601.   }
  2602.   index = parseInt( index, 10 );
  2603.   // wrap position so slider is within normal area
  2604.   var len = this.cells.length;
  2605.   if ( this.options.wrapAround && len > 1 ) {
  2606.     if ( index < 0 ) {
  2607.       this.x -= this.slideableWidth;
  2608.     } else if ( index >= len ) {
  2609.       this.x += this.slideableWidth;
  2610.     }
  2611.   }
  2612.  
  2613.   if ( this.options.wrapAround || isWrap ) {
  2614.     index = utils.modulo( index, len );
  2615.   }
  2616.   // bail if invalid index
  2617.   if ( !this.cells[ index ] ) {
  2618.     return;
  2619.   }
  2620.   this.selectedIndex = index;
  2621.   this.setSelectedCell();
  2622.   if ( isInstant ) {
  2623.     this.positionSliderAtSelected();
  2624.   } else {
  2625.     this.startAnimation();
  2626.   }
  2627.   this.dispatchEvent('cellSelect');
  2628. };
  2629.  
  2630. Flickity.prototype.previous = function( isWrap ) {
  2631.   this.select( this.selectedIndex - 1, isWrap );
  2632. };
  2633.  
  2634. Flickity.prototype.next = function( isWrap ) {
  2635.   this.select( this.selectedIndex + 1, isWrap );
  2636. };
  2637.  
  2638. Flickity.prototype.setSelectedCell = function() {
  2639.   this._removeSelectedCellClass();
  2640.   this.selectedCell = this.cells[ this.selectedIndex ];
  2641.   this.selectedElement = this.selectedCell.element;
  2642.   classie.add( this.selectedElement, 'is-selected' );
  2643. };
  2644.  
  2645. Flickity.prototype._removeSelectedCellClass = function() {
  2646.   if ( this.selectedCell ) {
  2647.     classie.remove( this.selectedCell.element, 'is-selected' );
  2648.   }
  2649. };
  2650.  
  2651. // -------------------------- get cells -------------------------- //
  2652.  
  2653. /**
  2654.  * get Flickity.Cell, given an Element
  2655.  * @param {Element} elem
  2656.  * @returns {Flickity.Cell} item
  2657.  */
  2658. Flickity.prototype.getCell = function( elem ) {
  2659.   // loop through cells to get the one that matches
  2660.   for ( var i=0, len = this.cells.length; i < len; i++ ) {
  2661.     var cell = this.cells[i];
  2662.     if ( cell.element == elem ) {
  2663.       return cell;
  2664.     }
  2665.   }
  2666. };
  2667.  
  2668. /**
  2669.  * get collection of Flickity.Cells, given Elements
  2670.  * @param {Element, Array, NodeList} elems
  2671.  * @returns {Array} cells - Flickity.Cells
  2672.  */
  2673. Flickity.prototype.getCells = function( elems ) {
  2674.   elems = utils.makeArray( elems );
  2675.   var cells = [];
  2676.   for ( var i=0, len = elems.length; i < len; i++ ) {
  2677.     var elem = elems[i];
  2678.     var cell = this.getCell( elem );
  2679.     if ( cell ) {
  2680.       cells.push( cell );
  2681.     }
  2682.   }
  2683.   return cells;
  2684. };
  2685.  
  2686. /**
  2687.  * get cell elements
  2688.  * @returns {Array} cellElems
  2689.  */
  2690. Flickity.prototype.getCellElements = function() {
  2691.   var cellElems = [];
  2692.   for ( var i=0, len = this.cells.length; i < len; i++ ) {
  2693.     cellElems.push( this.cells[i].element );
  2694.   }
  2695.   return cellElems;
  2696. };
  2697.  
  2698. /**
  2699.  * get parent cell from an element
  2700.  * @param {Element} elem
  2701.  * @returns {Flickit.Cell} cell
  2702.  */
  2703. Flickity.prototype.getParentCell = function( elem ) {
  2704.   // first check if elem is cell
  2705.   var cell = this.getCell( elem );
  2706.   if ( cell ) {
  2707.     return cell;
  2708.   }
  2709.   // try to get parent cell elem
  2710.   elem = utils.getParent( elem, '.flickity-slider > *' );
  2711.   return this.getCell( elem );
  2712. };
  2713.  
  2714. /**
  2715.  * get cells adjacent to a cell
  2716.  * @param {Integer} adjCount - number of adjacent cells
  2717.  * @param {Integer} index - index of cell to start
  2718.  * @returns {Array} cells - array of Flickity.Cells
  2719.  */
  2720. Flickity.prototype.getAdjacentCellElements = function( adjCount, index ) {
  2721.   if ( !adjCount ) {
  2722.     return [ this.selectedElement ];
  2723.   }
  2724.   index = index === undefined ? this.selectedIndex : index;
  2725.  
  2726.   var len = this.cells.length;
  2727.   if ( 1 + ( adjCount * 2 ) >= len ) {
  2728.     return this.getCellElements();
  2729.   }
  2730.  
  2731.   var cellElems = [];
  2732.   for ( var i = index - adjCount; i <= index + adjCount ; i++ ) {
  2733.     var cellIndex = this.options.wrapAround ? utils.modulo( i, len ) : i;
  2734.     var cell = this.cells[ cellIndex ];
  2735.     if ( cell ) {
  2736.       cellElems.push( cell.element );
  2737.     }
  2738.   }
  2739.   return cellElems;
  2740. };
  2741.  
  2742. // -------------------------- events -------------------------- //
  2743.  
  2744. Flickity.prototype.uiChange = function() {
  2745.   this.emit('uiChange');
  2746. };
  2747.  
  2748. Flickity.prototype.childUIPointerDown = function( event ) {
  2749.   this.emitEvent( 'childUIPointerDown', [ event ] );
  2750. };
  2751.  
  2752. // ----- resize ----- //
  2753.  
  2754. Flickity.prototype.onresize = function() {
  2755.   this.watchCSS();
  2756.   this.resize();
  2757. };
  2758.  
  2759. utils.debounceMethod( Flickity, 'onresize', 150 );
  2760.  
  2761. Flickity.prototype.resize = function() {
  2762.   if ( !this.isActive ) {
  2763.     return;
  2764.   }
  2765.   this.getSize();
  2766.   // wrap values
  2767.   if ( this.options.wrapAround ) {
  2768.     this.x = utils.modulo( this.x, this.slideableWidth );
  2769.   }
  2770.   this.positionCells();
  2771.   this._getWrapShiftCells();
  2772.   this.setGallerySize();
  2773.   this.positionSliderAtSelected();
  2774. };
  2775.  
  2776. var supportsConditionalCSS = Flickity.supportsConditionalCSS = ( function() {
  2777.   var supports;
  2778.   return function checkSupport() {
  2779.     if ( supports !== undefined ) {
  2780.       return supports;
  2781.     }
  2782.     if ( !getComputedStyle ) {
  2783.       supports = false;
  2784.       return;
  2785.     }
  2786.     // style body's :after and check that
  2787.     var style = document.createElement('style');
  2788.     var cssText = document.createTextNode('body:after { content: "foo"; display: none; }');
  2789.     style.appendChild( cssText );
  2790.     document.head.appendChild( style );
  2791.     var afterContent = getComputedStyle( document.body, ':after' ).content;
  2792.     // check if able to get :after content
  2793.     supports = afterContent.indexOf('foo') != -1;
  2794.     document.head.removeChild( style );
  2795.     return supports;
  2796.   };
  2797. })();
  2798.  
  2799. // watches the :after property, activates/deactivates
  2800. Flickity.prototype.watchCSS = function() {
  2801.   var watchOption = this.options.watchCSS;
  2802.   if ( !watchOption ) {
  2803.     return;
  2804.   }
  2805.   var supports = supportsConditionalCSS();
  2806.   if ( !supports ) {
  2807.     // activate if watch option is fallbackOn
  2808.     var method = watchOption == 'fallbackOn' ? 'activate' : 'deactivate';
  2809.     this[ method ]();
  2810.     return;
  2811.   }
  2812.  
  2813.   var afterContent = getComputedStyle( this.element, ':after' ).content;
  2814.   // activate if :after { content: 'flickity' }
  2815.   if ( afterContent.indexOf('flickity') != -1 ) {
  2816.     this.activate();
  2817.   } else {
  2818.     this.deactivate();
  2819.   }
  2820. };
  2821.  
  2822. // ----- keydown ----- //
  2823.  
  2824. // go previous/next if left/right keys pressed
  2825. Flickity.prototype.onkeydown = function( event ) {
  2826.   // only work if element is in focus
  2827.   if ( !this.options.accessibility ||
  2828.     ( document.activeElement && document.activeElement != this.element ) ) {
  2829.     return;
  2830.   }
  2831.  
  2832.   if ( event.keyCode == 37 ) {
  2833.     // go left
  2834.     var leftMethod = this.options.rightToLeft ? 'next' : 'previous';
  2835.     this.uiChange();
  2836.     this[ leftMethod ]();
  2837.   } else if ( event.keyCode == 39 ) {
  2838.     // go right
  2839.     var rightMethod = this.options.rightToLeft ? 'previous' : 'next';
  2840.     this.uiChange();
  2841.     this[ rightMethod ]();
  2842.   }
  2843. };
  2844.  
  2845. // -------------------------- destroy -------------------------- //
  2846.  
  2847. // deactivate all Flickity functionality, but keep stuff available
  2848. Flickity.prototype.deactivate = function() {
  2849.   if ( !this.isActive ) {
  2850.     return;
  2851.   }
  2852.   classie.remove( this.element, 'flickity-enabled' );
  2853.   classie.remove( this.element, 'flickity-rtl' );
  2854.   // destroy cells
  2855.   for ( var i=0, len = this.cells.length; i < len; i++ ) {
  2856.     var cell = this.cells[i];
  2857.     cell.destroy();
  2858.   }
  2859.   this._removeSelectedCellClass();
  2860.   this.element.removeChild( this.viewport );
  2861.   // move child elements back into element
  2862.   moveElements( this.slider.children, this.element );
  2863.   if ( this.options.accessibility ) {
  2864.     this.element.removeAttribute('tabIndex');
  2865.     eventie.unbind( this.element, 'keydown', this );
  2866.   }
  2867.   // set flags
  2868.   this.isActive = false;
  2869.   this.emit('deactivate');
  2870. };
  2871.  
  2872. Flickity.prototype.destroy = function() {
  2873.   this.deactivate();
  2874.   if ( this.isResizeBound ) {
  2875.     eventie.unbind( window, 'resize', this );
  2876.   }
  2877.   this.emit('destroy');
  2878.   if ( jQuery && this.$element ) {
  2879.     jQuery.removeData( this.element, 'flickity' );
  2880.   }
  2881.   delete this.element.flickityGUID;
  2882.   delete instances[ this.guid ];
  2883. };
  2884.  
  2885. // -------------------------- prototype -------------------------- //
  2886.  
  2887. utils.extend( Flickity.prototype, animatePrototype );
  2888.  
  2889. // -------------------------- extras -------------------------- //
  2890.  
  2891. // quick check for IE8
  2892. var isIE8 = 'attachEvent' in window;
  2893.  
  2894. Flickity.setUnselectable = function( elem ) {
  2895.   if ( !isIE8 ) {
  2896.     return;
  2897.   }
  2898.   // IE8 prevent child from changing focus http://stackoverflow.com/a/17525223/182183
  2899.   elem.setAttribute( 'unselectable', 'on' );
  2900. };
  2901.  
  2902. /**
  2903.  * get Flickity instance from element
  2904.  * @param {Element} elem
  2905.  * @returns {Flickity}
  2906.  */
  2907. Flickity.data = function( elem ) {
  2908.   elem = utils.getQueryElement( elem );
  2909.   var id = elem && elem.flickityGUID;
  2910.   return id && instances[ id ];
  2911. };
  2912.  
  2913. utils.htmlInit( Flickity, 'flickity' );
  2914.  
  2915. if ( jQuery && jQuery.bridget ) {
  2916.   jQuery.bridget( 'flickity', Flickity );
  2917. }
  2918.  
  2919. Flickity.Cell = Cell;
  2920.  
  2921. return Flickity;
  2922.  
  2923. }));
  2924.  
  2925. },{"./animate":10,"./cell":11,"desandro-classie":3,"eventie":7,"fizzy-ui-utils":8,"get-size":19,"wolfy87-eventemitter":24}],14:[function(require,module,exports){
  2926. /*!
  2927.  * Flickity v1.2.1
  2928.  * Touch, responsive, flickable galleries
  2929.  *
  2930.  * Licensed GPLv3 for open source use
  2931.  * or Flickity Commercial License for commercial use
  2932.  *
  2933.  * http://flickity.metafizzy.co
  2934.  * Copyright 2015 Metafizzy
  2935.  */
  2936.  
  2937. ( function( window, factory ) {
  2938.   'use strict';
  2939.   // universal module definition
  2940.  
  2941.   if ( typeof define == 'function' && define.amd ) {
  2942.     // AMD
  2943.     define( [
  2944.       './flickity',
  2945.       './drag',
  2946.       './prev-next-button',
  2947.       './page-dots',
  2948.       './player',
  2949.       './add-remove-cell',
  2950.       './lazyload'
  2951.     ], factory );
  2952.   } else if ( typeof exports == 'object' ) {
  2953.     // CommonJS
  2954.     module.exports = factory(
  2955.       require('./flickity'),
  2956.       require('./drag'),
  2957.       require('./prev-next-button'),
  2958.       require('./page-dots'),
  2959.       require('./player'),
  2960.       require('./add-remove-cell'),
  2961.       require('./lazyload')
  2962.     );
  2963.   }
  2964.  
  2965. })( window, function factory( Flickity ) {
  2966.   /*jshint strict: false*/
  2967.   return Flickity;
  2968. });
  2969.  
  2970. },{"./add-remove-cell":9,"./drag":12,"./flickity":13,"./lazyload":15,"./page-dots":16,"./player":17,"./prev-next-button":18}],15:[function(require,module,exports){
  2971. ( function( window, factory ) {
  2972.   'use strict';
  2973.   // universal module definition
  2974.  
  2975.   if ( typeof define == 'function' && define.amd ) {
  2976.     // AMD
  2977.     define( [
  2978.       'classie/classie',
  2979.       'eventie/eventie',
  2980.       './flickity',
  2981.       'fizzy-ui-utils/utils'
  2982.     ], function( classie, eventie, Flickity, utils ) {
  2983.       return factory( window, classie, eventie, Flickity, utils );
  2984.     });
  2985.   } else if ( typeof exports == 'object' ) {
  2986.     // CommonJS
  2987.     module.exports = factory(
  2988.       window,
  2989.       require('desandro-classie'),
  2990.       require('eventie'),
  2991.       require('./flickity'),
  2992.       require('fizzy-ui-utils')
  2993.     );
  2994.   } else {
  2995.     // browser global
  2996.     factory(
  2997.       window,
  2998.       window.classie,
  2999.       window.eventie,
  3000.       window.Flickity,
  3001.       window.fizzyUIUtils
  3002.     );
  3003.   }
  3004.  
  3005. }( window, function factory( window, classie, eventie, Flickity, utils ) {
  3006. 'use strict';
  3007.  
  3008. Flickity.createMethods.push('_createLazyload');
  3009.  
  3010. Flickity.prototype._createLazyload = function() {
  3011.   this.on( 'cellSelect', this.lazyLoad );
  3012. };
  3013.  
  3014. Flickity.prototype.lazyLoad = function() {
  3015.   var lazyLoad = this.options.lazyLoad;
  3016.   if ( !lazyLoad ) {
  3017.     return;
  3018.   }
  3019.   // get adjacent cells, use lazyLoad option for adjacent count
  3020.   var adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;
  3021.   var cellElems = this.getAdjacentCellElements( adjCount );
  3022.   // get lazy images in those cells
  3023.   var lazyImages = [];
  3024.   for ( var i=0, len = cellElems.length; i < len; i++ ) {
  3025.     var cellElem = cellElems[i];
  3026.     var lazyCellImages = getCellLazyImages( cellElem );
  3027.     lazyImages = lazyImages.concat( lazyCellImages );
  3028.   }
  3029.   // load lazy images
  3030.   for ( i=0, len = lazyImages.length; i < len; i++ ) {
  3031.     var img = lazyImages[i];
  3032.     new LazyLoader( img, this );
  3033.   }
  3034. };
  3035.  
  3036. function getCellLazyImages( cellElem ) {
  3037.   // check if cell element is lazy image
  3038.   if ( cellElem.nodeName == 'IMG' &&
  3039.     cellElem.getAttribute('data-flickity-lazyload') ) {
  3040.     return [ cellElem ];
  3041.   }
  3042.   // select lazy images in cell
  3043.   var imgs = cellElem.querySelectorAll('img[data-flickity-lazyload]');
  3044.   return utils.makeArray( imgs );
  3045. }
  3046.  
  3047. // -------------------------- LazyLoader -------------------------- //
  3048.  
  3049. /**
  3050.  * class to handle loading images
  3051.  */
  3052. function LazyLoader( img, flickity ) {
  3053.   this.img = img;
  3054.   this.flickity = flickity;
  3055.   this.load();
  3056. }
  3057.  
  3058. LazyLoader.prototype.handleEvent = utils.handleEvent;
  3059.  
  3060. LazyLoader.prototype.load = function() {
  3061.   eventie.bind( this.img, 'load', this );
  3062.   eventie.bind( this.img, 'error', this );
  3063.   // load image
  3064.   this.img.src = this.img.getAttribute('data-flickity-lazyload');
  3065.   // remove attr
  3066.   this.img.removeAttribute('data-flickity-lazyload');
  3067. };
  3068.  
  3069. LazyLoader.prototype.onload = function( event ) {
  3070.   this.complete( event, 'flickity-lazyloaded' );
  3071. };
  3072.  
  3073. LazyLoader.prototype.onerror = function( event ) {
  3074.   this.complete( event, 'flickity-lazyerror' );
  3075. };
  3076.  
  3077. LazyLoader.prototype.complete = function( event, className ) {
  3078.   // unbind events
  3079.   eventie.unbind( this.img, 'load', this );
  3080.   eventie.unbind( this.img, 'error', this );
  3081.  
  3082.   var cell = this.flickity.getParentCell( this.img );
  3083.   var cellElem = cell && cell.element;
  3084.   this.flickity.cellSizeChange( cellElem );
  3085.  
  3086.   classie.add( this.img, className );
  3087.   this.flickity.dispatchEvent( 'lazyLoad', event, cellElem );
  3088. };
  3089.  
  3090. // -----  ----- //
  3091.  
  3092. Flickity.LazyLoader = LazyLoader;
  3093.  
  3094. return Flickity;
  3095.  
  3096. }));
  3097.  
  3098. },{"./flickity":13,"desandro-classie":3,"eventie":7,"fizzy-ui-utils":8}],16:[function(require,module,exports){
  3099. ( function( window, factory ) {
  3100.   'use strict';
  3101.   // universal module definition
  3102.  
  3103.   if ( typeof define == 'function' && define.amd ) {
  3104.     // AMD
  3105.     define( [
  3106.       'eventie/eventie',
  3107.       './flickity',
  3108.       'tap-listener/tap-listener',
  3109.       'fizzy-ui-utils/utils'
  3110.     ], function( eventie, Flickity, TapListener, utils ) {
  3111.       return factory( window, eventie, Flickity, TapListener, utils );
  3112.     });
  3113.   } else if ( typeof exports == 'object' ) {
  3114.     // CommonJS
  3115.     module.exports = factory(
  3116.       window,
  3117.       require('eventie'),
  3118.       require('./flickity'),
  3119.       require('tap-listener'),
  3120.       require('fizzy-ui-utils')
  3121.     );
  3122.   } else {
  3123.     // browser global
  3124.     factory(
  3125.       window,
  3126.       window.eventie,
  3127.       window.Flickity,
  3128.       window.TapListener,
  3129.       window.fizzyUIUtils
  3130.     );
  3131.   }
  3132.  
  3133. }( window, function factory( window, eventie, Flickity, TapListener, utils ) {
  3134.  
  3135. // -------------------------- PageDots -------------------------- //
  3136.  
  3137. 'use strict';
  3138.  
  3139. function PageDots( parent ) {
  3140.   this.parent = parent;
  3141.   this._create();
  3142. }
  3143.  
  3144. PageDots.prototype = new TapListener();
  3145.  
  3146. PageDots.prototype._create = function() {
  3147.   // create holder element
  3148.   this.holder = document.createElement('ol');
  3149.   this.holder.className = 'flickity-page-dots';
  3150.   Flickity.setUnselectable( this.holder );
  3151.   // create dots, array of elements
  3152.   this.dots = [];
  3153.   // update on select
  3154.   var _this = this;
  3155.   this.onCellSelect = function() {
  3156.     _this.updateSelected();
  3157.   };
  3158.   this.parent.on( 'cellSelect', this.onCellSelect );
  3159.   // tap
  3160.   this.on( 'tap', this.onTap );
  3161.   // pointerDown
  3162.   this.on( 'pointerDown', function onPointerDown( button, event ) {
  3163.     _this.parent.childUIPointerDown( event );
  3164.   });
  3165. };
  3166.  
  3167. PageDots.prototype.activate = function() {
  3168.   this.setDots();
  3169.   this.bindTap( this.holder );
  3170.   // add to DOM
  3171.   this.parent.element.appendChild( this.holder );
  3172. };
  3173.  
  3174. PageDots.prototype.deactivate = function() {
  3175.   // remove from DOM
  3176.   this.parent.element.removeChild( this.holder );
  3177.   TapListener.prototype.destroy.call( this );
  3178. };
  3179.  
  3180. PageDots.prototype.setDots = function() {
  3181.   // get difference between number of cells and number of dots
  3182.   var delta = this.parent.cells.length - this.dots.length;
  3183.   if ( delta > 0 ) {
  3184.     this.addDots( delta );
  3185.   } else if ( delta < 0 ) {
  3186.     this.removeDots( -delta );
  3187.   }
  3188. };
  3189.  
  3190. PageDots.prototype.addDots = function( count ) {
  3191.   var fragment = document.createDocumentFragment();
  3192.   var newDots = [];
  3193.   while ( count ) {
  3194.     var dot = document.createElement('li');
  3195.     dot.className = 'dot';
  3196.     fragment.appendChild( dot );
  3197.     newDots.push( dot );
  3198.     count--;
  3199.   }
  3200.   this.holder.appendChild( fragment );
  3201.   this.dots = this.dots.concat( newDots );
  3202. };
  3203.  
  3204. PageDots.prototype.removeDots = function( count ) {
  3205.   // remove from this.dots collection
  3206.   var removeDots = this.dots.splice( this.dots.length - count, count );
  3207.   // remove from DOM
  3208.   for ( var i=0, len = removeDots.length; i < len; i++ ) {
  3209.     var dot = removeDots[i];
  3210.     this.holder.removeChild( dot );
  3211.   }
  3212. };
  3213.  
  3214. PageDots.prototype.updateSelected = function() {
  3215.   // remove selected class on previous
  3216.   if ( this.selectedDot ) {
  3217.     this.selectedDot.className = 'dot';
  3218.   }
  3219.   // don't proceed if no dots
  3220.   if ( !this.dots.length ) {
  3221.     return;
  3222.   }
  3223.   this.selectedDot = this.dots[ this.parent.selectedIndex ];
  3224.   this.selectedDot.className = 'dot is-selected';
  3225. };
  3226.  
  3227. PageDots.prototype.onTap = function( event ) {
  3228.   var target = event.target;
  3229.   // only care about dot clicks
  3230.   if ( target.nodeName != 'LI' ) {
  3231.     return;
  3232.   }
  3233.  
  3234.   this.parent.uiChange();
  3235.   var index = utils.indexOf( this.dots, target );
  3236.   this.parent.select( index );
  3237. };
  3238.  
  3239. PageDots.prototype.destroy = function() {
  3240.   this.deactivate();
  3241. };
  3242.  
  3243. Flickity.PageDots = PageDots;
  3244.  
  3245. // -------------------------- Flickity -------------------------- //
  3246.  
  3247. utils.extend( Flickity.defaults, {
  3248.   pageDots: true
  3249. });
  3250.  
  3251. Flickity.createMethods.push('_createPageDots');
  3252.  
  3253. Flickity.prototype._createPageDots = function() {
  3254.   if ( !this.options.pageDots ) {
  3255.     return;
  3256.   }
  3257.   this.pageDots = new PageDots( this );
  3258.   this.on( 'activate', this.activatePageDots );
  3259.   this.on( 'cellAddedRemoved', this.onCellAddedRemovedPageDots );
  3260.   this.on( 'deactivate', this.deactivatePageDots );
  3261. };
  3262.  
  3263. Flickity.prototype.activatePageDots = function() {
  3264.   this.pageDots.activate();
  3265. };
  3266.  
  3267. Flickity.prototype.onCellAddedRemovedPageDots = function() {
  3268.   this.pageDots.setDots();
  3269. };
  3270.  
  3271. Flickity.prototype.deactivatePageDots = function() {
  3272.   this.pageDots.deactivate();
  3273. };
  3274.  
  3275. // -----  ----- //
  3276.  
  3277. Flickity.PageDots = PageDots;
  3278.  
  3279. return Flickity;
  3280.  
  3281. }));
  3282.  
  3283. },{"./flickity":13,"eventie":7,"fizzy-ui-utils":8,"tap-listener":21}],17:[function(require,module,exports){
  3284. ( function( window, factory ) {
  3285.   'use strict';
  3286.   // universal module definition
  3287.  
  3288.   if ( typeof define == 'function' && define.amd ) {
  3289.     // AMD
  3290.     define( [
  3291.       'eventEmitter/EventEmitter',
  3292.       'eventie/eventie',
  3293.       'fizzy-ui-utils/utils',
  3294.       './flickity'
  3295.     ], function( EventEmitter, eventie, utils, Flickity ) {
  3296.       return factory( EventEmitter, eventie, utils, Flickity );
  3297.     });
  3298.   } else if ( typeof exports == 'object' ) {
  3299.     // CommonJS
  3300.     module.exports = factory(
  3301.       require('wolfy87-eventemitter'),
  3302.       require('eventie'),
  3303.       require('fizzy-ui-utils'),
  3304.       require('./flickity')
  3305.     );
  3306.   } else {
  3307.     // browser global
  3308.     factory(
  3309.       window.EventEmitter,
  3310.       window.eventie,
  3311.       window.fizzyUIUtils,
  3312.       window.Flickity
  3313.     );
  3314.   }
  3315.  
  3316. }( window, function factory( EventEmitter, eventie, utils, Flickity ) {
  3317.  
  3318. 'use strict';
  3319.  
  3320. // -------------------------- Page Visibility -------------------------- //
  3321. // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API
  3322.  
  3323. var hiddenProperty, visibilityEvent;
  3324. if ( 'hidden' in document ) {
  3325.   hiddenProperty = 'hidden';
  3326.   visibilityEvent = 'visibilitychange';
  3327. } else if ( 'webkitHidden' in document ) {
  3328.   hiddenProperty = 'webkitHidden';
  3329.   visibilityEvent = 'webkitvisibilitychange';
  3330. }
  3331.  
  3332. // -------------------------- Player -------------------------- //
  3333.  
  3334. function Player( parent ) {
  3335.   this.parent = parent;
  3336.   this.state = 'stopped';
  3337.   // visibility change event handler
  3338.   if ( visibilityEvent ) {
  3339.     var _this = this;
  3340.     this.onVisibilityChange = function() {
  3341.       _this.visibilityChange();
  3342.     };
  3343.   }
  3344. }
  3345.  
  3346. Player.prototype = new EventEmitter();
  3347.  
  3348. // start play
  3349. Player.prototype.play = function() {
  3350.   if ( this.state == 'playing' ) {
  3351.     return;
  3352.   }
  3353.   this.state = 'playing';
  3354.   // listen to visibility change
  3355.   if ( visibilityEvent ) {
  3356.     document.addEventListener( visibilityEvent, this.onVisibilityChange, false );
  3357.   }
  3358.   // start ticking
  3359.   this.tick();
  3360. };
  3361.  
  3362. Player.prototype.tick = function() {
  3363.   // do not tick if not playing
  3364.   if ( this.state != 'playing' ) {
  3365.     return;
  3366.   }
  3367.  
  3368.   var time = this.parent.options.autoPlay;
  3369.   // default to 3 seconds
  3370.   time = typeof time == 'number' ? time : 3000;
  3371.   var _this = this;
  3372.   // HACK: reset ticks if stopped and started within interval
  3373.   this.clear();
  3374.   this.timeout = setTimeout( function() {
  3375.     _this.parent.next( true );
  3376.     _this.tick();
  3377.   }, time );
  3378. };
  3379.  
  3380. Player.prototype.stop = function() {
  3381.   this.state = 'stopped';
  3382.   this.clear();
  3383.   // remove visibility change event
  3384.   if ( visibilityEvent ) {
  3385.     document.removeEventListener( visibilityEvent, this.onVisibilityChange, false );
  3386.   }
  3387. };
  3388.  
  3389. Player.prototype.clear = function() {
  3390.   clearTimeout( this.timeout );
  3391. };
  3392.  
  3393. Player.prototype.pause = function() {
  3394.   if ( this.state == 'playing' ) {
  3395.     this.state = 'paused';
  3396.     this.clear();
  3397.   }
  3398. };
  3399.  
  3400. Player.prototype.unpause = function() {
  3401.   // re-start play if in unpaused state
  3402.   if ( this.state == 'paused' ) {
  3403.     this.play();
  3404.   }
  3405. };
  3406.  
  3407. // pause if page visibility is hidden, unpause if visible
  3408. Player.prototype.visibilityChange = function() {
  3409.   var isHidden = document[ hiddenProperty ];
  3410.   this[ isHidden ? 'pause' : 'unpause' ]();
  3411. };
  3412.  
  3413. // -------------------------- Flickity -------------------------- //
  3414.  
  3415. utils.extend( Flickity.defaults, {
  3416.   pauseAutoPlayOnHover: true
  3417. });
  3418.  
  3419. Flickity.createMethods.push('_createPlayer');
  3420.  
  3421. Flickity.prototype._createPlayer = function() {
  3422.   this.player = new Player( this );
  3423.  
  3424.   this.on( 'activate', this.activatePlayer );
  3425.   this.on( 'uiChange', this.stopPlayer );
  3426.   this.on( 'pointerDown', this.stopPlayer );
  3427.   this.on( 'deactivate', this.deactivatePlayer );
  3428. };
  3429.  
  3430. Flickity.prototype.activatePlayer = function() {
  3431.   if ( !this.options.autoPlay ) {
  3432.     return;
  3433.   }
  3434.   this.player.play();
  3435.   eventie.bind( this.element, 'mouseenter', this );
  3436.   this.isMouseenterBound = true;
  3437. };
  3438.  
  3439. // Player API, don't hate the ... thanks I know where the door is
  3440.  
  3441. Flickity.prototype.playPlayer = function() {
  3442.   this.player.play();
  3443. };
  3444.  
  3445. Flickity.prototype.stopPlayer = function() {
  3446.   this.player.stop();
  3447. };
  3448.  
  3449. Flickity.prototype.pausePlayer = function() {
  3450.   this.player.pause();
  3451. };
  3452.  
  3453. Flickity.prototype.unpausePlayer = function() {
  3454.   this.player.unpause();
  3455. };
  3456.  
  3457. Flickity.prototype.deactivatePlayer = function() {
  3458.   this.player.stop();
  3459.   if ( this.isMouseenterBound ) {
  3460.     eventie.unbind( this.element, 'mouseenter', this );
  3461.     delete this.isMouseenterBound;
  3462.   }
  3463. };
  3464.  
  3465. // ----- mouseenter/leave ----- //
  3466.  
  3467. // pause auto-play on hover
  3468. Flickity.prototype.onmouseenter = function() {
  3469.   if ( !this.options.pauseAutoPlayOnHover ) {
  3470.     return;
  3471.   }
  3472.   this.player.pause();
  3473.   eventie.bind( this.element, 'mouseleave', this );
  3474. };
  3475.  
  3476. // resume auto-play on hover off
  3477. Flickity.prototype.onmouseleave = function() {
  3478.   this.player.unpause();
  3479.   eventie.unbind( this.element, 'mouseleave', this );
  3480. };
  3481.  
  3482. // -----  ----- //
  3483.  
  3484. Flickity.Player = Player;
  3485.  
  3486. return Flickity;
  3487.  
  3488. }));
  3489.  
  3490. },{"./flickity":13,"eventie":7,"fizzy-ui-utils":8,"wolfy87-eventemitter":24}],18:[function(require,module,exports){
  3491. // -------------------------- prev/next button -------------------------- //
  3492.  
  3493. ( function( window, factory ) {
  3494.   'use strict';
  3495.   // universal module definition
  3496.  
  3497.   if ( typeof define == 'function' && define.amd ) {
  3498.     // AMD
  3499.     define( [
  3500.       'eventie/eventie',
  3501.       './flickity',
  3502.       'tap-listener/tap-listener',
  3503.       'fizzy-ui-utils/utils'
  3504.     ], function( eventie, Flickity, TapListener, utils ) {
  3505.       return factory( window, eventie, Flickity, TapListener, utils );
  3506.     });
  3507.   } else if ( typeof exports == 'object' ) {
  3508.     // CommonJS
  3509.     module.exports = factory(
  3510.       window,
  3511.       require('eventie'),
  3512.       require('./flickity'),
  3513.       require('tap-listener'),
  3514.       require('fizzy-ui-utils')
  3515.     );
  3516.   } else {
  3517.     // browser global
  3518.     factory(
  3519.       window,
  3520.       window.eventie,
  3521.       window.Flickity,
  3522.       window.TapListener,
  3523.       window.fizzyUIUtils
  3524.     );
  3525.   }
  3526.  
  3527. }( window, function factory( window, eventie, Flickity, TapListener, utils ) {
  3528.  
  3529. 'use strict';
  3530.  
  3531. // ----- inline SVG support ----- //
  3532.  
  3533. var svgURI = 'http://www.w3.org/2000/svg';
  3534.  
  3535. // only check on demand, not on script load
  3536. var supportsInlineSVG = ( function() {
  3537.   var supports;
  3538.   function checkSupport() {
  3539.     if ( supports !== undefined ) {
  3540.       return supports;
  3541.     }
  3542.     var div = document.createElement('div');
  3543.     div.innerHTML = '<svg/>';
  3544.     supports = ( div.firstChild && div.firstChild.namespaceURI ) == svgURI;
  3545.     return supports;
  3546.   }
  3547.   return checkSupport;
  3548. })();
  3549.  
  3550. // -------------------------- PrevNextButton -------------------------- //
  3551.  
  3552. function PrevNextButton( direction, parent ) {
  3553.   this.direction = direction;
  3554.   this.parent = parent;
  3555.   this._create();
  3556. }
  3557.  
  3558. PrevNextButton.prototype = new TapListener();
  3559.  
  3560. PrevNextButton.prototype._create = function() {
  3561.   // properties
  3562.   this.isEnabled = true;
  3563.   this.isPrevious = this.direction == -1;
  3564.   var leftDirection = this.parent.options.rightToLeft ? 1 : -1;
  3565.   this.isLeft = this.direction == leftDirection;
  3566.  
  3567.   var element = this.element = document.createElement('button');
  3568.   element.className = 'flickity-prev-next-button';
  3569.   element.className += this.isPrevious ? ' previous' : ' next';
  3570.   // prevent button from submitting form http://stackoverflow.com/a/10836076/182183
  3571.   element.setAttribute( 'type', 'button' );
  3572.   // init as disabled
  3573.   this.disable();
  3574.  
  3575.   element.setAttribute( 'aria-label', this.isPrevious ? 'previous' : 'next' );
  3576.  
  3577.   Flickity.setUnselectable( element );
  3578.   // create arrow
  3579.   if ( supportsInlineSVG() ) {
  3580.     var svg = this.createSVG();
  3581.     element.appendChild( svg );
  3582.   } else {
  3583.     // SVG not supported, set button text
  3584.     this.setArrowText();
  3585.     element.className += ' no-svg';
  3586.   }
  3587.   // update on select
  3588.   var _this = this;
  3589.   this.onCellSelect = function() {
  3590.     _this.update();
  3591.   };
  3592.   this.parent.on( 'cellSelect', this.onCellSelect );
  3593.   // tap
  3594.   this.on( 'tap', this.onTap );
  3595.   // pointerDown
  3596.   this.on( 'pointerDown', function onPointerDown( button, event ) {
  3597.     _this.parent.childUIPointerDown( event );
  3598.   });
  3599. };
  3600.  
  3601. PrevNextButton.prototype.activate = function() {
  3602.   this.bindTap( this.element );
  3603.   // click events from keyboard
  3604.   eventie.bind( this.element, 'click', this );
  3605.   // add to DOM
  3606.   this.parent.element.appendChild( this.element );
  3607. };
  3608.  
  3609. PrevNextButton.prototype.deactivate = function() {
  3610.   // remove from DOM
  3611.   this.parent.element.removeChild( this.element );
  3612.   // do regular TapListener destroy
  3613.   TapListener.prototype.destroy.call( this );
  3614.   // click events from keyboard
  3615.   eventie.unbind( this.element, 'click', this );
  3616. };
  3617.  
  3618. PrevNextButton.prototype.createSVG = function() {
  3619.   var svg = document.createElementNS( svgURI, 'svg');
  3620.   svg.setAttribute( 'viewBox', '0 0 100 100' );
  3621.   var path = document.createElementNS( svgURI, 'path');
  3622.   var pathMovements = getArrowMovements( this.parent.options.arrowShape );
  3623.   path.setAttribute( 'd', pathMovements );
  3624.   path.setAttribute( 'class', 'arrow' );
  3625.   // rotate arrow
  3626.   if ( !this.isLeft ) {
  3627.     path.setAttribute( 'transform', 'translate(100, 100) rotate(180) ' );
  3628.   }
  3629.   svg.appendChild( path );
  3630.   return svg;
  3631. };
  3632.  
  3633. // get SVG path movmement
  3634. function getArrowMovements( shape ) {
  3635.   // use shape as movement if string
  3636.   if ( typeof shape == 'string' ) {
  3637.     return shape;
  3638.   }
  3639.   // create movement string
  3640.   return 'M ' + shape.x0 + ',50' +
  3641.     ' L ' + shape.x1 + ',' + ( shape.y1 + 50 ) +
  3642.     ' L ' + shape.x2 + ',' + ( shape.y2 + 50 ) +
  3643.     ' L ' + shape.x3 + ',50 ' +
  3644.     ' L ' + shape.x2 + ',' + ( 50 - shape.y2 ) +
  3645.     ' L ' + shape.x1 + ',' + ( 50 - shape.y1 ) +
  3646.     ' Z';
  3647. }
  3648.  
  3649. PrevNextButton.prototype.setArrowText = function() {
  3650.   var parentOptions = this.parent.options;
  3651.   var arrowText = this.isLeft ? parentOptions.leftArrowText : parentOptions.rightArrowText;
  3652.   utils.setText( this.element, arrowText );
  3653. };
  3654.  
  3655. PrevNextButton.prototype.onTap = function() {
  3656.   if ( !this.isEnabled ) {
  3657.     return;
  3658.   }
  3659.   this.parent.uiChange();
  3660.   var method = this.isPrevious ? 'previous' : 'next';
  3661.   this.parent[ method ]();
  3662. };
  3663.  
  3664. PrevNextButton.prototype.handleEvent = utils.handleEvent;
  3665.  
  3666. PrevNextButton.prototype.onclick = function() {
  3667.   // only allow clicks from keyboard
  3668.   var focused = document.activeElement;
  3669.   if ( focused && focused == this.element ) {
  3670.     this.onTap();
  3671.   }
  3672. };
  3673.  
  3674. // -----  ----- //
  3675.  
  3676. PrevNextButton.prototype.enable = function() {
  3677.   if ( this.isEnabled ) {
  3678.     return;
  3679.   }
  3680.   this.element.disabled = false;
  3681.   this.isEnabled = true;
  3682. };
  3683.  
  3684. PrevNextButton.prototype.disable = function() {
  3685.   if ( !this.isEnabled ) {
  3686.     return;
  3687.   }
  3688.   this.element.disabled = true;
  3689.   this.isEnabled = false;
  3690. };
  3691.  
  3692. PrevNextButton.prototype.update = function() {
  3693.   // index of first or last cell, if previous or next
  3694.   var cells = this.parent.cells;
  3695.   // enable is wrapAround and at least 2 cells
  3696.   if ( this.parent.options.wrapAround && cells.length > 1 ) {
  3697.     this.enable();
  3698.     return;
  3699.   }
  3700.   var lastIndex = cells.length ? cells.length - 1 : 0;
  3701.   var boundIndex = this.isPrevious ? 0 : lastIndex;
  3702.   var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable';
  3703.   this[ method ]();
  3704. };
  3705.  
  3706. PrevNextButton.prototype.destroy = function() {
  3707.   this.deactivate();
  3708. };
  3709.  
  3710. // -------------------------- Flickity prototype -------------------------- //
  3711.  
  3712. utils.extend( Flickity.defaults, {
  3713.   prevNextButtons: true,
  3714.   leftArrowText: '‹',
  3715.   rightArrowText: '›',
  3716.   arrowShape: {
  3717.     x0: 10,
  3718.     x1: 60, y1: 50,
  3719.     x2: 70, y2: 40,
  3720.     x3: 30
  3721.   }
  3722. });
  3723.  
  3724. Flickity.createMethods.push('_createPrevNextButtons');
  3725.  
  3726. Flickity.prototype._createPrevNextButtons = function() {
  3727.   if ( !this.options.prevNextButtons ) {
  3728.     return;
  3729.   }
  3730.  
  3731.   this.prevButton = new PrevNextButton( -1, this );
  3732.   this.nextButton = new PrevNextButton( 1, this );
  3733.  
  3734.   this.on( 'activate', this.activatePrevNextButtons );
  3735. };
  3736.  
  3737. Flickity.prototype.activatePrevNextButtons = function() {
  3738.   this.prevButton.activate();
  3739.   this.nextButton.activate();
  3740.   this.on( 'deactivate', this.deactivatePrevNextButtons );
  3741. };
  3742.  
  3743. Flickity.prototype.deactivatePrevNextButtons = function() {
  3744.   this.prevButton.deactivate();
  3745.   this.nextButton.deactivate();
  3746.   this.off( 'deactivate', this.deactivatePrevNextButtons );
  3747. };
  3748.  
  3749. // --------------------------  -------------------------- //
  3750.  
  3751. Flickity.PrevNextButton = PrevNextButton;
  3752.  
  3753. return Flickity;
  3754.  
  3755. }));
  3756.  
  3757. },{"./flickity":13,"eventie":7,"fizzy-ui-utils":8,"tap-listener":21}],19:[function(require,module,exports){
  3758. /*!
  3759.  * getSize v1.2.2
  3760.  * measure size of elements
  3761.  * MIT license
  3762.  */
  3763.  
  3764. /*jshint browser: true, strict: true, undef: true, unused: true */
  3765. /*global define: false, exports: false, require: false, module: false, console: false */
  3766.  
  3767. ( function( window, undefined ) {
  3768.  
  3769. 'use strict';
  3770.  
  3771. // -------------------------- helpers -------------------------- //
  3772.  
  3773. // get a number from a string, not a percentage
  3774. function getStyleSize( value ) {
  3775.   var num = parseFloat( value );
  3776.   // not a percent like '100%', and a number
  3777.   var isValid = value.indexOf('%') === -1 && !isNaN( num );
  3778.   return isValid && num;
  3779. }
  3780.  
  3781. function noop() {}
  3782.  
  3783. var logError = typeof console === 'undefined' ? noop :
  3784.   function( message ) {
  3785.     console.error( message );
  3786.   };
  3787.  
  3788. // -------------------------- measurements -------------------------- //
  3789.  
  3790. var measurements = [
  3791.   'paddingLeft',
  3792.   'paddingRight',
  3793.   'paddingTop',
  3794.   'paddingBottom',
  3795.   'marginLeft',
  3796.   'marginRight',
  3797.   'marginTop',
  3798.   'marginBottom',
  3799.   'borderLeftWidth',
  3800.   'borderRightWidth',
  3801.   'borderTopWidth',
  3802.   'borderBottomWidth'
  3803. ];
  3804.  
  3805. function getZeroSize() {
  3806.   var size = {
  3807.     width: 0,
  3808.     height: 0,
  3809.     innerWidth: 0,
  3810.     innerHeight: 0,
  3811.     outerWidth: 0,
  3812.     outerHeight: 0
  3813.   };
  3814.   for ( var i=0, len = measurements.length; i < len; i++ ) {
  3815.     var measurement = measurements[i];
  3816.     size[ measurement ] = 0;
  3817.   }
  3818.   return size;
  3819. }
  3820.  
  3821.  
  3822.  
  3823. function defineGetSize( getStyleProperty ) {
  3824.  
  3825. // -------------------------- setup -------------------------- //
  3826.  
  3827. var isSetup = false;
  3828.  
  3829. var getStyle, boxSizingProp, isBoxSizeOuter;
  3830.  
  3831. /**
  3832.  * setup vars and functions
  3833.  * do it on initial getSize(), rather than on script load
  3834.  * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  3835.  */
  3836. function setup() {
  3837.   // setup once
  3838.   if ( isSetup ) {
  3839.     return;
  3840.   }
  3841.   isSetup = true;
  3842.  
  3843.   var getComputedStyle = window.getComputedStyle;
  3844.   getStyle = ( function() {
  3845.     var getStyleFn = getComputedStyle ?
  3846.       function( elem ) {
  3847.         return getComputedStyle( elem, null );
  3848.       } :
  3849.       function( elem ) {
  3850.         return elem.currentStyle;
  3851.       };
  3852.  
  3853.       return function getStyle( elem ) {
  3854.         var style = getStyleFn( elem );
  3855.         if ( !style ) {
  3856.           logError( 'Style returned ' + style +
  3857.             '. Are you running this code in a hidden iframe on Firefox? ' +
  3858.             'See http://bit.ly/getsizebug1' );
  3859.         }
  3860.         return style;
  3861.       };
  3862.   })();
  3863.  
  3864.   // -------------------------- box sizing -------------------------- //
  3865.  
  3866.   boxSizingProp = getStyleProperty('boxSizing');
  3867.  
  3868.   /**
  3869.    * WebKit measures the outer-width on style.width on border-box elems
  3870.    * IE & Firefox measures the inner-width
  3871.    */
  3872.   if ( boxSizingProp ) {
  3873.     var div = document.createElement('div');
  3874.     div.style.width = '200px';
  3875.     div.style.padding = '1px 2px 3px 4px';
  3876.     div.style.borderStyle = 'solid';
  3877.     div.style.borderWidth = '1px 2px 3px 4px';
  3878.     div.style[ boxSizingProp ] = 'border-box';
  3879.  
  3880.     var body = document.body || document.documentElement;
  3881.     body.appendChild( div );
  3882.     var style = getStyle( div );
  3883.  
  3884.     isBoxSizeOuter = getStyleSize( style.width ) === 200;
  3885.     body.removeChild( div );
  3886.   }
  3887.  
  3888. }
  3889.  
  3890. // -------------------------- getSize -------------------------- //
  3891.  
  3892. function getSize( elem ) {
  3893.   setup();
  3894.  
  3895.   // use querySeletor if elem is string
  3896.   if ( typeof elem === 'string' ) {
  3897.     elem = document.querySelector( elem );
  3898.   }
  3899.  
  3900.   // do not proceed on non-objects
  3901.   if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
  3902.     return;
  3903.   }
  3904.  
  3905.   var style = getStyle( elem );
  3906.  
  3907.   // if hidden, everything is 0
  3908.   if ( style.display === 'none' ) {
  3909.     return getZeroSize();
  3910.   }
  3911.  
  3912.   var size = {};
  3913.   size.width = elem.offsetWidth;
  3914.   size.height = elem.offsetHeight;
  3915.  
  3916.   var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
  3917.     style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
  3918.  
  3919.   // get all measurements
  3920.   for ( var i=0, len = measurements.length; i < len; i++ ) {
  3921.     var measurement = measurements[i];
  3922.     var value = style[ measurement ];
  3923.     value = mungeNonPixel( elem, value );
  3924.     var num = parseFloat( value );
  3925.     // any 'auto', 'medium' value will be 0
  3926.     size[ measurement ] = !isNaN( num ) ? num : 0;
  3927.   }
  3928.  
  3929.   var paddingWidth = size.paddingLeft + size.paddingRight;
  3930.   var paddingHeight = size.paddingTop + size.paddingBottom;
  3931.   var marginWidth = size.marginLeft + size.marginRight;
  3932.   var marginHeight = size.marginTop + size.marginBottom;
  3933.   var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  3934.   var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  3935.  
  3936.   var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  3937.  
  3938.   // overwrite width and height if we can get it from style
  3939.   var styleWidth = getStyleSize( style.width );
  3940.   if ( styleWidth !== false ) {
  3941.     size.width = styleWidth +
  3942.       // add padding and border unless it's already including it
  3943.       ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  3944.   }
  3945.  
  3946.   var styleHeight = getStyleSize( style.height );
  3947.   if ( styleHeight !== false ) {
  3948.     size.height = styleHeight +
  3949.       // add padding and border unless it's already including it
  3950.       ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  3951.   }
  3952.  
  3953.   size.innerWidth = size.width - ( paddingWidth + borderWidth );
  3954.   size.innerHeight = size.height - ( paddingHeight + borderHeight );
  3955.  
  3956.   size.outerWidth = size.width + marginWidth;
  3957.   size.outerHeight = size.height + marginHeight;
  3958.  
  3959.   return size;
  3960. }
  3961.  
  3962. // IE8 returns percent values, not pixels
  3963. // taken from jQuery's curCSS
  3964. function mungeNonPixel( elem, value ) {
  3965.   // IE8 and has percent value
  3966.   if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
  3967.     return value;
  3968.   }
  3969.   var style = elem.style;
  3970.   // Remember the original values
  3971.   var left = style.left;
  3972.   var rs = elem.runtimeStyle;
  3973.   var rsLeft = rs && rs.left;
  3974.  
  3975.   // Put in the new values to get a computed value out
  3976.   if ( rsLeft ) {
  3977.     rs.left = elem.currentStyle.left;
  3978.   }
  3979.   style.left = value;
  3980.   value = style.pixelLeft;
  3981.  
  3982.   // Revert the changed values
  3983.   style.left = left;
  3984.   if ( rsLeft ) {
  3985.     rs.left = rsLeft;
  3986.   }
  3987.  
  3988.   return value;
  3989. }
  3990.  
  3991. return getSize;
  3992.  
  3993. }
  3994.  
  3995. // transport
  3996. if ( typeof define === 'function' && define.amd ) {
  3997.   // AMD for RequireJS
  3998.   define( [ 'get-style-property/get-style-property' ], defineGetSize );
  3999. } else if ( typeof exports === 'object' ) {
  4000.   // CommonJS for Component
  4001.   module.exports = defineGetSize( require('desandro-get-style-property') );
  4002. } else {
  4003.   // browser global
  4004.   window.getSize = defineGetSize( window.getStyleProperty );
  4005. }
  4006.  
  4007. })( window );
  4008.  
  4009. },{"desandro-get-style-property":4}],20:[function(require,module,exports){
  4010. /*
  4011.  * Backstretch
  4012.  * http://srobbin.com/jquery-plugins/backstretch/
  4013.  *
  4014.  * Copyright (c) 2013 Scott Robbin
  4015.  * Licensed under the MIT license.
  4016.  */
  4017.  
  4018. ;(function ($, window, undefined) {
  4019.   'use strict';
  4020.  
  4021.   /** @const */
  4022.   var YOUTUBE_REGEXP = /^.*(youtu\.be\/|youtube\.com\/v\/|youtube\.com\/embed\/|youtube\.com\/watch\?v=|youtube\.com\/watch\?.*\&v=)([^#\&\?]*).*/i;
  4023.  
  4024.   /* PLUGIN DEFINITION
  4025.    * ========================= */
  4026.  
  4027.   $.fn.backstretch = function (images, options) {
  4028.     var args = arguments;
  4029.  
  4030.     /*
  4031.      * Scroll the page one pixel to get the right window height on iOS
  4032.      * Pretty harmless for everyone else
  4033.     */
  4034.     if ($(window).scrollTop() === 0 ) {
  4035.       window.scrollTo(0, 0);
  4036.     }
  4037.  
  4038.     var returnValues;
  4039.    
  4040.     this.each(function (eachIndex) {
  4041.       var $this = $(this)
  4042.         , obj = $this.data('backstretch');
  4043.  
  4044.       // Do we already have an instance attached to this element?
  4045.       if (obj) {
  4046.  
  4047.         // Is this a method they're trying to execute?
  4048.         if (typeof args[0] === 'string' &&
  4049.             typeof obj[args[0]] === 'function') {
  4050.              
  4051.           // Call the method
  4052.           var returnValue = obj[args[0]].apply(obj, Array.prototype.slice.call(args, 1));
  4053.           if (returnValue === obj) { // If a method is chaining
  4054.             returnValue = undefined;
  4055.           }
  4056.           if (returnValue !== undefined) {
  4057.             returnValues = returnValues || [];
  4058.             returnValues[eachIndex] = returnValue;
  4059.           }
  4060.          
  4061.           return; // Nothing further to do
  4062.         }
  4063.  
  4064.         // Merge the old options with the new
  4065.         options = $.extend(obj.options, options);
  4066.  
  4067.         // Remove the old instance
  4068.         if ( obj.hasOwnProperty('destroy') ) {
  4069.           obj.destroy(true);
  4070.         }
  4071.       }
  4072.  
  4073.       // We need at least one image
  4074.       if (!images || (images && images.length === 0)) {
  4075.         var cssBackgroundImage = $this.css('background-image');
  4076.         if (cssBackgroundImage && cssBackgroundImage !== 'none') {
  4077.           images = [ { url: $this.css('backgroundImage').replace(/url\(|\)|"|'/g,"") } ];
  4078.         } else {
  4079.           $.error('No images were supplied for Backstretch, or element must have a CSS-defined background image.');
  4080.         }
  4081.       }
  4082.  
  4083.       obj = new Backstretch(this, images, options || {});
  4084.       $this.data('backstretch', obj);
  4085.     });
  4086.    
  4087.     return returnValues ? returnValues.length === 1 ? returnValues[0] : returnValues : this;
  4088.   };
  4089.  
  4090.   // If no element is supplied, we'll attach to body
  4091.   $.backstretch = function (images, options) {
  4092.     // Return the instance
  4093.     return $('body')
  4094.             .backstretch(images, options)
  4095.             .data('backstretch');
  4096.   };
  4097.  
  4098.   // Custom selector
  4099.   $.expr[':'].backstretch = function(elem) {
  4100.     return $(elem).data('backstretch') !== undefined;
  4101.   };
  4102.  
  4103.   /* DEFAULTS
  4104.    * ========================= */
  4105.  
  4106.   $.fn.backstretch.defaults = {
  4107.     duration: 5000                // Amount of time in between slides (if slideshow)
  4108.     , transition: 'fade'          // Type of transition between slides
  4109.     , transitionDuration: 0       // Duration of transition between slides
  4110.     , animateFirst: true          // Animate the transition of first image of slideshow in?
  4111.     , alignX: 0.5                 // The x-alignment for the image, can be 'left'|'center'|'right' or any number between 0.0 and 1.0
  4112.     , alignY: 0.5                 // The y-alignment for the image, can be 'top'|'center'|'bottom' or any number between 0.0 and 1.0
  4113.     , paused: false               // Whether the images should slide after given duration
  4114.     , start: 0                    // Index of the first image to show
  4115.     , preload: 2                  // How many images preload at a time?
  4116.     , preloadSize: 1              // How many images can we preload in parallel?
  4117.     , resolutionRefreshRate: 2500 // How long to wait before switching resolution?
  4118.     , resolutionChangeRatioThreshold: 0.1 // How much a change should it be before switching resolution?
  4119.   };
  4120.  
  4121.   /* STYLES
  4122.    *
  4123.    * Baked-in styles that we'll apply to our elements.
  4124.    * In an effort to keep the plugin simple, these are not exposed as options.
  4125.    * That said, anyone can override these in their own stylesheet.
  4126.    * ========================= */
  4127.   var styles = {
  4128.     wrap: {
  4129.       left: 0
  4130.       , top: 0
  4131.       , overflow: 'hidden'
  4132.       , margin: 0
  4133.       , padding: 0
  4134.       , height: '100%'
  4135.       , width: '100%'
  4136.       , zIndex: -999999
  4137.     }
  4138.     , itemWrapper: {
  4139.       position: 'absolute'
  4140.       , display: 'none'
  4141.       , margin: 0
  4142.       , padding: 0
  4143.       , border: 'none'
  4144.       , width: '100%'
  4145.       , height: '100%'
  4146.       , zIndex: -999999
  4147.     }
  4148.     , item: {
  4149.       position: 'absolute'
  4150.       , margin: 0
  4151.       , padding: 0
  4152.       , border: 'none'
  4153.       , width: '100%'
  4154.       , height: '100%'
  4155.       , maxWidth: 'none'
  4156.     }
  4157.   };
  4158.  
  4159.   /* Given an array of different options for an image,
  4160.    * choose the optimal image for the container size.
  4161.    *
  4162.    * Given an image template (a string with {{ width }} and/or
  4163.    * {{height}} inside) and a container object, returns the
  4164.    * image url with the exact values for the size of that
  4165.    * container.
  4166.    *
  4167.    * Returns an array of urls optimized for the specified resolution.
  4168.    *
  4169.    */
  4170.   var optimalSizeImages = (function () {
  4171.  
  4172.     /* Sorts the array of image sizes based on width */
  4173.     var widthInsertSort = function (arr) {
  4174.       for (var i = 1; i < arr.length; i++) {
  4175.         var tmp = arr[i],
  4176.             j = i;
  4177.         while (arr[j - 1] && parseInt(arr[j - 1].width, 10) > parseInt(tmp.width, 10)) {
  4178.           arr[j] = arr[j - 1];
  4179.           --j;
  4180.         }
  4181.         arr[j] = tmp;
  4182.       }
  4183.  
  4184.       return arr;
  4185.     };
  4186.  
  4187.     /* Given an array of various sizes of the same image and a container width,
  4188.      * return the best image.
  4189.      */
  4190.     var selectBest = function (containerWidth, imageSizes) {
  4191.  
  4192.       var devicePixelRatio = window.devicePixelRatio || 1;
  4193.       var lastAllowedImage = 0;
  4194.       var testWidth;
  4195.  
  4196.       for (var j = 0, image; j < imageSizes.length; j++) {
  4197.  
  4198.           image = imageSizes[j];
  4199.  
  4200.           // In case a new image was pushed in, process it:
  4201.           if (typeof image === 'string') {
  4202.               image = imageSizes[j] = { url: image };
  4203.           }
  4204.  
  4205.           if (image.pixelRatio && image.pixelRatio !== 'auto' && parseFloat(image.pixelRatio) !== devicePixelRatio) {
  4206.               // We disallowed choosing this image for current device pixel ratio,
  4207.               // So skip this one.
  4208.               continue;
  4209.           }
  4210.  
  4211.           // Mark this one as the last one we investigated
  4212.           // which does not violate device pixel ratio rules.
  4213.           // We may choose this one later if there's no match.
  4214.           lastAllowedImage = j;
  4215.  
  4216.           // For most images, we match the specified width against element width,
  4217.           // And enforcing a limit depending on the "pixelRatio" property if specified.
  4218.           // But if a pixelRatio="auto", then we consider the width as the physical width of the image,
  4219.           // And match it while considering the device's pixel ratio.
  4220.           testWidth = containerWidth;
  4221.           if (image.pixelRatio === 'auto') {
  4222.               containerWidth *= devicePixelRatio;
  4223.           }
  4224.  
  4225.           // Stop when the width of the image is larger or equal to the container width
  4226.           if (image.width >= testWidth) {
  4227.               break;
  4228.           }
  4229.       }
  4230.  
  4231.       // Use the image located at where we stopped
  4232.       return imageSizes[Math.min(j, lastAllowedImage)];
  4233.     };
  4234.    
  4235.     var replaceTagsInUrl = function (url, templateReplacer) {
  4236.        
  4237.         if (typeof url === 'string') {
  4238.             url = url.replace(/{{(width|height)}}/g, templateReplacer);
  4239.         } else if (url instanceof Array) {
  4240.             for (var i = 0; i < url.length; i++) {
  4241.                 if (url[i].src) {
  4242.                     url[i].src = replaceTagsInUrl(url[i].src, templateReplacer);
  4243.                 } else {
  4244.                     url[i] = replaceTagsInUrl(url[i], templateReplacer);
  4245.                 }
  4246.             }
  4247.         }
  4248.        
  4249.         return url;
  4250.     };
  4251.  
  4252.     return function ($container, images) {
  4253.       var containerWidth = $container.width(),
  4254.           containerHeight = $container.height();
  4255.  
  4256.       var chosenImages = [];
  4257.  
  4258.       var templateReplacer = function (match, key) {
  4259.         if (key === 'width') {
  4260.           return containerWidth;
  4261.         }
  4262.         if (key === 'height') {
  4263.           return containerHeight;
  4264.         }
  4265.         return match;
  4266.       };
  4267.  
  4268.       for (var i = 0; i < images.length; i++) {
  4269.         if ($.isArray(images[i])) {
  4270.           images[i] = widthInsertSort(images[i]);
  4271.           var chosen = selectBest(containerWidth, images[i]);
  4272.           chosenImages.push(chosen);
  4273.         } else {
  4274.           // In case a new image was pushed in, process it:
  4275.           if (typeof images[i] === 'string') {
  4276.               images[i] = { url: images[i] };
  4277.           }
  4278.  
  4279.           var item = $.extend({}, images[i]);
  4280.           item.url = replaceTagsInUrl(item.url, templateReplacer);
  4281.           chosenImages.push(item);
  4282.         }
  4283.       }
  4284.       return chosenImages;
  4285.     };
  4286.  
  4287.   })();
  4288.  
  4289.   var isVideoSource = function (source) {
  4290.     return YOUTUBE_REGEXP.test(source.url) || source.isVideo;
  4291.   };
  4292.  
  4293.   /* Preload images */
  4294.   var preload = (function (sources, startAt, count, batchSize, callback) {
  4295.     // Plugin cache
  4296.     var cache = [];
  4297.  
  4298.     // Wrapper for cache
  4299.     var caching = function(image){
  4300.       for (var i = 0; i < cache.length; i++) {
  4301.         if (cache[i].src === image.src) {
  4302.           return cache[i];
  4303.         }
  4304.       }
  4305.       cache.push(image);
  4306.       return image;
  4307.     };
  4308.  
  4309.     // Execute callback
  4310.     var exec = function(sources, callback, last){
  4311.       if (typeof callback === 'function') {
  4312.         callback.call(sources, last);
  4313.       }
  4314.     };
  4315.  
  4316.     // Closure to hide cache
  4317.     return function preload (sources, startAt, count, batchSize, callback){
  4318.       // Check input data
  4319.       if (typeof sources === 'undefined') {
  4320.         return;
  4321.       }
  4322.       if (!$.isArray(sources)) {
  4323.         sources = [sources];
  4324.       }
  4325.  
  4326.       if (arguments.length < 5 && typeof arguments[arguments.length - 1] === 'function') {
  4327.         callback = arguments[arguments.length - 1];
  4328.       }
  4329.  
  4330.       startAt = (typeof startAt === 'function' || !startAt) ? 0 : startAt;
  4331.       count = (typeof count === 'function' || !count || count < 0) ? sources.length : Math.min(count, sources.length);
  4332.       batchSize = (typeof batchSize === 'function' || !batchSize) ? 1 : batchSize;
  4333.  
  4334.       if (startAt >= sources.length) {
  4335.           startAt = 0;
  4336.           count = 0;
  4337.       }
  4338.       if (batchSize < 0) {
  4339.           batchSize = count;
  4340.       }
  4341.       batchSize = Math.min(batchSize, count);
  4342.  
  4343.       var next = sources.slice(startAt + batchSize, count - batchSize);
  4344.       sources = sources.slice(startAt, batchSize);
  4345.       count = sources.length;
  4346.  
  4347.       // If sources array is empty
  4348.       if (!count) {
  4349.         exec(sources, callback, true);
  4350.         return;
  4351.       }
  4352.  
  4353.       // Image loading callback
  4354.       var countLoaded = 0;
  4355.  
  4356.       var loaded = function() {
  4357.         countLoaded++;
  4358.         if (countLoaded !== count) {
  4359.           return;
  4360.         }
  4361.  
  4362.         exec(sources, callback, !next);
  4363.         preload(next, 0, 0, batchSize, callback);
  4364.       };
  4365.  
  4366.       // Loop sources to preload
  4367.       var image;
  4368.  
  4369.       for (var i = 0; i < sources.length; i++) {
  4370.        
  4371.         if (isVideoSource(sources[i])) {
  4372.          
  4373.           // Do not preload videos. There are issues with that.
  4374.           // First - we need to keep an instance of the preloaded and use that exactly, not a copy.
  4375.           // Second - there are memory issues.
  4376.           // If there will be a requirement from users - I'll try to implement this.
  4377.  
  4378.           continue;
  4379.            
  4380.         } else {
  4381.      
  4382.           image = new Image();
  4383.           image.src = sources[i].url;
  4384.  
  4385.           image = caching(image);
  4386.  
  4387.           if (image.complete) {
  4388.             loaded();
  4389.           } else {
  4390.             $(image).on('load error', loaded);
  4391.           }
  4392.            
  4393.         }
  4394.        
  4395.       }
  4396.     };
  4397.   })();
  4398.  
  4399.   /* Process images array */
  4400.   var processImagesArray = function (images) {
  4401.     var processed = [];
  4402.     for (var i = 0; i < images.length; i++) {
  4403.       if (typeof images[i] === 'string') {
  4404.         processed.push({ url: images[i] });
  4405.       }
  4406.       else if ($.isArray(images[i])) {
  4407.         processed.push(processImagesArray(images[i]));
  4408.       }
  4409.       else {
  4410.         processed.push(processOptions(images[i]));
  4411.       }
  4412.     }
  4413.     return processed;
  4414.   };
  4415.  
  4416.   /* Process options */
  4417.   var processOptions = function (options, required) {
  4418.  
  4419.     // Convert old options
  4420.  
  4421.     // centeredX/centeredY are deprecated
  4422.     if (options.centeredX || options.centeredY) {
  4423.       if (window.console && window.console.log) {
  4424.         window.console.log('jquery.backstretch: `centeredX`/`centeredY` is deprecated, please use `alignX`/`alignY`');
  4425.       }
  4426.       if (options.centeredX) {
  4427.         options.alignX = 0.5;
  4428.       }
  4429.       if (options.centeredY) {
  4430.         options.alignY = 0.5;
  4431.       }
  4432.     }
  4433.  
  4434.     // Deprecated spec
  4435.     if (options.speed !== undefined) {
  4436.  
  4437.       if (window.console && window.console.log) {
  4438.         window.console.log('jquery.backstretch: `speed` is deprecated, please use `transitionDuration`');
  4439.       }
  4440.  
  4441.       options.transitionDuration = options.speed;
  4442.       options.transition = 'fade';
  4443.     }
  4444.  
  4445.     // Typo
  4446.     if (options.resolutionChangeRatioTreshold !== undefined) {
  4447.       window.console.log('jquery.backstretch: `treshold` is a typo!');
  4448.       options.resolutionChangeRatioThreshold = options.resolutionChangeRatioTreshold;
  4449.     }
  4450.  
  4451.     // Current spec that needs processing
  4452.  
  4453.     if (options.fadeFirst !== undefined) {
  4454.       options.animateFirst = options.fadeFirst;
  4455.     }
  4456.  
  4457.     if (options.fade !== undefined) {
  4458.       options.transitionDuration = options.fade;
  4459.       options.transition = 'fade';
  4460.     }
  4461.  
  4462.     return processAlignOptions(options);
  4463.   };
  4464.  
  4465.   /* Process align options */
  4466.   var processAlignOptions = function (options, required) {
  4467.     if (options.alignX === 'left') {
  4468.       options.alignX = 0.0;
  4469.     }
  4470.     else if (options.alignX === 'center') {
  4471.       options.alignX = 0.5;
  4472.     }
  4473.     else if (options.alignX === 'right') {
  4474.       options.alignX = 1.0;
  4475.     }
  4476.     else {
  4477.       if (options.alignX !== undefined || required) {
  4478.         options.alignX = parseFloat(options.alignX);
  4479.         if (isNaN(options.alignX)) {
  4480.           options.alignX = 0.5;
  4481.         }
  4482.       }
  4483.     }
  4484.  
  4485.     if (options.alignY === 'top') {
  4486.       options.alignY = 0.0;
  4487.     }
  4488.     else if (options.alignY === 'center') {
  4489.       options.alignY = 0.5;
  4490.     }
  4491.     else if (options.alignY === 'bottom') {
  4492.       options.alignY = 1.0;
  4493.     }
  4494.     else {
  4495.       if (options.alignX !== undefined || required) {
  4496.         options.alignY = parseFloat(options.alignY);
  4497.         if (isNaN(options.alignY)) {
  4498.           options.alignY = 0.5;
  4499.         }
  4500.       }
  4501.     }
  4502.  
  4503.     return options;
  4504.   };
  4505.  
  4506.   /* CLASS DEFINITION
  4507.    * ========================= */
  4508.   var Backstretch = function (container, images, options) {
  4509.     this.options = $.extend({}, $.fn.backstretch.defaults, options || {});
  4510.  
  4511.     this.firstShow = true;
  4512.  
  4513.     // Process options
  4514.     processOptions(this.options, true);
  4515.  
  4516.     /* In its simplest form, we allow Backstretch to be called on an image path.
  4517.      * e.g. $.backstretch('/path/to/image.jpg')
  4518.      * So, we need to turn this back into an array.
  4519.      */
  4520.     this.images = processImagesArray($.isArray(images) ? images : [images]);
  4521.  
  4522.     /**
  4523.      * Paused-Option
  4524.      */
  4525.     if (this.options.paused) {
  4526.         this.paused = true;
  4527.     }
  4528.  
  4529.     /**
  4530.      * Start-Option (Index)
  4531.      */
  4532.     if (this.options.start >= this.images.length)
  4533.     {
  4534.         this.options.start = this.images.length - 1;
  4535.     }
  4536.     if (this.options.start < 0)
  4537.     {
  4538.         this.options.start = 0;
  4539.     }
  4540.  
  4541.     // Convenience reference to know if the container is body.
  4542.     this.isBody = container === document.body;
  4543.  
  4544.     /* We're keeping track of a few different elements
  4545.      *
  4546.      * Container: the element that Backstretch was called on.
  4547.      * Wrap: a DIV that we place the image into, so we can hide the overflow.
  4548.      * Root: Convenience reference to help calculate the correct height.
  4549.      */
  4550.     var $window = $(window);
  4551.     this.$container = $(container);
  4552.     this.$root = this.isBody ? supportsFixedPosition ? $window : $(document) : this.$container;
  4553.  
  4554.     this.originalImages = this.images;
  4555.     this.images = optimalSizeImages(
  4556.         this.options.alwaysTestWindowResolution ? $window : this.$root,
  4557.         this.originalImages);
  4558.  
  4559.     /**
  4560.      * Pre-Loading.
  4561.      * This is the first image, so we will preload a minimum of 1 images.
  4562.      */
  4563.     preload(this.images, this.options.start || 0, this.options.preload || 1);
  4564.  
  4565.     // Don't create a new wrap if one already exists (from a previous instance of Backstretch)
  4566.     var $existing = this.$container.children(".backstretch").first();
  4567.     this.$wrap = $existing.length ? $existing :
  4568.         $('<div class="backstretch"></div>')
  4569.         .css(this.options.bypassCss ? {} : styles.wrap)
  4570.         .appendTo(this.$container);
  4571.  
  4572.     if (!this.options.bypassCss) {
  4573.        
  4574.         // Non-body elements need some style adjustments
  4575.         if (!this.isBody) {
  4576.           // If the container is statically positioned, we need to make it relative,
  4577.           // and if no zIndex is defined, we should set it to zero.
  4578.           var position = this.$container.css('position')
  4579.             , zIndex = this.$container.css('zIndex');
  4580.  
  4581.           this.$container.css({
  4582.               position: position === 'static' ? 'relative' : position
  4583.             , zIndex: zIndex === 'auto' ? 0 : zIndex
  4584.           });
  4585.  
  4586.           // Needs a higher z-index
  4587.           this.$wrap.css({zIndex: -999998});
  4588.         }
  4589.  
  4590.         // Fixed or absolute positioning?
  4591.         this.$wrap.css({
  4592.             position: this.isBody && supportsFixedPosition ? 'fixed' : 'absolute'
  4593.         });
  4594.    
  4595.     }
  4596.  
  4597.     // Set the first image
  4598.     this.index = this.options.start;
  4599.     this.show(this.index);
  4600.  
  4601.     // Listen for resize
  4602.     $window.on('resize.backstretch', $.proxy(this.resize, this))
  4603.            .on('orientationchange.backstretch', $.proxy(function () {
  4604.               // Need to do this in order to get the right window height
  4605.               if (this.isBody && window.pageYOffset === 0) {
  4606.                 window.scrollTo(0, 1);
  4607.                 this.resize();
  4608.               }
  4609.            }, this));
  4610.   };
  4611.  
  4612.   var performTransition = function (options) {
  4613.  
  4614.     var transition = options.transition || 'fade';
  4615.  
  4616.     // Look for multiple options
  4617.     if (typeof transition === 'string' && transition.indexOf('|') > -1) {
  4618.       transition = transition.split('|');
  4619.     }
  4620.  
  4621.     if (transition instanceof Array) {
  4622.       transition = transition[Math.round(Math.random() * (transition.length - 1))];
  4623.     }
  4624.    
  4625.     var $new = options['new'];
  4626.     var $old = options['old'] ? options['old'] : $([]);
  4627.  
  4628.     switch (transition.toString().toLowerCase()) {
  4629.  
  4630.       default:
  4631.       case 'fade':
  4632.         $new.fadeIn({
  4633.           duration: options.duration,
  4634.           complete: options.complete,
  4635.           easing: options.easing || undefined
  4636.         });
  4637.         break;
  4638.        
  4639.       case 'fadeinout':
  4640.       case 'fade_in_out':
  4641.            
  4642.         var fadeInNew = function () {
  4643.             $new.fadeIn({
  4644.               duration: options.duration / 2,
  4645.               complete: options.complete,
  4646.               easing: options.easing || undefined
  4647.             });
  4648.         };
  4649.        
  4650.         if ($old.length) {
  4651.             $old.fadeOut({
  4652.               duration: options.duration / 2,
  4653.               complete: fadeInNew,
  4654.               easing: options.easing || undefined
  4655.             });
  4656.         } else {
  4657.             fadeInNew();
  4658.         }
  4659.        
  4660.         break;
  4661.  
  4662.       case 'pushleft':
  4663.       case 'push_left':
  4664.       case 'pushright':
  4665.       case 'push_right':
  4666.       case 'pushup':
  4667.       case 'push_up':
  4668.       case 'pushdown':
  4669.       case 'push_down':
  4670.       case 'coverleft':
  4671.       case 'cover_left':
  4672.       case 'coverright':
  4673.       case 'cover_right':
  4674.       case 'coverup':
  4675.       case 'cover_up':
  4676.       case 'coverdown':
  4677.       case 'cover_down':
  4678.  
  4679.         var transitionParts = transition.match(/^(cover|push)_?(.*)$/);
  4680.  
  4681.         var animProp = transitionParts[2] === 'left' ? 'right' :
  4682.             transitionParts[2] === 'right' ? 'left' :
  4683.                 transitionParts[2] === 'down' ? 'top' :
  4684.                     transitionParts[2] === 'up' ? 'bottom' :
  4685.                         'right';
  4686.  
  4687.         var newCssStart = {
  4688.           'display': ''
  4689.         }, newCssAnim = {};
  4690.         newCssStart[animProp] = '-100%';
  4691.         newCssAnim[animProp] = 0;
  4692.  
  4693.         $new
  4694.             .css(newCssStart)
  4695.             .animate(newCssAnim, {
  4696.               duration: options.duration,
  4697.               complete: function () {
  4698.                 $new.css(animProp, '');
  4699.                 options.complete.apply(this, arguments);
  4700.               },
  4701.               easing: options.easing || undefined
  4702.             });
  4703.  
  4704.         if (transitionParts[1] === 'push' && $old.length) {
  4705.             var oldCssAnim = {};
  4706.             oldCssAnim[animProp] = '100%';
  4707.  
  4708.             $old
  4709.                 .animate(oldCssAnim, {
  4710.                   duration: options.duration,
  4711.                   complete: function () {
  4712.                     $old.css('display', 'none');
  4713.                   },
  4714.                   easing: options.easing || undefined
  4715.                 });
  4716.         }
  4717.  
  4718.         break;
  4719.     }
  4720.  
  4721.   };
  4722.  
  4723.   /* PUBLIC METHODS
  4724.    * ========================= */
  4725.   Backstretch.prototype = {
  4726.  
  4727.       resize: function () {
  4728.         try {
  4729.  
  4730.           // Check for a better suited image after the resize
  4731.           var $resTest = this.options.alwaysTestWindowResolution ? $(window) : this.$root;
  4732.           var newContainerWidth = $resTest.width();
  4733.           var newContainerHeight = $resTest.height();
  4734.           var changeRatioW = newContainerWidth / (this._lastResizeContainerWidth || 0);
  4735.           var changeRatioH = newContainerHeight / (this._lastResizeContainerHeight || 0);
  4736.           var resolutionChangeRatioThreshold = this.options.resolutionChangeRatioThreshold || 0.0;
  4737.  
  4738.           // check for big changes in container size
  4739.           if ((newContainerWidth !== this._lastResizeContainerWidth ||
  4740.                newContainerHeight !== this._lastResizeContainerHeight) &&
  4741.               ((Math.abs(changeRatioW - 1) >= resolutionChangeRatioThreshold || isNaN(changeRatioW)) ||
  4742.               (Math.abs(changeRatioH - 1) >= resolutionChangeRatioThreshold || isNaN(changeRatioH)))) {
  4743.  
  4744.             this._lastResizeContainerWidth = newContainerWidth;
  4745.             this._lastResizeContainerHeight = newContainerHeight;
  4746.  
  4747.             // Big change: rebuild the entire images array
  4748.             this.images = optimalSizeImages($resTest, this.originalImages);
  4749.  
  4750.             // Preload them (they will be automatically inserted on the next cycle)
  4751.             if (this.options.preload) {
  4752.               preload(this.images, (this.index + 1) % this.images.length, this.options.preload);
  4753.             }
  4754.  
  4755.             // In case there is no cycle and the new source is different than the current
  4756.             if (this.images.length === 1 &&
  4757.                 this._currentImage.url !== this.images[0].url) {
  4758.  
  4759.               // Wait a little an update the image being showed
  4760.               var that = this;
  4761.               clearTimeout(that._selectAnotherResolutionTimeout);
  4762.               that._selectAnotherResolutionTimeout = setTimeout(function () {
  4763.                 that.show(0);
  4764.               }, this.options.resolutionRefreshRate);
  4765.             }
  4766.           }
  4767.  
  4768.           var bgCSS = {left: 0, top: 0, right: 'auto', bottom: 'auto'}
  4769.             , rootWidth = this.isBody ? this.$root.width() : this.$root.innerWidth()
  4770.             , rootHeight = this.isBody ? ( window.innerHeight ? window.innerHeight : this.$root.height() ) : this.$root.innerHeight()
  4771.             , bgWidth = rootWidth
  4772.             , bgHeight = bgWidth / this.$itemWrapper.data('ratio')
  4773.             , evt = $.Event('backstretch.resize', {
  4774.               relatedTarget: this.$container[0]
  4775.             })
  4776.             , bgOffset
  4777.             , alignX = this._currentImage.alignX === undefined ? this.options.alignX : this._currentImage.alignX
  4778.             , alignY = this._currentImage.alignY === undefined ? this.options.alignY : this._currentImage.alignY;
  4779.  
  4780.             // Make adjustments based on image ratio
  4781.             if (bgHeight >= rootHeight) {
  4782.                 bgCSS.top = -(bgHeight - rootHeight) * alignY;
  4783.             } else {
  4784.                 bgHeight = rootHeight;
  4785.                 bgWidth = bgHeight * this.$itemWrapper.data('ratio');
  4786.                 bgOffset = (bgWidth - rootWidth) / 2;
  4787.                 bgCSS.left = -(bgWidth - rootWidth) * alignX;
  4788.             }
  4789.  
  4790.             if (!this.options.bypassCss) {
  4791.  
  4792.                 this.$wrap
  4793.                     .css({width: rootWidth, height: rootHeight})
  4794.                     .find('>.backstretch-item').not('.deleteable')
  4795.                     .each(function () {
  4796.                         var $wrapper = $(this);
  4797.                         $wrapper.find('img,video,iframe')
  4798.                                 .css({width: bgWidth, height: bgHeight})
  4799.                                 .css(bgCSS);
  4800.                     });
  4801.             }
  4802.  
  4803.             this.$container.trigger(evt, this);
  4804.         } catch(err) {
  4805.             // IE7 seems to trigger resize before the image is loaded.
  4806.             // This try/catch block is a hack to let it fail gracefully.
  4807.         }
  4808.  
  4809.         return this;
  4810.       }
  4811.  
  4812.       // Show the slide at a certain position
  4813.     , show: function (newIndex, overrideOptions) {
  4814.  
  4815.         // Validate index
  4816.         if (Math.abs(newIndex) > this.images.length - 1) {
  4817.           return;
  4818.         }
  4819.  
  4820.         // Vars
  4821.         var that = this
  4822.           , $oldItemWrapper = that.$wrap.find('>.backstretch-item').addClass('deleteable')
  4823.           , oldVideoWrapper = that.videoWrapper
  4824.           , evtOptions = { relatedTarget: that.$container[0] };
  4825.  
  4826.         // Trigger the "before" event
  4827.         that.$container.trigger($.Event('backstretch.before', evtOptions), [that, newIndex]);
  4828.  
  4829.         // Set the new frame index
  4830.         this.index = newIndex;
  4831.         var selectedImage = that.images[newIndex];
  4832.  
  4833.         // Pause the slideshow
  4834.         clearTimeout(that._cycleTimeout);
  4835.  
  4836.         // New image
  4837.  
  4838.         delete that.videoWrapper; // Current item may not be a video
  4839.  
  4840.         var isVideo = isVideoSource(selectedImage);
  4841.         if (isVideo) {
  4842.           that.videoWrapper = new VideoWrapper(selectedImage);
  4843.           that.$item = that.videoWrapper.$video.css('pointer-events', 'none');
  4844.         } else {
  4845.           that.$item = $('<img />');
  4846.         }
  4847.  
  4848.         that.$itemWrapper = $('<div class="backstretch-item">')
  4849.             .append(that.$item);
  4850.  
  4851.         if (this.options.bypassCss) {
  4852.             that.$itemWrapper.css({
  4853.               'display': 'none'
  4854.             });
  4855.         } else {
  4856.           that.$itemWrapper.css(styles.itemWrapper);
  4857.           that.$item.css(styles.item);
  4858.         }
  4859.  
  4860.         that.$item.bind(isVideo ? 'canplay' : 'load', function (e) {
  4861.             var $this = $(this)
  4862.               , $wrapper = $this.parent()
  4863.               , options = $wrapper.data('options');
  4864.              
  4865.             if (overrideOptions) {
  4866.               options = $.extend({}, options, overrideOptions);
  4867.             }
  4868.  
  4869.             var imgWidth = this.naturalWidth || this.videoWidth || this.width
  4870.               , imgHeight = this.naturalHeight || this.videoHeight || this.height;
  4871.  
  4872.             // Save the ratio
  4873.             $wrapper.data('ratio', imgWidth / imgHeight);
  4874.  
  4875.             var getOption = function (opt) {
  4876.               return options[opt] !== undefined ?
  4877.                 options[opt] :
  4878.                 that.options[opt];
  4879.             };
  4880.  
  4881.             var transition = getOption('transition');
  4882.             var transitionEasing = getOption('transitionEasing');
  4883.             var transitionDuration = getOption('transitionDuration');
  4884.  
  4885.             // Show the image, then delete the old one
  4886.             var bringInNextImage = function () {
  4887.              
  4888.               if (oldVideoWrapper) {
  4889.                 oldVideoWrapper.stop();
  4890.                 oldVideoWrapper.destroy();
  4891.               }
  4892.              
  4893.               $oldItemWrapper.remove();
  4894.  
  4895.               // Resume the slideshow
  4896.               if (!that.paused && that.images.length > 1) {
  4897.                 that.cycle();
  4898.               }
  4899.  
  4900.               // Now we can clear the background on the element, to spare memory
  4901.               if (!that.options.bypassCss && !that.isBody) {
  4902.                 that.$container.css('background', 'none');
  4903.               }
  4904.  
  4905.               // Trigger the "after" and "show" events
  4906.               // "show" is being deprecated
  4907.               $(['after', 'show']).each(function () {
  4908.                 that.$container.trigger($.Event('backstretch.' + this, evtOptions), [that, newIndex]);
  4909.               });
  4910.              
  4911.               if (isVideo) {
  4912.                 that.videoWrapper.play();
  4913.               }
  4914.             };
  4915.  
  4916.             if ((that.firstShow && !that.options.animateFirst) || !transitionDuration || !transition) {
  4917.                 // Avoid transition on first show or if there's no transitionDuration value
  4918.                 $wrapper.show();
  4919.                 bringInNextImage();
  4920.             } else {
  4921.  
  4922.                 performTransition({
  4923.                     'new': $wrapper,
  4924.                     old: $oldItemWrapper,
  4925.                     transition: transition,
  4926.                     duration: transitionDuration,
  4927.                     easing: transitionEasing,
  4928.                     complete: bringInNextImage
  4929.                 });
  4930.  
  4931.             }
  4932.  
  4933.             that.firstShow = false;
  4934.  
  4935.             // Resize
  4936.             that.resize();
  4937.         });
  4938.  
  4939.         that.$itemWrapper.appendTo(that.$wrap);
  4940.  
  4941.         that.$item.attr('alt', selectedImage.alt || '');
  4942.         that.$itemWrapper.data('options', selectedImage);
  4943.  
  4944.         if (!isVideo) {
  4945.           that.$item.attr('src', selectedImage.url);
  4946.         }
  4947.        
  4948.         that._currentImage = selectedImage;
  4949.  
  4950.         return that;
  4951.       }
  4952.  
  4953.     , current: function () {
  4954.         return this.index;
  4955.       }
  4956.  
  4957.     , next: function () {
  4958.         var args = Array.prototype.slice.call(arguments, 0);
  4959.         args.unshift(this.index < this.images.length - 1 ? this.index + 1 : 0);
  4960.         return this.show.apply(this, args);
  4961.       }
  4962.  
  4963.     , prev: function () {
  4964.         var args = Array.prototype.slice.call(arguments, 0);
  4965.         args.unshift(this.index === 0 ? this.images.length - 1 : this.index - 1);
  4966.         return this.show.apply(this, args);
  4967.       }
  4968.  
  4969.     , pause: function () {
  4970.         // Pause the slideshow
  4971.         this.paused = true;
  4972.        
  4973.         if (this.videoWrapper) {
  4974.           this.videoWrapper.pause();
  4975.         }
  4976.        
  4977.         return this;
  4978.       }
  4979.  
  4980.     , resume: function () {
  4981.         // Resume the slideshow
  4982.         this.paused = false;
  4983.        
  4984.         if (this.videoWrapper) {
  4985.           this.videoWrapper.play();
  4986.         }
  4987.        
  4988.         this.cycle();
  4989.         return this;
  4990.       }
  4991.  
  4992.     , cycle: function () {
  4993.         // Start/resume the slideshow
  4994.         if(this.images.length > 1) {
  4995.           // Clear the timeout, just in case
  4996.           clearTimeout(this._cycleTimeout);
  4997.  
  4998.           var duration = (this._currentImage && this._currentImage.duration) || this.options.duration;
  4999.           var isVideo = isVideoSource(this._currentImage);
  5000.          
  5001.           var callNext = function () {
  5002.             this.$item.off('.cycle');
  5003.            
  5004.             // Check for paused slideshow
  5005.             if (!this.paused) {
  5006.               this.next();
  5007.             }
  5008.           };
  5009.  
  5010.           // Special video handling
  5011.           if (isVideo) {
  5012.  
  5013.             // Leave video at last frame
  5014.             if (!this._currentImage.loop) {
  5015.               var lastFrameTimeout = 0;
  5016.  
  5017.               this.$item
  5018.                 .on('playing.cycle', function () {
  5019.                   var player = $(this).data('player');
  5020.  
  5021.                   clearTimeout(lastFrameTimeout);
  5022.                   lastFrameTimeout = setTimeout(function () {
  5023.                     player.pause();
  5024.                     player.$video.trigger('ended');
  5025.                   }, (player.getDuration() - player.getCurrentTime()) * 1000);
  5026.                 })
  5027.                 .on('ended.cycle', function () {
  5028.                   clearTimeout(lastFrameTimeout);
  5029.                 });
  5030.             }
  5031.  
  5032.             // On error go to next
  5033.             this.$item.on('error.cycle initerror.cycle', $.proxy(callNext, this));
  5034.           }
  5035.  
  5036.           if (isVideo && !this._currentImage.duration) {
  5037.             // It's a video - playing until end
  5038.             this.$item.on('ended.cycle', $.proxy(callNext, this));
  5039.            
  5040.           } else {
  5041.             // Cycling according to specified duration
  5042.             this._cycleTimeout = setTimeout($.proxy(callNext, this), duration);
  5043.           }
  5044.          
  5045.         }
  5046.         return this;
  5047.       }
  5048.  
  5049.     , destroy: function (preserveBackground) {
  5050.         // Stop the resize events
  5051.         $(window).off('resize.backstretch orientationchange.backstretch');
  5052.  
  5053.         // Stop any videos
  5054.         if (this.videoWrapper) {
  5055.           this.videoWrapper.destroy();
  5056.         }
  5057.        
  5058.         // Clear the timeout
  5059.         clearTimeout(this._cycleTimeout);
  5060.  
  5061.         // Remove Backstretch
  5062.         if(!preserveBackground) {
  5063.           this.$wrap.remove();
  5064.         }
  5065.         this.$container.removeData('backstretch');
  5066.       }
  5067.   };
  5068.    
  5069.  /**
  5070.   * Video Abstraction Layer
  5071.   *
  5072.   * Static methods:
  5073.   * > VideoWrapper.loadYoutubeAPI() -> Call in order to load the Youtube API.
  5074.   *                                   An 'youtube_api_load' event will be triggered on $(window) when the API is loaded.
  5075.   *
  5076.   * Generic:
  5077.   * > player.type -> type of the video
  5078.   * > player.video / player.$video -> contains the element holding the video
  5079.   * > player.play() -> plays the video
  5080.   * > player.pause() -> pauses the video
  5081.   * > player.setCurrentTime(position) -> seeks to a position by seconds
  5082.   *
  5083.   * Youtube:
  5084.   * > player.ytId will contain the youtube ID if the source is a youtube url
  5085.   * > player.ytReady is a flag telling whether the youtube source is ready for playback
  5086.   * */
  5087.  
  5088.   var VideoWrapper = function () { this.init.apply(this, arguments); };
  5089.  
  5090.   /**
  5091.    * @param {Object} options
  5092.    * @param {String|Array<String>|Array<{{src: String, type: String?}}>} options.url
  5093.    * @param {Boolean} options.loop=false
  5094.    * @param {Boolean?} options.mute=true
  5095.    * @param {String?} options.poster
  5096.    * loop, mute, poster
  5097.    */
  5098.   VideoWrapper.prototype.init = function (options) {
  5099.  
  5100.     var that = this;
  5101.    
  5102.     var $video;
  5103.  
  5104.     var setVideoElement = function () {
  5105.       that.$video = $video;
  5106.       that.video = $video[0];
  5107.     };
  5108.    
  5109.     // Determine video type
  5110.    
  5111.     var videoType = 'video';
  5112.    
  5113.     if (!(options.url instanceof Array) &&
  5114.       YOUTUBE_REGEXP.test(options.url)) {
  5115.       videoType = 'youtube';
  5116.     }
  5117.    
  5118.     that.type = videoType;
  5119.  
  5120.     if (videoType === 'youtube') {
  5121.  
  5122.       // Try to load the API in the meantime
  5123.       VideoWrapper.loadYoutubeAPI();
  5124.  
  5125.       that.ytId = options.url.match(YOUTUBE_REGEXP)[2];
  5126.       var src = 'https://www.youtube.com/embed/' + that.ytId +
  5127.         '?rel=0&autoplay=0&showinfo=0&controls=0&modestbranding=1' +
  5128.         '&cc_load_policy=0&disablekb=1&iv_load_policy=3&loop=0' +
  5129.         '&enablejsapi=1&origin=' + encodeURIComponent(window.location.origin);
  5130.  
  5131.       that.__ytStartMuted = !!options.mute || options.mute === undefined;
  5132.  
  5133.       $video = $('<iframe />')
  5134.         .attr({ 'src_to_load': src })
  5135.         .css({ 'border': 0, 'margin': 0, 'padding': 0 })
  5136.         .data('player', that);
  5137.        
  5138.       if (options.loop) {
  5139.         $video.on('ended.loop', function () {
  5140.           if (!that.__manuallyStopped) {
  5141.            that.play();
  5142.           }
  5143.         });
  5144.       }
  5145.  
  5146.       that.ytReady = false;
  5147.  
  5148.       setVideoElement();
  5149.  
  5150.       if (window['YT']) {
  5151.         that._initYoutube();
  5152.         $video.trigger('initsuccess');
  5153.       } else {
  5154.         $(window).one('youtube_api_load', function () {
  5155.           that._initYoutube();
  5156.           $video.trigger('initsuccess');
  5157.         });
  5158.       }
  5159.      
  5160.     }
  5161.     else {
  5162.       // Traditional <video> tag with multiple sources
  5163.      
  5164.       $video = $('<video>')
  5165.         .prop('autoplay', false)
  5166.         .prop('controls', false)
  5167.         .prop('loop', !!options.loop)
  5168.         .prop('muted', !!options.mute || options.mute === undefined)
  5169.        
  5170.         // Let the first frames be available before playback, as we do transitions
  5171.         .prop('preload', 'auto')
  5172.         .prop('poster', options.poster || '');
  5173.        
  5174.       var sources = (options.url instanceof Array) ? options.url : [options.url];
  5175.  
  5176.       for (var i = 0; i < sources.length; i++) {
  5177.         var sourceItem = sources[i];
  5178.         if (typeof(sourceItem) === 'string') {
  5179.           sourceItem = { src: sourceItem };
  5180.         }
  5181.         $('<source>')
  5182.           .attr('src', sourceItem.src)
  5183.           // Make sure to not specify type if unknown -
  5184.           //   so the browser will try to autodetect.
  5185.           .attr('type', sourceItem.type || null)
  5186.           .appendTo($video);
  5187.       }
  5188.      
  5189.       if (!$video[0].canPlayType || !sources.length) {
  5190.         $video.trigger('initerror');
  5191.       } else {
  5192.         $video.trigger('initsuccess');
  5193.       }
  5194.  
  5195.       setVideoElement();
  5196.     }
  5197.  
  5198.   };
  5199.  
  5200.   VideoWrapper.prototype._initYoutube = function () {
  5201.     var that = this;
  5202.    
  5203.     var YT = window['YT'];
  5204.  
  5205.     that.$video
  5206.       .attr('src', that.$video.attr('src_to_load'))
  5207.       .removeAttr('src_to_load');
  5208.  
  5209.     // It won't init if it's not in the DOM, so we emulate that
  5210.     var hasParent = !!that.$video[0].parentNode;
  5211.     if (!hasParent) {
  5212.       var $tmpParent = $('<div>').css('display', 'none !important').appendTo(document.body);
  5213.       that.$video.appendTo($tmpParent);
  5214.     }
  5215.  
  5216.     var player = new YT.Player(that.video, {
  5217.       events: {
  5218.         'onReady': function () {
  5219.  
  5220.           if (that.__ytStartMuted) {
  5221.             player.mute();
  5222.           }
  5223.  
  5224.           if (!hasParent) {
  5225.             // Restore parent to old state - without interrupting any changes
  5226.             if (that.$video[0].parentNode === $tmpParent[0]) {
  5227.               that.$video.detach();
  5228.             }
  5229.             $tmpParent.remove();
  5230.           }
  5231.  
  5232.           that.ytReady = true;
  5233.           that._updateYoutubeSize();
  5234.           that.$video.trigger('canplay');
  5235.         },
  5236.         'onStateChange': function (event) {
  5237.           switch (event.data) {
  5238.             case YT.PlayerState.PLAYING:
  5239.               that.$video.trigger('playing');
  5240.               break;
  5241.             case YT.PlayerState.ENDED:
  5242.               that.$video.trigger('ended');
  5243.               break;
  5244.             case YT.PlayerState.PAUSED:
  5245.               that.$video.trigger('pause');
  5246.               break;
  5247.             case YT.PlayerState.BUFFERING:
  5248.               that.$video.trigger('waiting');
  5249.               break;
  5250.             case YT.PlayerState.CUED:
  5251.               that.$video.trigger('canplay');
  5252.               break;
  5253.           }
  5254.         },
  5255.         'onPlaybackQualityChange': function () {
  5256.           that._updateYoutubeSize();
  5257.           that.$video.trigger('resize');
  5258.         },
  5259.         'onError': function (err) {
  5260.           that.hasError = true;
  5261.           that.$video.trigger({ 'type': 'error', 'error': err });
  5262.         }
  5263.       }
  5264.     });
  5265.  
  5266.     that.ytPlayer = player;
  5267.  
  5268.     return that;
  5269.   };    
  5270.    
  5271.   VideoWrapper.prototype._updateYoutubeSize = function () {
  5272.     var that = this;
  5273.  
  5274.     switch (that.ytPlayer.getPlaybackQuality() || 'medium') {
  5275.       case 'small':
  5276.         that.video.videoWidth = 426;
  5277.         that.video.videoHeight = 240;
  5278.         break;
  5279.       case 'medium':
  5280.         that.video.videoWidth = 640;
  5281.         that.video.videoHeight = 360;
  5282.         break;
  5283.       default:
  5284.       case 'large':
  5285.         that.video.videoWidth = 854;
  5286.         that.video.videoHeight = 480;
  5287.         break;
  5288.       case 'hd720':
  5289.         that.video.videoWidth = 1280;
  5290.         that.video.videoHeight = 720;
  5291.         break;
  5292.       case 'hd1080':
  5293.         that.video.videoWidth = 1920;
  5294.         that.video.videoHeight = 1080;
  5295.         break;
  5296.       case 'highres':
  5297.         that.video.videoWidth = 2560;
  5298.         that.video.videoHeight = 1440;
  5299.         break;
  5300.     }
  5301.  
  5302.     return that;
  5303.   };
  5304.  
  5305.   VideoWrapper.prototype.play = function () {
  5306.     var that = this;
  5307.  
  5308.     that.__manuallyStopped = false;
  5309.    
  5310.     if (that.type === 'youtube') {
  5311.       if (that.ytReady) {
  5312.         that.$video.trigger('play');
  5313.         that.ytPlayer.playVideo();
  5314.       }
  5315.     } else {
  5316.       that.video.play();
  5317.     }
  5318.  
  5319.     return that;
  5320.   };
  5321.  
  5322.   VideoWrapper.prototype.pause = function () {
  5323.     var that = this;
  5324.  
  5325.     that.__manuallyStopped = false;
  5326.    
  5327.     if (that.type === 'youtube') {
  5328.       if (that.ytReady) {
  5329.         that.ytPlayer.pauseVideo();
  5330.       }
  5331.     } else {
  5332.       that.video.pause();
  5333.     }
  5334.  
  5335.     return that;
  5336.   };
  5337.  
  5338.   VideoWrapper.prototype.stop = function () {
  5339.     var that = this;
  5340.  
  5341.     that.__manuallyStopped = true;
  5342.    
  5343.     if (that.type === 'youtube') {
  5344.       if (that.ytReady) {
  5345.         that.ytPlayer.pauseVideo();
  5346.         that.ytPlayer.seekTo(0);
  5347.       }
  5348.     } else {
  5349.       that.video.pause();
  5350.       that.video.currentTime = 0;
  5351.     }
  5352.  
  5353.     return that;
  5354.   };
  5355.  
  5356.   VideoWrapper.prototype.destroy = function () {
  5357.     var that = this;
  5358.  
  5359.     if (that.ytPlayer) {
  5360.       that.ytPlayer.destroy();
  5361.     }
  5362.  
  5363.     that.$video.remove();
  5364.  
  5365.     return that;
  5366.   };
  5367.  
  5368.   VideoWrapper.prototype.getCurrentTime = function (seconds) {
  5369.     var that = this;
  5370.  
  5371.     if (that.type === 'youtube') {
  5372.       if (that.ytReady) {
  5373.         return that.ytPlayer.getCurrentTime();
  5374.       }
  5375.     } else {
  5376.       return that.video.currentTime;
  5377.     }
  5378.  
  5379.     return 0;
  5380.   };
  5381.  
  5382.   VideoWrapper.prototype.setCurrentTime = function (seconds) {
  5383.     var that = this;
  5384.  
  5385.     if (that.type === 'youtube') {
  5386.       if (that.ytReady) {
  5387.         that.ytPlayer.seekTo(seconds, true);
  5388.       }
  5389.     } else {
  5390.       that.video.currentTime = seconds;
  5391.     }
  5392.  
  5393.     return that;
  5394.   };
  5395.  
  5396.   VideoWrapper.prototype.getDuration = function () {
  5397.     var that = this;
  5398.  
  5399.     if (that.type === 'youtube') {
  5400.       if (that.ytReady) {
  5401.         return that.ytPlayer.getDuration();
  5402.       }
  5403.     } else {
  5404.       return that.video.duration;
  5405.     }
  5406.  
  5407.     return 0;
  5408.   };
  5409.  
  5410.   /**
  5411.    * This will load the youtube API (if not loaded yet)
  5412.    * Use $(window).one('youtube_api_load', ...) to listen for API loaded event
  5413.    */
  5414.   VideoWrapper.loadYoutubeAPI = function () {
  5415.     if (window['YT']) {
  5416.       return;
  5417.     }
  5418.     if (!$('script[src*=www\\.youtube\\.com\\/iframe_api]').length) {
  5419.       $('<script type="text/javascript" src="https://www.youtube.com/iframe_api">').appendTo('body');
  5420.     }
  5421.     var ytAPILoadInt = setInterval(function () {
  5422.       if (window['YT'] && window['YT'].loaded) {
  5423.         $(window).trigger('youtube_api_load');
  5424.         clearTimeout(ytAPILoadInt);
  5425.       }
  5426.     }, 50);
  5427.   };
  5428.  
  5429.  
  5430.   /* SUPPORTS FIXED POSITION?
  5431.    *
  5432.    * Based on code from jQuery Mobile 1.1.0
  5433.    * http://jquerymobile.com/
  5434.    *
  5435.    * In a nutshell, we need to figure out if fixed positioning is supported.
  5436.    * Unfortunately, this is very difficult to do on iOS, and usually involves
  5437.    * injecting content, scrolling the page, etc.. It's ugly.
  5438.    * jQuery Mobile uses this workaround. It's not ideal, but works.
  5439.    *
  5440.    * Modified to detect IE6
  5441.    * ========================= */
  5442.  
  5443.   var supportsFixedPosition = (function () {
  5444.     var ua = navigator.userAgent
  5445.       , platform = navigator.platform
  5446.         // Rendering engine is Webkit, and capture major version
  5447.       , wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ )
  5448.       , wkversion = !!wkmatch && wkmatch[ 1 ]
  5449.       , ffmatch = ua.match( /Fennec\/([0-9]+)/ )
  5450.       , ffversion = !!ffmatch && ffmatch[ 1 ]
  5451.       , operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ )
  5452.       , omversion = !!operammobilematch && operammobilematch[ 1 ]
  5453.       , iematch = ua.match( /MSIE ([0-9]+)/ )
  5454.       , ieversion = !!iematch && iematch[ 1 ];
  5455.  
  5456.     return !(
  5457.       // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
  5458.       ((platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1  || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534) ||
  5459.  
  5460.       // Opera Mini
  5461.       (window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]") ||
  5462.       (operammobilematch && omversion < 7458) ||
  5463.  
  5464.       //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
  5465.       (ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533) ||
  5466.  
  5467.       // Firefox Mobile before 6.0 -
  5468.       (ffversion && ffversion < 6) ||
  5469.  
  5470.       // WebOS less than 3
  5471.       ("palmGetResource" in window && wkversion && wkversion < 534) ||
  5472.  
  5473.       // MeeGo
  5474.       (ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1) ||
  5475.  
  5476.       // IE6
  5477.       (ieversion && ieversion <= 6)
  5478.     );
  5479.   }());
  5480.  
  5481. }(jQuery, window));
  5482.  
  5483. },{}],21:[function(require,module,exports){
  5484. /*!
  5485.  * Tap listener v1.1.2
  5486.  * listens to taps
  5487.  * MIT license
  5488.  */
  5489.  
  5490. /*jshint browser: true, unused: true, undef: true, strict: true */
  5491.  
  5492. ( function( window, factory ) {
  5493.   // universal module definition
  5494.   /*jshint strict: false*/ /*globals define, module, require */
  5495.  
  5496.   if ( typeof define == 'function' && define.amd ) {
  5497.     // AMD
  5498.     define( [
  5499.       'unipointer/unipointer'
  5500.     ], function( Unipointer ) {
  5501.       return factory( window, Unipointer );
  5502.     });
  5503.   } else if ( typeof exports == 'object' ) {
  5504.     // CommonJS
  5505.     module.exports = factory(
  5506.       window,
  5507.       require('unipointer')
  5508.     );
  5509.   } else {
  5510.     // browser global
  5511.     window.TapListener = factory(
  5512.       window,
  5513.       window.Unipointer
  5514.     );
  5515.   }
  5516.  
  5517. }( window, function factory( window, Unipointer ) {
  5518.  
  5519. 'use strict';
  5520.  
  5521. // --------------------------  TapListener -------------------------- //
  5522.  
  5523. function TapListener( elem ) {
  5524.   this.bindTap( elem );
  5525. }
  5526.  
  5527. // inherit Unipointer & EventEmitter
  5528. TapListener.prototype = new Unipointer();
  5529.  
  5530. /**
  5531.  * bind tap event to element
  5532.  * @param {Element} elem
  5533.  */
  5534. TapListener.prototype.bindTap = function( elem ) {
  5535.   if ( !elem ) {
  5536.     return;
  5537.   }
  5538.   this.unbindTap();
  5539.   this.tapElement = elem;
  5540.   this._bindStartEvent( elem, true );
  5541. };
  5542.  
  5543. TapListener.prototype.unbindTap = function() {
  5544.   if ( !this.tapElement ) {
  5545.     return;
  5546.   }
  5547.   this._bindStartEvent( this.tapElement, true );
  5548.   delete this.tapElement;
  5549. };
  5550.  
  5551. var isPageOffset = window.pageYOffset !== undefined;
  5552. /**
  5553.  * pointer up
  5554.  * @param {Event} event
  5555.  * @param {Event or Touch} pointer
  5556.  */
  5557. TapListener.prototype.pointerUp = function( event, pointer ) {
  5558.   // ignore emulated mouse up clicks
  5559.   if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
  5560.     return;
  5561.   }
  5562.  
  5563.   var pointerPoint = Unipointer.getPointerPoint( pointer );
  5564.   var boundingRect = this.tapElement.getBoundingClientRect();
  5565.   // standard or IE8 scroll positions
  5566.   var scrollX = isPageOffset ? window.pageXOffset : document.body.scrollLeft;
  5567.   var scrollY = isPageOffset ? window.pageYOffset : document.body.scrollTop;
  5568.   // calculate if pointer is inside tapElement
  5569.   var isInside = pointerPoint.x >= boundingRect.left + scrollX &&
  5570.     pointerPoint.x <= boundingRect.right + scrollX &&
  5571.     pointerPoint.y >= boundingRect.top + scrollY &&
  5572.     pointerPoint.y <= boundingRect.bottom + scrollY;
  5573.   // trigger callback if pointer is inside element
  5574.   if ( isInside ) {
  5575.     this.emitEvent( 'tap', [ event, pointer ] );
  5576.   }
  5577.  
  5578.   // set flag for emulated clicks 300ms after touchend
  5579.   if ( event.type != 'mouseup' ) {
  5580.     this.isIgnoringMouseUp = true;
  5581.     // reset flag after 300ms
  5582.     setTimeout( function() {
  5583.       delete this.isIgnoringMouseUp;
  5584.     }.bind( this ), 320 );
  5585.   }
  5586. };
  5587.  
  5588. TapListener.prototype.destroy = function() {
  5589.   this.pointerDone();
  5590.   this.unbindTap();
  5591. };
  5592.  
  5593. // -----  ----- //
  5594.  
  5595. return TapListener;
  5596.  
  5597. }));
  5598.  
  5599. },{"unipointer":23}],22:[function(require,module,exports){
  5600. /*!
  5601.  * Unidragger v1.1.5
  5602.  * Draggable base class
  5603.  * MIT license
  5604.  */
  5605.  
  5606. /*jshint browser: true, unused: true, undef: true, strict: true */
  5607.  
  5608. ( function( window, factory ) {
  5609.   /*global define: false, module: false, require: false */
  5610.   'use strict';
  5611.   // universal module definition
  5612.  
  5613.   if ( typeof define == 'function' && define.amd ) {
  5614.     // AMD
  5615.     define( [
  5616.       'eventie/eventie',
  5617.       'unipointer/unipointer'
  5618.     ], function( eventie, Unipointer ) {
  5619.       return factory( window, eventie, Unipointer );
  5620.     });
  5621.   } else if ( typeof exports == 'object' ) {
  5622.     // CommonJS
  5623.     module.exports = factory(
  5624.       window,
  5625.       require('eventie'),
  5626.       require('unipointer')
  5627.     );
  5628.   } else {
  5629.     // browser global
  5630.     window.Unidragger = factory(
  5631.       window,
  5632.       window.eventie,
  5633.       window.Unipointer
  5634.     );
  5635.   }
  5636.  
  5637. }( window, function factory( window, eventie, Unipointer ) {
  5638.  
  5639. 'use strict';
  5640.  
  5641. // -----  ----- //
  5642.  
  5643. function noop() {}
  5644.  
  5645. // handle IE8 prevent default
  5646. function preventDefaultEvent( event ) {
  5647.   if ( event.preventDefault ) {
  5648.     event.preventDefault();
  5649.   } else {
  5650.     event.returnValue = false;
  5651.   }
  5652. }
  5653.  
  5654. // -------------------------- Unidragger -------------------------- //
  5655.  
  5656. function Unidragger() {}
  5657.  
  5658. // inherit Unipointer & EventEmitter
  5659. Unidragger.prototype = new Unipointer();
  5660.  
  5661. // ----- bind start ----- //
  5662.  
  5663. Unidragger.prototype.bindHandles = function() {
  5664.   this._bindHandles( true );
  5665. };
  5666.  
  5667. Unidragger.prototype.unbindHandles = function() {
  5668.   this._bindHandles( false );
  5669. };
  5670.  
  5671. var navigator = window.navigator;
  5672. /**
  5673.  * works as unbinder, as you can .bindHandles( false ) to unbind
  5674.  * @param {Boolean} isBind - will unbind if falsey
  5675.  */
  5676. Unidragger.prototype._bindHandles = function( isBind ) {
  5677.   // munge isBind, default to true
  5678.   isBind = isBind === undefined ? true : !!isBind;
  5679.   // extra bind logic
  5680.   var binderExtra;
  5681.   if ( navigator.pointerEnabled ) {
  5682.     binderExtra = function( handle ) {
  5683.       // disable scrolling on the element
  5684.       handle.style.touchAction = isBind ? 'none' : '';
  5685.     };
  5686.   } else if ( navigator.msPointerEnabled ) {
  5687.     binderExtra = function( handle ) {
  5688.       // disable scrolling on the element
  5689.       handle.style.msTouchAction = isBind ? 'none' : '';
  5690.     };
  5691.   } else {
  5692.     binderExtra = function() {
  5693.       // TODO re-enable img.ondragstart when unbinding
  5694.       if ( isBind ) {
  5695.         disableImgOndragstart( handle );
  5696.       }
  5697.     };
  5698.   }
  5699.   // bind each handle
  5700.   var bindMethod = isBind ? 'bind' : 'unbind';
  5701.   for ( var i=0, len = this.handles.length; i < len; i++ ) {
  5702.     var handle = this.handles[i];
  5703.     this._bindStartEvent( handle, isBind );
  5704.     binderExtra( handle );
  5705.     eventie[ bindMethod ]( handle, 'click', this );
  5706.   }
  5707. };
  5708.  
  5709. // remove default dragging interaction on all images in IE8
  5710. // IE8 does its own drag thing on images, which messes stuff up
  5711.  
  5712. function noDragStart() {
  5713.   return false;
  5714. }
  5715.  
  5716. // TODO replace this with a IE8 test
  5717. var isIE8 = 'attachEvent' in document.documentElement;
  5718.  
  5719. // IE8 only
  5720. var disableImgOndragstart = !isIE8 ? noop : function( handle ) {
  5721.  
  5722.   if ( handle.nodeName == 'IMG' ) {
  5723.     handle.ondragstart = noDragStart;
  5724.   }
  5725.  
  5726.   var images = handle.querySelectorAll('img');
  5727.   for ( var i=0, len = images.length; i < len; i++ ) {
  5728.     var img = images[i];
  5729.     img.ondragstart = noDragStart;
  5730.   }
  5731. };
  5732.  
  5733. // ----- start event ----- //
  5734.  
  5735. /**
  5736.  * pointer start
  5737.  * @param {Event} event
  5738.  * @param {Event or Touch} pointer
  5739.  */
  5740. Unidragger.prototype.pointerDown = function( event, pointer ) {
  5741.   // dismiss range sliders
  5742.   if ( event.target.nodeName == 'INPUT' && event.target.type == 'range' ) {
  5743.     // reset pointerDown logic
  5744.     this.isPointerDown = false;
  5745.     delete this.pointerIdentifier;
  5746.     return;
  5747.   }
  5748.  
  5749.   this._dragPointerDown( event, pointer );
  5750.   // kludge to blur focused inputs in dragger
  5751.   var focused = document.activeElement;
  5752.   if ( focused && focused.blur ) {
  5753.     focused.blur();
  5754.   }
  5755.   // bind move and end events
  5756.   this._bindPostStartEvents( event );
  5757.   // track scrolling
  5758.   this.pointerDownScroll = Unidragger.getScrollPosition();
  5759.   eventie.bind( window, 'scroll', this );
  5760.  
  5761.   this.emitEvent( 'pointerDown', [ event, pointer ] );
  5762. };
  5763.  
  5764. // base pointer down logic
  5765. Unidragger.prototype._dragPointerDown = function( event, pointer ) {
  5766.   // track to see when dragging starts
  5767.   this.pointerDownPoint = Unipointer.getPointerPoint( pointer );
  5768.  
  5769.   // prevent default, unless touchstart or <select>
  5770.   var isTouchstart = event.type == 'touchstart';
  5771.   var targetNodeName = event.target.nodeName;
  5772.   if ( !isTouchstart && targetNodeName != 'SELECT' ) {
  5773.     preventDefaultEvent( event );
  5774.   }
  5775. };
  5776.  
  5777. // ----- move event ----- //
  5778.  
  5779. /**
  5780.  * drag move
  5781.  * @param {Event} event
  5782.  * @param {Event or Touch} pointer
  5783.  */
  5784. Unidragger.prototype.pointerMove = function( event, pointer ) {
  5785.   var moveVector = this._dragPointerMove( event, pointer );
  5786.   this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
  5787.   this._dragMove( event, pointer, moveVector );
  5788. };
  5789.  
  5790. // base pointer move logic
  5791. Unidragger.prototype._dragPointerMove = function( event, pointer ) {
  5792.   var movePoint = Unipointer.getPointerPoint( pointer );
  5793.   var moveVector = {
  5794.     x: movePoint.x - this.pointerDownPoint.x,
  5795.     y: movePoint.y - this.pointerDownPoint.y
  5796.   };
  5797.   // start drag if pointer has moved far enough to start drag
  5798.   if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {
  5799.     this._dragStart( event, pointer );
  5800.   }
  5801.   return moveVector;
  5802. };
  5803.  
  5804. // condition if pointer has moved far enough to start drag
  5805. Unidragger.prototype.hasDragStarted = function( moveVector ) {
  5806.   return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
  5807. };
  5808.  
  5809.  
  5810. // ----- end event ----- //
  5811.  
  5812. /**
  5813.  * pointer up
  5814.  * @param {Event} event
  5815.  * @param {Event or Touch} pointer
  5816.  */
  5817. Unidragger.prototype.pointerUp = function( event, pointer ) {
  5818.   this.emitEvent( 'pointerUp', [ event, pointer ] );
  5819.   this._dragPointerUp( event, pointer );
  5820. };
  5821.  
  5822. Unidragger.prototype._dragPointerUp = function( event, pointer ) {
  5823.   if ( this.isDragging ) {
  5824.     this._dragEnd( event, pointer );
  5825.   } else {
  5826.     // pointer didn't move enough for drag to start
  5827.     this._staticClick( event, pointer );
  5828.   }
  5829. };
  5830.  
  5831. Unipointer.prototype.pointerDone = function() {
  5832.   eventie.unbind( window, 'scroll', this );
  5833. };
  5834.  
  5835. // -------------------------- drag -------------------------- //
  5836.  
  5837. // dragStart
  5838. Unidragger.prototype._dragStart = function( event, pointer ) {
  5839.   this.isDragging = true;
  5840.   this.dragStartPoint = Unidragger.getPointerPoint( pointer );
  5841.   // prevent clicks
  5842.   this.isPreventingClicks = true;
  5843.  
  5844.   this.dragStart( event, pointer );
  5845. };
  5846.  
  5847. Unidragger.prototype.dragStart = function( event, pointer ) {
  5848.   this.emitEvent( 'dragStart', [ event, pointer ] );
  5849. };
  5850.  
  5851. // dragMove
  5852. Unidragger.prototype._dragMove = function( event, pointer, moveVector ) {
  5853.   // do not drag if not dragging yet
  5854.   if ( !this.isDragging ) {
  5855.     return;
  5856.   }
  5857.  
  5858.   this.dragMove( event, pointer, moveVector );
  5859. };
  5860.  
  5861. Unidragger.prototype.dragMove = function( event, pointer, moveVector ) {
  5862.   preventDefaultEvent( event );
  5863.   this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
  5864. };
  5865.  
  5866. // dragEnd
  5867. Unidragger.prototype._dragEnd = function( event, pointer ) {
  5868.   // set flags
  5869.   this.isDragging = false;
  5870.   // re-enable clicking async
  5871.   var _this = this;
  5872.   setTimeout( function() {
  5873.     delete _this.isPreventingClicks;
  5874.   });
  5875.  
  5876.   this.dragEnd( event, pointer );
  5877. };
  5878.  
  5879. Unidragger.prototype.dragEnd = function( event, pointer ) {
  5880.   this.emitEvent( 'dragEnd', [ event, pointer ] );
  5881. };
  5882.  
  5883. Unidragger.prototype.pointerDone = function() {
  5884.   eventie.unbind( window, 'scroll', this );
  5885.   delete this.pointerDownScroll;
  5886. };
  5887.  
  5888. // ----- onclick ----- //
  5889.  
  5890. // handle all clicks and prevent clicks when dragging
  5891. Unidragger.prototype.onclick = function( event ) {
  5892.   if ( this.isPreventingClicks ) {
  5893.     preventDefaultEvent( event );
  5894.   }
  5895. };
  5896.  
  5897. // ----- staticClick ----- //
  5898.  
  5899. // triggered after pointer down & up with no/tiny movement
  5900. Unidragger.prototype._staticClick = function( event, pointer ) {
  5901.   // ignore emulated mouse up clicks
  5902.   if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
  5903.     return;
  5904.   }
  5905.  
  5906.   // allow click in <input>s and <textarea>s
  5907.   var nodeName = event.target.nodeName;
  5908.   if ( nodeName == 'INPUT' || nodeName == 'TEXTAREA' ) {
  5909.     event.target.focus();
  5910.   }
  5911.   this.staticClick( event, pointer );
  5912.  
  5913.   // set flag for emulated clicks 300ms after touchend
  5914.   if ( event.type != 'mouseup' ) {
  5915.     this.isIgnoringMouseUp = true;
  5916.     var _this = this;
  5917.     // reset flag after 300ms
  5918.     setTimeout( function() {
  5919.       delete _this.isIgnoringMouseUp;
  5920.     }, 400 );
  5921.   }
  5922. };
  5923.  
  5924. Unidragger.prototype.staticClick = function( event, pointer ) {
  5925.   this.emitEvent( 'staticClick', [ event, pointer ] );
  5926. };
  5927.  
  5928. // ----- scroll ----- //
  5929.  
  5930. Unidragger.prototype.onscroll = function() {
  5931.   var scroll = Unidragger.getScrollPosition();
  5932.   var scrollMoveX = this.pointerDownScroll.x - scroll.x;
  5933.   var scrollMoveY = this.pointerDownScroll.y - scroll.y;
  5934.   // cancel click/tap if scroll is too much
  5935.   if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {
  5936.     this._pointerDone();
  5937.   }
  5938. };
  5939.  
  5940. // ----- utils ----- //
  5941.  
  5942. Unidragger.getPointerPoint = function( pointer ) {
  5943.   return {
  5944.     x: pointer.pageX !== undefined ? pointer.pageX : pointer.clientX,
  5945.     y: pointer.pageY !== undefined ? pointer.pageY : pointer.clientY
  5946.   };
  5947. };
  5948.  
  5949. var isPageOffset = window.pageYOffset !== undefined;
  5950.  
  5951. // get scroll in { x, y }
  5952. Unidragger.getScrollPosition = function() {
  5953.   return {
  5954.     x: isPageOffset ? window.pageXOffset : document.body.scrollLeft,
  5955.     y: isPageOffset ? window.pageYOffset : document.body.scrollTop
  5956.   };
  5957. };
  5958.  
  5959. // -----  ----- //
  5960.  
  5961. Unidragger.getPointerPoint = Unipointer.getPointerPoint;
  5962.  
  5963. return Unidragger;
  5964.  
  5965. }));
  5966.  
  5967. },{"eventie":7,"unipointer":23}],23:[function(require,module,exports){
  5968. /*!
  5969.  * Unipointer v1.1.0
  5970.  * base class for doing one thing with pointer event
  5971.  * MIT license
  5972.  */
  5973.  
  5974. /*jshint browser: true, undef: true, unused: true, strict: true */
  5975. /*global define: false, module: false, require: false */
  5976.  
  5977. ( function( window, factory ) {
  5978.   'use strict';
  5979.   // universal module definition
  5980.  
  5981.   if ( typeof define == 'function' && define.amd ) {
  5982.     // AMD
  5983.     define( [
  5984.       'eventEmitter/EventEmitter',
  5985.       'eventie/eventie'
  5986.     ], function( EventEmitter, eventie ) {
  5987.       return factory( window, EventEmitter, eventie );
  5988.     });
  5989.   } else if ( typeof exports == 'object' ) {
  5990.     // CommonJS
  5991.     module.exports = factory(
  5992.       window,
  5993.       require('wolfy87-eventemitter'),
  5994.       require('eventie')
  5995.     );
  5996.   } else {
  5997.     // browser global
  5998.     window.Unipointer = factory(
  5999.       window,
  6000.       window.EventEmitter,
  6001.       window.eventie
  6002.     );
  6003.   }
  6004.  
  6005. }( window, function factory( window, EventEmitter, eventie ) {
  6006.  
  6007. 'use strict';
  6008.  
  6009. function noop() {}
  6010.  
  6011. function Unipointer() {}
  6012.  
  6013. // inherit EventEmitter
  6014. Unipointer.prototype = new EventEmitter();
  6015.  
  6016. Unipointer.prototype.bindStartEvent = function( elem ) {
  6017.   this._bindStartEvent( elem, true );
  6018. };
  6019.  
  6020. Unipointer.prototype.unbindStartEvent = function( elem ) {
  6021.   this._bindStartEvent( elem, false );
  6022. };
  6023.  
  6024. /**
  6025.  * works as unbinder, as you can ._bindStart( false ) to unbind
  6026.  * @param {Boolean} isBind - will unbind if falsey
  6027.  */
  6028. Unipointer.prototype._bindStartEvent = function( elem, isBind ) {
  6029.   // munge isBind, default to true
  6030.   isBind = isBind === undefined ? true : !!isBind;
  6031.   var bindMethod = isBind ? 'bind' : 'unbind';
  6032.  
  6033.   if ( window.navigator.pointerEnabled ) {
  6034.     // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca
  6035.     eventie[ bindMethod ]( elem, 'pointerdown', this );
  6036.   } else if ( window.navigator.msPointerEnabled ) {
  6037.     // IE10 Pointer Events
  6038.     eventie[ bindMethod ]( elem, 'MSPointerDown', this );
  6039.   } else {
  6040.     // listen for both, for devices like Chrome Pixel
  6041.     eventie[ bindMethod ]( elem, 'mousedown', this );
  6042.     eventie[ bindMethod ]( elem, 'touchstart', this );
  6043.   }
  6044. };
  6045.  
  6046. // trigger handler methods for events
  6047. Unipointer.prototype.handleEvent = function( event ) {
  6048.   var method = 'on' + event.type;
  6049.   if ( this[ method ] ) {
  6050.     this[ method ]( event );
  6051.   }
  6052. };
  6053.  
  6054. // returns the touch that we're keeping track of
  6055. Unipointer.prototype.getTouch = function( touches ) {
  6056.   for ( var i=0, len = touches.length; i < len; i++ ) {
  6057.     var touch = touches[i];
  6058.     if ( touch.identifier == this.pointerIdentifier ) {
  6059.       return touch;
  6060.     }
  6061.   }
  6062. };
  6063.  
  6064. // ----- start event ----- //
  6065.  
  6066. Unipointer.prototype.onmousedown = function( event ) {
  6067.   // dismiss clicks from right or middle buttons
  6068.   var button = event.button;
  6069.   if ( button && ( button !== 0 && button !== 1 ) ) {
  6070.     return;
  6071.   }
  6072.   this._pointerDown( event, event );
  6073. };
  6074.  
  6075. Unipointer.prototype.ontouchstart = function( event ) {
  6076.   this._pointerDown( event, event.changedTouches[0] );
  6077. };
  6078.  
  6079. Unipointer.prototype.onMSPointerDown =
  6080. Unipointer.prototype.onpointerdown = function( event ) {
  6081.   this._pointerDown( event, event );
  6082. };
  6083.  
  6084. /**
  6085.  * pointer start
  6086.  * @param {Event} event
  6087.  * @param {Event or Touch} pointer
  6088.  */
  6089. Unipointer.prototype._pointerDown = function( event, pointer ) {
  6090.   // dismiss other pointers
  6091.   if ( this.isPointerDown ) {
  6092.     return;
  6093.   }
  6094.  
  6095.   this.isPointerDown = true;
  6096.   // save pointer identifier to match up touch events
  6097.   this.pointerIdentifier = pointer.pointerId !== undefined ?
  6098.     // pointerId for pointer events, touch.indentifier for touch events
  6099.     pointer.pointerId : pointer.identifier;
  6100.  
  6101.   this.pointerDown( event, pointer );
  6102. };
  6103.  
  6104. Unipointer.prototype.pointerDown = function( event, pointer ) {
  6105.   this._bindPostStartEvents( event );
  6106.   this.emitEvent( 'pointerDown', [ event, pointer ] );
  6107. };
  6108.  
  6109. // hash of events to be bound after start event
  6110. var postStartEvents = {
  6111.   mousedown: [ 'mousemove', 'mouseup' ],
  6112.   touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
  6113.   pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
  6114.   MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ]
  6115. };
  6116.  
  6117. Unipointer.prototype._bindPostStartEvents = function( event ) {
  6118.   if ( !event ) {
  6119.     return;
  6120.   }
  6121.   // get proper events to match start event
  6122.   var events = postStartEvents[ event.type ];
  6123.   // IE8 needs to be bound to document
  6124.   var node = event.preventDefault ? window : document;
  6125.   // bind events to node
  6126.   for ( var i=0, len = events.length; i < len; i++ ) {
  6127.     var evnt = events[i];
  6128.     eventie.bind( node, evnt, this );
  6129.   }
  6130.   // save these arguments
  6131.   this._boundPointerEvents = {
  6132.     events: events,
  6133.     node: node
  6134.   };
  6135. };
  6136.  
  6137. Unipointer.prototype._unbindPostStartEvents = function() {
  6138.   var args = this._boundPointerEvents;
  6139.   // IE8 can trigger dragEnd twice, check for _boundEvents
  6140.   if ( !args || !args.events ) {
  6141.     return;
  6142.   }
  6143.  
  6144.   for ( var i=0, len = args.events.length; i < len; i++ ) {
  6145.     var event = args.events[i];
  6146.     eventie.unbind( args.node, event, this );
  6147.   }
  6148.   delete this._boundPointerEvents;
  6149. };
  6150.  
  6151. // ----- move event ----- //
  6152.  
  6153. Unipointer.prototype.onmousemove = function( event ) {
  6154.   this._pointerMove( event, event );
  6155. };
  6156.  
  6157. Unipointer.prototype.onMSPointerMove =
  6158. Unipointer.prototype.onpointermove = function( event ) {
  6159.   if ( event.pointerId == this.pointerIdentifier ) {
  6160.     this._pointerMove( event, event );
  6161.   }
  6162. };
  6163.  
  6164. Unipointer.prototype.ontouchmove = function( event ) {
  6165.   var touch = this.getTouch( event.changedTouches );
  6166.   if ( touch ) {
  6167.     this._pointerMove( event, touch );
  6168.   }
  6169. };
  6170.  
  6171. /**
  6172.  * pointer move
  6173.  * @param {Event} event
  6174.  * @param {Event or Touch} pointer
  6175.  * @private
  6176.  */
  6177. Unipointer.prototype._pointerMove = function( event, pointer ) {
  6178.   this.pointerMove( event, pointer );
  6179. };
  6180.  
  6181. // public
  6182. Unipointer.prototype.pointerMove = function( event, pointer ) {
  6183.   this.emitEvent( 'pointerMove', [ event, pointer ] );
  6184. };
  6185.  
  6186. // ----- end event ----- //
  6187.  
  6188.  
  6189. Unipointer.prototype.onmouseup = function( event ) {
  6190.   this._pointerUp( event, event );
  6191. };
  6192.  
  6193. Unipointer.prototype.onMSPointerUp =
  6194. Unipointer.prototype.onpointerup = function( event ) {
  6195.   if ( event.pointerId == this.pointerIdentifier ) {
  6196.     this._pointerUp( event, event );
  6197.   }
  6198. };
  6199.  
  6200. Unipointer.prototype.ontouchend = function( event ) {
  6201.   var touch = this.getTouch( event.changedTouches );
  6202.   if ( touch ) {
  6203.     this._pointerUp( event, touch );
  6204.   }
  6205. };
  6206.  
  6207. /**
  6208.  * pointer up
  6209.  * @param {Event} event
  6210.  * @param {Event or Touch} pointer
  6211.  * @private
  6212.  */
  6213. Unipointer.prototype._pointerUp = function( event, pointer ) {
  6214.   this._pointerDone();
  6215.   this.pointerUp( event, pointer );
  6216. };
  6217.  
  6218. // public
  6219. Unipointer.prototype.pointerUp = function( event, pointer ) {
  6220.   this.emitEvent( 'pointerUp', [ event, pointer ] );
  6221. };
  6222.  
  6223. // ----- pointer done ----- //
  6224.  
  6225. // triggered on pointer up & pointer cancel
  6226. Unipointer.prototype._pointerDone = function() {
  6227.   // reset properties
  6228.   this.isPointerDown = false;
  6229.   delete this.pointerIdentifier;
  6230.   // remove events
  6231.   this._unbindPostStartEvents();
  6232.   this.pointerDone();
  6233. };
  6234.  
  6235. Unipointer.prototype.pointerDone = noop;
  6236.  
  6237. // ----- pointer cancel ----- //
  6238.  
  6239. Unipointer.prototype.onMSPointerCancel =
  6240. Unipointer.prototype.onpointercancel = function( event ) {
  6241.   if ( event.pointerId == this.pointerIdentifier ) {
  6242.     this._pointerCancel( event, event );
  6243.   }
  6244. };
  6245.  
  6246. Unipointer.prototype.ontouchcancel = function( event ) {
  6247.   var touch = this.getTouch( event.changedTouches );
  6248.   if ( touch ) {
  6249.     this._pointerCancel( event, touch );
  6250.   }
  6251. };
  6252.  
  6253. /**
  6254.  * pointer cancel
  6255.  * @param {Event} event
  6256.  * @param {Event or Touch} pointer
  6257.  * @private
  6258.  */
  6259. Unipointer.prototype._pointerCancel = function( event, pointer ) {
  6260.   this._pointerDone();
  6261.   this.pointerCancel( event, pointer );
  6262. };
  6263.  
  6264. // public
  6265. Unipointer.prototype.pointerCancel = function( event, pointer ) {
  6266.   this.emitEvent( 'pointerCancel', [ event, pointer ] );
  6267. };
  6268.  
  6269. // -----  ----- //
  6270.  
  6271. // utility function for getting x/y cooridinates from event, because IE8
  6272. Unipointer.getPointerPoint = function( pointer ) {
  6273.   return {
  6274.     x: pointer.pageX !== undefined ? pointer.pageX : pointer.clientX,
  6275.     y: pointer.pageY !== undefined ? pointer.pageY : pointer.clientY
  6276.   };
  6277. };
  6278.  
  6279. // -----  ----- //
  6280.  
  6281. return Unipointer;
  6282.  
  6283. }));
  6284.  
  6285. },{"eventie":7,"wolfy87-eventemitter":24}],24:[function(require,module,exports){
  6286. /*!
  6287.  * EventEmitter v4.2.11 - git.io/ee
  6288.  * Unlicense - http://unlicense.org/
  6289.  * Oliver Caldwell - http://oli.me.uk/
  6290.  * @preserve
  6291.  */
  6292.  
  6293. ;(function () {
  6294.     'use strict';
  6295.  
  6296.     /**
  6297.      * Class for managing events.
  6298.      * Can be extended to provide event functionality in other classes.
  6299.      *
  6300.      * @class EventEmitter Manages event registering and emitting.
  6301.      */
  6302.     function EventEmitter() {}
  6303.  
  6304.     // Shortcuts to improve speed and size
  6305.     var proto = EventEmitter.prototype;
  6306.     var exports = this;
  6307.     var originalGlobalValue = exports.EventEmitter;
  6308.  
  6309.     /**
  6310.      * Finds the index of the listener for the event in its storage array.
  6311.      *
  6312.      * @param {Function[]} listeners Array of listeners to search through.
  6313.      * @param {Function} listener Method to look for.
  6314.      * @return {Number} Index of the specified listener, -1 if not found
  6315.      * @api private
  6316.      */
  6317.     function indexOfListener(listeners, listener) {
  6318.         var i = listeners.length;
  6319.         while (i--) {
  6320.             if (listeners[i].listener === listener) {
  6321.                 return i;
  6322.             }
  6323.         }
  6324.  
  6325.         return -1;
  6326.     }
  6327.  
  6328.     /**
  6329.      * Alias a method while keeping the context correct, to allow for overwriting of target method.
  6330.      *
  6331.      * @param {String} name The name of the target method.
  6332.      * @return {Function} The aliased method
  6333.      * @api private
  6334.      */
  6335.     function alias(name) {
  6336.         return function aliasClosure() {
  6337.             return this[name].apply(this, arguments);
  6338.         };
  6339.     }
  6340.  
  6341.     /**
  6342.      * Returns the listener array for the specified event.
  6343.      * Will initialise the event object and listener arrays if required.
  6344.      * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
  6345.      * Each property in the object response is an array of listener functions.
  6346.      *
  6347.      * @param {String|RegExp} evt Name of the event to return the listeners from.
  6348.      * @return {Function[]|Object} All listener functions for the event.
  6349.      */
  6350.     proto.getListeners = function getListeners(evt) {
  6351.         var events = this._getEvents();
  6352.         var response;
  6353.         var key;
  6354.  
  6355.         // Return a concatenated array of all matching events if
  6356.         // the selector is a regular expression.
  6357.         if (evt instanceof RegExp) {
  6358.             response = {};
  6359.             for (key in events) {
  6360.                 if (events.hasOwnProperty(key) && evt.test(key)) {
  6361.                     response[key] = events[key];
  6362.                 }
  6363.             }
  6364.         }
  6365.         else {
  6366.             response = events[evt] || (events[evt] = []);
  6367.         }
  6368.  
  6369.         return response;
  6370.     };
  6371.  
  6372.     /**
  6373.      * Takes a list of listener objects and flattens it into a list of listener functions.
  6374.      *
  6375.      * @param {Object[]} listeners Raw listener objects.
  6376.      * @return {Function[]} Just the listener functions.
  6377.      */
  6378.     proto.flattenListeners = function flattenListeners(listeners) {
  6379.         var flatListeners = [];
  6380.         var i;
  6381.  
  6382.         for (i = 0; i < listeners.length; i += 1) {
  6383.             flatListeners.push(listeners[i].listener);
  6384.         }
  6385.  
  6386.         return flatListeners;
  6387.     };
  6388.  
  6389.     /**
  6390.      * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
  6391.      *
  6392.      * @param {String|RegExp} evt Name of the event to return the listeners from.
  6393.      * @return {Object} All listener functions for an event in an object.
  6394.      */
  6395.     proto.getListenersAsObject = function getListenersAsObject(evt) {
  6396.         var listeners = this.getListeners(evt);
  6397.         var response;
  6398.  
  6399.         if (listeners instanceof Array) {
  6400.             response = {};
  6401.             response[evt] = listeners;
  6402.         }
  6403.  
  6404.         return response || listeners;
  6405.     };
  6406.  
  6407.     /**
  6408.      * Adds a listener function to the specified event.
  6409.      * The listener will not be added if it is a duplicate.
  6410.      * If the listener returns true then it will be removed after it is called.
  6411.      * If you pass a regular expression as the event name then the listener will be added to all events that match it.
  6412.      *
  6413.      * @param {String|RegExp} evt Name of the event to attach the listener to.
  6414.      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  6415.      * @return {Object} Current instance of EventEmitter for chaining.
  6416.      */
  6417.     proto.addListener = function addListener(evt, listener) {
  6418.         var listeners = this.getListenersAsObject(evt);
  6419.         var listenerIsWrapped = typeof listener === 'object';
  6420.         var key;
  6421.  
  6422.         for (key in listeners) {
  6423.             if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
  6424.                 listeners[key].push(listenerIsWrapped ? listener : {
  6425.                     listener: listener,
  6426.                     once: false
  6427.                 });
  6428.             }
  6429.         }
  6430.  
  6431.         return this;
  6432.     };
  6433.  
  6434.     /**
  6435.      * Alias of addListener
  6436.      */
  6437.     proto.on = alias('addListener');
  6438.  
  6439.     /**
  6440.      * Semi-alias of addListener. It will add a listener that will be
  6441.      * automatically removed after its first execution.
  6442.      *
  6443.      * @param {String|RegExp} evt Name of the event to attach the listener to.
  6444.      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  6445.      * @return {Object} Current instance of EventEmitter for chaining.
  6446.      */
  6447.     proto.addOnceListener = function addOnceListener(evt, listener) {
  6448.         return this.addListener(evt, {
  6449.             listener: listener,
  6450.             once: true
  6451.         });
  6452.     };
  6453.  
  6454.     /**
  6455.      * Alias of addOnceListener.
  6456.      */
  6457.     proto.once = alias('addOnceListener');
  6458.  
  6459.     /**
  6460.      * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
  6461.      * You need to tell it what event names should be matched by a regex.
  6462.      *
  6463.      * @param {String} evt Name of the event to create.
  6464.      * @return {Object} Current instance of EventEmitter for chaining.
  6465.      */
  6466.     proto.defineEvent = function defineEvent(evt) {
  6467.         this.getListeners(evt);
  6468.         return this;
  6469.     };
  6470.  
  6471.     /**
  6472.      * Uses defineEvent to define multiple events.
  6473.      *
  6474.      * @param {String[]} evts An array of event names to define.
  6475.      * @return {Object} Current instance of EventEmitter for chaining.
  6476.      */
  6477.     proto.defineEvents = function defineEvents(evts) {
  6478.         for (var i = 0; i < evts.length; i += 1) {
  6479.             this.defineEvent(evts[i]);
  6480.         }
  6481.         return this;
  6482.     };
  6483.  
  6484.     /**
  6485.      * Removes a listener function from the specified event.
  6486.      * When passed a regular expression as the event name, it will remove the listener from all events that match it.
  6487.      *
  6488.      * @param {String|RegExp} evt Name of the event to remove the listener from.
  6489.      * @param {Function} listener Method to remove from the event.
  6490.      * @return {Object} Current instance of EventEmitter for chaining.
  6491.      */
  6492.     proto.removeListener = function removeListener(evt, listener) {
  6493.         var listeners = this.getListenersAsObject(evt);
  6494.         var index;
  6495.         var key;
  6496.  
  6497.         for (key in listeners) {
  6498.             if (listeners.hasOwnProperty(key)) {
  6499.                 index = indexOfListener(listeners[key], listener);
  6500.  
  6501.                 if (index !== -1) {
  6502.                     listeners[key].splice(index, 1);
  6503.                 }
  6504.             }
  6505.         }
  6506.  
  6507.         return this;
  6508.     };
  6509.  
  6510.     /**
  6511.      * Alias of removeListener
  6512.      */
  6513.     proto.off = alias('removeListener');
  6514.  
  6515.     /**
  6516.      * Adds listeners in bulk using the manipulateListeners method.
  6517.      * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
  6518.      * You can also pass it a regular expression to add the array of listeners to all events that match it.
  6519.      * Yeah, this function does quite a bit. That's probably a bad thing.
  6520.      *
  6521.      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
  6522.      * @param {Function[]} [listeners] An optional array of listener functions to add.
  6523.      * @return {Object} Current instance of EventEmitter for chaining.
  6524.      */
  6525.     proto.addListeners = function addListeners(evt, listeners) {
  6526.         // Pass through to manipulateListeners
  6527.         return this.manipulateListeners(false, evt, listeners);
  6528.     };
  6529.  
  6530.     /**
  6531.      * Removes listeners in bulk using the manipulateListeners method.
  6532.      * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
  6533.      * You can also pass it an event name and an array of listeners to be removed.
  6534.      * You can also pass it a regular expression to remove the listeners from all events that match it.
  6535.      *
  6536.      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
  6537.      * @param {Function[]} [listeners] An optional array of listener functions to remove.
  6538.      * @return {Object} Current instance of EventEmitter for chaining.
  6539.      */
  6540.     proto.removeListeners = function removeListeners(evt, listeners) {
  6541.         // Pass through to manipulateListeners
  6542.         return this.manipulateListeners(true, evt, listeners);
  6543.     };
  6544.  
  6545.     /**
  6546.      * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
  6547.      * The first argument will determine if the listeners are removed (true) or added (false).
  6548.      * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
  6549.      * You can also pass it an event name and an array of listeners to be added/removed.
  6550.      * You can also pass it a regular expression to manipulate the listeners of all events that match it.
  6551.      *
  6552.      * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
  6553.      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
  6554.      * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
  6555.      * @return {Object} Current instance of EventEmitter for chaining.
  6556.      */
  6557.     proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
  6558.         var i;
  6559.         var value;
  6560.         var single = remove ? this.removeListener : this.addListener;
  6561.         var multiple = remove ? this.removeListeners : this.addListeners;
  6562.  
  6563.         // If evt is an object then pass each of its properties to this method
  6564.         if (typeof evt === 'object' && !(evt instanceof RegExp)) {
  6565.             for (i in evt) {
  6566.                 if (evt.hasOwnProperty(i) && (value = evt[i])) {
  6567.                     // Pass the single listener straight through to the singular method
  6568.                     if (typeof value === 'function') {
  6569.                         single.call(this, i, value);
  6570.                     }
  6571.                     else {
  6572.                         // Otherwise pass back to the multiple function
  6573.                         multiple.call(this, i, value);
  6574.                     }
  6575.                 }
  6576.             }
  6577.         }
  6578.         else {
  6579.             // So evt must be a string
  6580.             // And listeners must be an array of listeners
  6581.             // Loop over it and pass each one to the multiple method
  6582.             i = listeners.length;
  6583.             while (i--) {
  6584.                 single.call(this, evt, listeners[i]);
  6585.             }
  6586.         }
  6587.  
  6588.         return this;
  6589.     };
  6590.  
  6591.     /**
  6592.      * Removes all listeners from a specified event.
  6593.      * If you do not specify an event then all listeners will be removed.
  6594.      * That means every event will be emptied.
  6595.      * You can also pass a regex to remove all events that match it.
  6596.      *
  6597.      * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
  6598.      * @return {Object} Current instance of EventEmitter for chaining.
  6599.      */
  6600.     proto.removeEvent = function removeEvent(evt) {
  6601.         var type = typeof evt;
  6602.         var events = this._getEvents();
  6603.         var key;
  6604.  
  6605.         // Remove different things depending on the state of evt
  6606.         if (type === 'string') {
  6607.             // Remove all listeners for the specified event
  6608.             delete events[evt];
  6609.         }
  6610.         else if (evt instanceof RegExp) {
  6611.             // Remove all events matching the regex.
  6612.             for (key in events) {
  6613.                 if (events.hasOwnProperty(key) && evt.test(key)) {
  6614.                     delete events[key];
  6615.                 }
  6616.             }
  6617.         }
  6618.         else {
  6619.             // Remove all listeners in all events
  6620.             delete this._events;
  6621.         }
  6622.  
  6623.         return this;
  6624.     };
  6625.  
  6626.     /**
  6627.      * Alias of removeEvent.
  6628.      *
  6629.      * Added to mirror the node API.
  6630.      */
  6631.     proto.removeAllListeners = alias('removeEvent');
  6632.  
  6633.     /**
  6634.      * Emits an event of your choice.
  6635.      * When emitted, every listener attached to that event will be executed.
  6636.      * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
  6637.      * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
  6638.      * So they will not arrive within the array on the other side, they will be separate.
  6639.      * You can also pass a regular expression to emit to all events that match it.
  6640.      *
  6641.      * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  6642.      * @param {Array} [args] Optional array of arguments to be passed to each listener.
  6643.      * @return {Object} Current instance of EventEmitter for chaining.
  6644.      */
  6645.     proto.emitEvent = function emitEvent(evt, args) {
  6646.         var listeners = this.getListenersAsObject(evt);
  6647.         var listener;
  6648.         var i;
  6649.         var key;
  6650.         var response;
  6651.  
  6652.         for (key in listeners) {
  6653.             if (listeners.hasOwnProperty(key)) {
  6654.                 i = listeners[key].length;
  6655.  
  6656.                 while (i--) {
  6657.                     // If the listener returns true then it shall be removed from the event
  6658.                     // The function is executed either with a basic call or an apply if there is an args array
  6659.                     listener = listeners[key][i];
  6660.  
  6661.                     if (listener.once === true) {
  6662.                         this.removeListener(evt, listener.listener);
  6663.                     }
  6664.  
  6665.                     response = listener.listener.apply(this, args || []);
  6666.  
  6667.                     if (response === this._getOnceReturnValue()) {
  6668.                         this.removeListener(evt, listener.listener);
  6669.                     }
  6670.                 }
  6671.             }
  6672.         }
  6673.  
  6674.         return this;
  6675.     };
  6676.  
  6677.     /**
  6678.      * Alias of emitEvent
  6679.      */
  6680.     proto.trigger = alias('emitEvent');
  6681.  
  6682.     /**
  6683.      * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
  6684.      * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
  6685.      *
  6686.      * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  6687.      * @param {...*} Optional additional arguments to be passed to each listener.
  6688.      * @return {Object} Current instance of EventEmitter for chaining.
  6689.      */
  6690.     proto.emit = function emit(evt) {
  6691.         var args = Array.prototype.slice.call(arguments, 1);
  6692.         return this.emitEvent(evt, args);
  6693.     };
  6694.  
  6695.     /**
  6696.      * Sets the current value to check against when executing listeners. If a
  6697.      * listeners return value matches the one set here then it will be removed
  6698.      * after execution. This value defaults to true.
  6699.      *
  6700.      * @param {*} value The new value to check for when executing listeners.
  6701.      * @return {Object} Current instance of EventEmitter for chaining.
  6702.      */
  6703.     proto.setOnceReturnValue = function setOnceReturnValue(value) {
  6704.         this._onceReturnValue = value;
  6705.         return this;
  6706.     };
  6707.  
  6708.     /**
  6709.      * Fetches the current value to check against when executing listeners. If
  6710.      * the listeners return value matches this one then it should be removed
  6711.      * automatically. It will return true by default.
  6712.      *
  6713.      * @return {*|Boolean} The current value to check for or the default, true.
  6714.      * @api private
  6715.      */
  6716.     proto._getOnceReturnValue = function _getOnceReturnValue() {
  6717.         if (this.hasOwnProperty('_onceReturnValue')) {
  6718.             return this._onceReturnValue;
  6719.         }
  6720.         else {
  6721.             return true;
  6722.         }
  6723.     };
  6724.  
  6725.     /**
  6726.      * Fetches the events object and creates one if required.
  6727.      *
  6728.      * @return {Object} The events storage object.
  6729.      * @api private
  6730.      */
  6731.     proto._getEvents = function _getEvents() {
  6732.         return this._events || (this._events = {});
  6733.     };
  6734.  
  6735.     /**
  6736.      * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
  6737.      *
  6738.      * @return {Function} Non conflicting EventEmitter class.
  6739.      */
  6740.     EventEmitter.noConflict = function noConflict() {
  6741.         exports.EventEmitter = originalGlobalValue;
  6742.         return EventEmitter;
  6743.     };
  6744.  
  6745.     // Expose the class either via AMD, CommonJS or the global object
  6746.     if (typeof define === 'function' && define.amd) {
  6747.         define(function () {
  6748.             return EventEmitter;
  6749.         });
  6750.     }
  6751.     else if (typeof module === 'object' && module.exports){
  6752.         module.exports = EventEmitter;
  6753.     }
  6754.     else {
  6755.         exports.EventEmitter = EventEmitter;
  6756.     }
  6757. }.call(this));
  6758.  
  6759. },{}]},{},[1]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement