text: /*!
   * Material Design for Bootstrap 4
   * Version: MDB Admin Dashboard 4.8.2
   *
   *
   * Copyright: Material Design for Bootstrap
   * https://mdbootstrap.com/
   *
   * Read the license: https://mdbootstrap.com/license/
   *
   *
   * Documentation: https://mdbootstrap.com/
   *
   * Getting started: https://mdbootstrap.com/getting-started/
   *
   * Tutorials: https://mdbootstrap.com/bootstrap-tutorial/
   *
   * Templates: https://mdbootstrap.com/templates/
   *
   * Support: https://mdbootstrap.com/forums/forum/support/
   *
   * Contact: office@mdbootstrap.com
   *
   * Attribution: Animate CSS, Twitter Bootstrap, Materialize CSS, Normalize CSS, Waves JS, WOW JS, Toastr, Chart.js
   *
   */
  
  
  /*
  
  jquery.easing.js
  velocity.min.js
  chart.js
  wow.js
  scrolling-navbar.js
  waves.js
  forms-free.js
  cards.js
  smooth-scroll.js
  toastr.js
  dropdown.js
  buttons.js
  sidenav.js
  collapsible.js
  jquery.easypiechart.js
  file-input.js
  material-select.js
  picker.js
  picker-date.js
  picker-time.js
  lightbox.js
  jquery.sticky.js
  scrollbar.js
  chips.js
  jarallax.js
  jarallax-video.js
  mdb-autocomplete.js
  treeview.js
  
  
  */
  
  /*
   * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
   *
   * Uses the built in easing capabilities added In jQuery 1.1
   * to offer multiple easing options
   *
   * TERMS OF USE - jQuery Easing
   *
   * Open source under the BSD License.
   *
   * Copyright © 2008 George McGinley Smith
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted provided that the following conditions are met:
   *
   * Redistributions of source code must retain the above copyright notice, this list of
   * conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list
   * of conditions and the following disclaimer in the documentation and/or other materials
   * provided with the distribution.
   *
   * Neither the name of the author nor the names of contributors may be used to endorse
   * or promote products derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   *
  */
  
  // t: current time, b: begInnIng value, c: change In value, d: duration
  jQuery.easing['jswing'] = jQuery.easing['swing'];
  
  jQuery.extend( jQuery.easing,
  {
      def: 'easeOutQuad',
      swing: function (x, t, b, c, d) {
          //alert(jQuery.easing.default);
          return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
      },
      easeInQuad: function (x, t, b, c, d) {
          return c*(t/=d)*t + b;
      },
      easeOutQuad: function (x, t, b, c, d) {
          return -c *(t/=d)*(t-2) + b;
      },
      easeInOutQuad: function (x, t, b, c, d) {
          if ((t/=d/2) < 1) return c/2*t*t + b;
          return -c/2 * ((--t)*(t-2) - 1) + b;
      },
      easeInCubic: function (x, t, b, c, d) {
          return c*(t/=d)*t*t + b;
      },
      easeOutCubic: function (x, t, b, c, d) {
          return c*((t=t/d-1)*t*t + 1) + b;
      },
      easeInOutCubic: function (x, t, b, c, d) {
          if ((t/=d/2) < 1) return c/2*t*t*t + b;
          return c/2*((t-=2)*t*t + 2) + b;
      },
      easeInQuart: function (x, t, b, c, d) {
          return c*(t/=d)*t*t*t + b;
      },
      easeOutQuart: function (x, t, b, c, d) {
          return -c * ((t=t/d-1)*t*t*t - 1) + b;
      },
      easeInOutQuart: function (x, t, b, c, d) {
          if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
          return -c/2 * ((t-=2)*t*t*t - 2) + b;
      },
      easeInQuint: function (x, t, b, c, d) {
          return c*(t/=d)*t*t*t*t + b;
      },
      easeOutQuint: function (x, t, b, c, d) {
          return c*((t=t/d-1)*t*t*t*t + 1) + b;
      },
      easeInOutQuint: function (x, t, b, c, d) {
          if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
          return c/2*((t-=2)*t*t*t*t + 2) + b;
      },
      easeInSine: function (x, t, b, c, d) {
          return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
      },
      easeOutSine: function (x, t, b, c, d) {
          return c * Math.sin(t/d * (Math.PI/2)) + b;
      },
      easeInOutSine: function (x, t, b, c, d) {
          return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
      },
      easeInExpo: function (x, t, b, c, d) {
          return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
      },
      easeOutExpo: function (x, t, b, c, d) {
          return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
      },
      easeInOutExpo: function (x, t, b, c, d) {
          if (t==0) return b;
          if (t==d) return b+c;
          if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
          return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
      },
      easeInCirc: function (x, t, b, c, d) {
          return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
      },
      easeOutCirc: function (x, t, b, c, d) {
          return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
      },
      easeInOutCirc: function (x, t, b, c, d) {
          if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
          return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
      },
      easeInElastic: function (x, t, b, c, d) {
          var s=1.70158;var p=0;var a=c;
          if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
          if (a < Math.abs(c)) { a=c; var s=p/4; }
          else var s = p/(2*Math.PI) * Math.asin (c/a);
          return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
      },
      easeOutElastic: function (x, t, b, c, d) {
          var s=1.70158;var p=0;var a=c;
          if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
          if (a < Math.abs(c)) { a=c; var s=p/4; }
          else var s = p/(2*Math.PI) * Math.asin (c/a);
          return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
      },
      easeInOutElastic: function (x, t, b, c, d) {
          var s=1.70158;var p=0;var a=c;
          if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
          if (a < Math.abs(c)) { a=c; var s=p/4; }
          else var s = p/(2*Math.PI) * Math.asin (c/a);
          if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
          return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
      },
      easeInBack: function (x, t, b, c, d, s) {
          if (s == undefined) s = 1.70158;
          return c*(t/=d)*t*((s+1)*t - s) + b;
      },
      easeOutBack: function (x, t, b, c, d, s) {
          if (s == undefined) s = 1.70158;
          return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
      },
      easeInOutBack: function (x, t, b, c, d, s) {
          if (s == undefined) s = 1.70158;
          if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
          return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
      },
      easeInBounce: function (x, t, b, c, d) {
          return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
      },
      easeOutBounce: function (x, t, b, c, d) {
          if ((t/=d) < (1/2.75)) {
              return c*(7.5625*t*t) + b;
          } else if (t < (2/2.75)) {
              return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
          } else if (t < (2.5/2.75)) {
              return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
          } else {
              return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
          }
      },
      easeInOutBounce: function (x, t, b, c, d) {
          if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
          return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
      }
  });
  
  /*
   *
   * TERMS OF USE - EASING EQUATIONS
   *
   * Open source under the BSD License.
   *
   * Copyright © 2001 Robert Penner
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted provided that the following conditions are met:
   *
   * Redistributions of source code must retain the above copyright notice, this list of
   * conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list
   * of conditions and the following disclaimer in the documentation and/or other materials
   * provided with the distribution.
   *
   * Neither the name of the author nor the names of contributors may be used to endorse
   * or promote products derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   */
  /*! VelocityJS.org (1.2.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */
  /*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */
  /*! Note that this has been modified by Materialize to confirm that Velocity is not already being imported. */
  jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(e){function t(e){var t=e.length,a=r.type(e);return"function"===a||r.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===a||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;l<s.length;l++)n["[object "+s[l]+"]"]=s[l].toLowerCase();r.fn.init.prototype=r.fn,e.Velocity={Utilities:r}}}(window),function(e){"object"==typeof module&&"object"==typeof module.exports?module.exports=e():"function"==typeof define&&define.amd?define(e):e()}(function(){return function(e,t,r,a){function n(e){for(var t=-1,r=e?e.length:0,a=[];++t<r;){var n=e[t];n&&a.push(n)}return a}function o(e){return m.isWrapped(e)?e=[].slice.call(e):m.isNode(e)&&(e=[e]),e}function i(e){var t=f.data(e,"velocity");return null===t?a:t}function s(e){return function(t){return Math.round(t*e)*(1/e)}}function l(e,r,a,n){function o(e,t){return 1-3*t+3*e}function i(e,t){return 3*t-6*e}function s(e){return 3*e}function l(e,t,r){return((o(t,r)*e+i(t,r))*e+s(t))*e}function u(e,t,r){return 3*o(t,r)*e*e+2*i(t,r)*e+s(t)}function c(t,r){for(var n=0;m>n;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s<v);return i}function d(t){for(var r=0,n=1,o=b-1;n!=o&&w[n]<=t;++n)r+=x;--n;var i=(t-w[n])/(w[n+1]-w[n]),s=r+i*x,l=u(s,e,a);return l>=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="<!--[if IE "+e+"]><span></span><![endif]-->",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e<S.Lists.colors.length;e++){var t="color"===S.Lists.colors[e]?"0 0 0 1":"255 255 255 1";S.Hooks.templates[S.Lists.colors[e]]=["Red Green Blue Alpha",t]}var r,a,n;if(d)for(r in S.Hooks.templates){a=S.Hooks.templates[r],n=a[0].split(" ");var o=a[1].match(S.RegEx.valueSplit);"Color"===n[0]&&(n.push(n.shift()),o.push(o.shift()),S.Hooks.templates[r]=[n.join(" "),o.join(" ")])}for(r in S.Hooks.templates){a=S.Hooks.templates[r],n=a[0].split(" ");for(var e in n){var i=r+n[e],s=e;S.Hooks.registered[i]=[r,s]}}},getRoot:function(e){var t=S.Hooks.registered[e];return t?t[0]:e},cleanRootPropertyValue:function(e,t){return S.RegEx.valueUnwrap.test(t)&&(t=t.match(S.RegEx.valueUnwrap)[1]),S.Values.isCSSNullValue(t)&&(t=S.Hooks.templates[e][1]),t},extractValue:function(e,t){var r=S.Hooks.registered[e];if(r){var a=r[0],n=r[1];return t=S.Hooks.cleanRootPropertyValue(a,t),t.toString().match(S.RegEx.valueSplit)[n]}return t},injectValue:function(e,t,r){var a=S.Hooks.registered[e];if(a){var n,o,i=a[0],s=a[1];return r=S.Hooks.cleanRootPropertyValue(i,r),n=r.toString().match(S.RegEx.valueSplit),n[s]=t,o=n.join(" ")}return r}},Normalizations:{registered:{clip:function(e,t,r){switch(e){case"name":return"clip";case"extract":var a;return S.RegEx.wrappedValueAlreadyExtracted.test(r)?a=r:(a=r.toString().match(S.RegEx.valueUnwrap),a=a?a[1].replace(/,(\s+)?/g," "):r),a;case"inject":return"rect("+r+")"}},blur:function(e,t,r){switch(e){case"name":return b.State.isFirefox?"filter":"-webkit-filter";case"extract":var a=parseFloat(r);if(!a&&0!==a){var n=r.toString().match(/blur\(([0-9]+[A-z]+)\)/i);a=n?n[1]:0}return a;case"inject":return parseFloat(r)?"blur("+r+")":"none"}},opacity:function(e,t,r){if(8>=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;e<S.Lists.transformsBase.length;e++)!function(){var t=S.Lists.transformsBase[e];S.Normalizations.registered[t]=function(e,r,n){switch(e){case"name":return"transform";case"extract":return i(r)===a||i(r).transformCache[t]===a?/^scale/i.test(t)?1:0:i(r).transformCache[t].replace(/[()]/g,"");case"inject":var o=!1;switch(t.substr(0,t.length-1)){case"translate":o=!/(%|px|em|rem|vw|vh|\d)$/i.test(n);break;case"scal":case"scale":b.State.isAndroid&&i(r).transformCache[t]===a&&1>n&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e<S.Lists.colors.length;e++)!function(){var t=S.Lists.colors[e];S.Normalizations.registered[t]=function(e,r,n){switch(e){case"name":return t;case"extract":var o;if(S.RegEx.wrappedValueAlreadyExtracted.test(n))o=n;else{var i,s={black:"rgb(0, 0, 0)",blue:"rgb(0, 0, 255)",gray:"rgb(128, 128, 128)",green:"rgb(0, 128, 0)",red:"rgb(255, 0, 0)",white:"rgb(255, 255, 255)"};/^[A-z]+$/i.test(n)?i=s[n]!==a?s[n]:s.black:S.RegEx.isHex.test(n)?i="rgb("+S.Values.hexToRgb(n).join(" ")+")":/^rgba?\(/i.test(n)||(i=s.black),o=(i||n).toString().match(S.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g," ")}return 8>=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;c<s.length;c++){var f=[l[c]];o&&f.push(o),u!==a&&f.push(u[c]),y[e+s[c]]=f}delete y[e]}}});for(var z in y){var O=p(y[z]),q=O[0],$=O[1],M=O[2];z=S.Names.camelCase(z);var I=S.Hooks.getRoot(z),B=!1;if(i(o).isSVG||"tween"===I||S.Names.prefixCheck(I)[1]!==!1||S.Normalizations.registered[I]!==a){(s.display!==a&&null!==s.display&&"none"!==s.display||s.visibility!==a&&"hidden"!==s.visibility)&&/opacity|filter/.test(z)&&!M&&0!==q&&(M=0),s._cacheValues&&E&&E[z]?(M===a&&(M=E[z].endValue+E[z].unitType),B=i(o).rootPropertyValueCache[I]):S.Hooks.registered[z]?M===a?(B=S.getPropertyValue(o,I),M=S.getPropertyValue(o,z,B)):B=S.Hooks.templates[I][1]:M===a&&(M=S.getPropertyValue(o,z));var W,G,Y,D=!1;if(W=d(z,M),M=W[0],Y=W[1],W=d(z,q),q=W[0].replace(/^([+-\/*])=/,function(e,t){return D=t,""}),G=W[1],M=parseFloat(M)||0,q=parseFloat(q)||0,"%"===G&&(/^(fontSize|lineHeight)$/.test(z)?(q/=100,G="em"):/^scale/.test(z)?(q/=100,G=""):/(Red|Green|Blue)$/i.test(z)&&(q=q/100*255,G="")),/[\/*]/.test(D))G=Y;else if(Y!==G&&0!==M)if(0===q)G=Y;else{n=n||h();var Q=/margin|padding|left|right|width|text|word|letter/i.test(z)||/X$/.test(z)||"x"===z?"x":"y";switch(Y){case"%":M*="x"===Q?n.percentToPxWidth:n.percentToPxHeight;break;case"px":break;default:M*=n[Y+"ToPx"]}switch(G){case"%":M*=1/("x"===Q?n.percentToPxWidth:n.percentToPxHeight);break;case"px":break;default:M*=1/n[G+"ToPx"]}}switch(D){case"+":q=M+q;break;case"-":q=M-q;break;case"*":q=M*q;break;case"/":q=M/q}l[z]={rootPropertyValue:B,startValue:M,currentValue:M,endValue:q,unitType:G,easing:$},b.debug&&console.log("tweensContainer ("+z+"): "+JSON.stringify(l[z]),o)}else b.debug&&console.log("Skipping ["+I+"] due to a lack of browser support.")}l.element=o}l.element&&(S.Values.addClass(o,"velocity-animating"),R.push(l),""===s.queue&&(i(o).tweensContainer=l,i(o).opts=s),i(o).isAnimating=!0,V===w-1?(b.State.calls.push([R,g,s,null,k.resolver]),b.State.isTicking===!1&&(b.State.isTicking=!0,c())):V++)}var n,o=this,s=f.extend({},b.defaults,v),l={};switch(i(o)===a&&b.init(o),parseFloat(s.delay)&&s.queue!==!1&&f.queue(o,s.queue,function(e){b.velocityQueueEntryFlag=!0,i(o).delayTimer={setTimeout:setTimeout(e,parseFloat(s.delay)),next:e}}),s.duration.toString().toLowerCase()){case"fast":s.duration=200;break;case"normal":s.duration=h;break;case"slow":s.duration=600;break;default:s.duration=parseFloat(s.duration)||1}b.mock!==!1&&(b.mock===!0?s.duration=s.delay=1:(s.duration*=parseFloat(b.mock)||1,s.delay*=parseFloat(b.mock)||1)),s.easing=u(s.easing,s.duration),s.begin&&!m.isFunction(s.begin)&&(s.begin=null),s.progress&&!m.isFunction(s.progress)&&(s.progress=null),s.complete&&!m.isFunction(s.complete)&&(s.complete=null),s.display!==a&&null!==s.display&&(s.display=s.display.toString().toLowerCase(),"auto"===s.display&&(s.display=b.CSS.Values.getDisplayType(o))),s.visibility!==a&&null!==s.visibility&&(s.visibility=s.visibility.toString().toLowerCase()),s.mobileHA=s.mobileHA&&b.State.isMobile&&!b.State.isGingerbread,s.queue===!1?s.delay?setTimeout(e,s.delay):e():f.queue(o,s.queue,function(t,r){return r===!0?(k.promise&&k.resolver(g),!0):(b.velocityQueueEntryFlag=!0,void e(t))}),""!==s.queue&&"fx"!==s.queue||"inprogress"===f.queue(o)[0]||f.dequeue(o)}var s,l,d,g,y,v,x=arguments[0]&&(arguments[0].p||f.isPlainObject(arguments[0].properties)&&!arguments[0].properties.names||m.isString(arguments[0].properties));if(m.isWrapped(this)?(s=!1,d=0,g=this,l=this):(s=!0,d=1,g=x?arguments[0].elements||arguments[0].e:arguments[0]),g=o(g)){x?(y=arguments[0].properties||arguments[0].p,v=arguments[0].options||arguments[0].o):(y=arguments[d],v=arguments[d+1]);var w=g.length,V=0;if(!/^(stop|finish)$/i.test(y)&&!f.isPlainObject(v)){var C=d+1;v={};for(var T=C;T<arguments.length;T++)m.isArray(arguments[T])||!/^(fast|normal|slow)$/i.test(arguments[T])&&!/^\d/.test(arguments[T])?m.isString(arguments[T])||m.isArray(arguments[T])?v.easing=arguments[T]:m.isFunction(arguments[T])&&(v.complete=arguments[T]):v.duration=arguments[T]}var k={promise:null,resolver:null,rejecter:null};s&&b.Promise&&(k.promise=new b.Promise(function(e,t){k.resolver=e,k.rejecter=t}));var A;switch(y){case"scroll":A="scroll";break;case"reverse":A="reverse";break;case"finish":case"stop":f.each(g,function(e,t){i(t)&&i(t).delayTimer&&(clearTimeout(i(t).delayTimer.setTimeout),i(t).delayTimer.next&&i(t).delayTimer.next(),delete i(t).delayTimer)});var F=[];return f.each(b.State.calls,function(e,t){t&&f.each(t[1],function(r,n){var o=v===a?"":v;return o===!0||t[2].queue===o||v===a&&t[2].queue===!1?void f.each(g,function(r,a){a===n&&((v===!0||m.isString(v))&&(f.each(f.queue(a,m.isString(v)?v:""),function(e,t){
  m.isFunction(t)&&t(null,!0)}),f.queue(a,m.isString(v)?v:"",[])),"stop"===y?(i(a)&&i(a).tweensContainer&&o!==!1&&f.each(i(a).tweensContainer,function(e,t){t.endValue=t.currentValue}),F.push(e)):"finish"===y&&(t[2].duration=1))}):!0})}),"stop"===y&&(f.each(F,function(e,t){p(t,!0)}),k.promise&&k.resolver(g)),e();default:if(!f.isPlainObject(y)||m.isEmptyObject(y)){if(m.isString(y)&&b.Redirects[y]){var j=f.extend({},v),E=j.duration,H=j.delay||0;return j.backwards===!0&&(g=f.extend(!0,[],g).reverse()),f.each(g,function(e,t){parseFloat(j.stagger)?j.delay=H+parseFloat(j.stagger)*e:m.isFunction(j.stagger)&&(j.delay=H+j.stagger.call(t,e,w)),j.drag&&(j.duration=parseFloat(E)||(/^(callout|transition)/.test(y)?1e3:h),j.duration=Math.max(j.duration*(j.backwards?1-e/w:(e+1)/w),.75*j.duration,200)),b.Redirects[y].call(t,t,j||{},e,w,g,k.promise?k:a)}),e()}var N="Velocity: First argument ("+y+") was not a property map, a known action, or a registered redirect. Aborting.";return k.promise?k.rejecter(new Error(N)):console.log(N),e()}A="start"}var L={lastParent:null,lastPosition:null,lastFontSize:null,lastPercentToPxWidth:null,lastPercentToPxHeight:null,lastEmToPx:null,remToPx:null,vwToPx:null,vhToPx:null},R=[];f.each(g,function(e,t){m.isNode(t)&&n.call(t)});var z,j=f.extend({},b.defaults,v);if(j.loop=parseInt(j.loop),z=2*j.loop-1,j.loop)for(var O=0;z>O;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)}));
  
  /*!
   * Chart.js
   * http://chartjs.org/
   * Version: 2.7.3
   *
   * Copyright 2018 Chart.js Contributors
   * Released under the MIT license
   * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
   */
  (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
  
  },{}],2:[function(require,module,exports){
  /* MIT license */
  var colorNames = require(6);
  
  module.exports = {
     getRgba: getRgba,
     getHsla: getHsla,
     getRgb: getRgb,
     getHsl: getHsl,
     getHwb: getHwb,
     getAlpha: getAlpha,
  
     hexString: hexString,
     rgbString: rgbString,
     rgbaString: rgbaString,
     percentString: percentString,
     percentaString: percentaString,
     hslString: hslString,
     hslaString: hslaString,
     hwbString: hwbString,
     keyword: keyword
  }
  
  function getRgba(string) {
     if (!string) {
        return;
     }
     var abbr =  /^#([a-fA-F0-9]{3})$/i,
         hex =  /^#([a-fA-F0-9]{6})$/i,
         rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
         per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
         keyword = /(\w+)/;
  
     var rgb = [0, 0, 0],
         a = 1,
         match = string.match(abbr);
     if (match) {
        match = match[1];
        for (var i = 0; i < rgb.length; i++) {
           rgb[i] = parseInt(match[i] + match[i], 16);
        }
     }
     else if (match = string.match(hex)) {
        match = match[1];
        for (var i = 0; i < rgb.length; i++) {
           rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
        }
     }
     else if (match = string.match(rgba)) {
        for (var i = 0; i < rgb.length; i++) {
           rgb[i] = parseInt(match[i + 1]);
        }
        a = parseFloat(match[4]);
     }
     else if (match = string.match(per)) {
        for (var i = 0; i < rgb.length; i++) {
           rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
        }
        a = parseFloat(match[4]);
     }
     else if (match = string.match(keyword)) {
        if (match[1] == "transparent") {
           return [0, 0, 0, 0];
        }
        rgb = colorNames[match[1]];
        if (!rgb) {
           return;
        }
     }
  
     for (var i = 0; i < rgb.length; i++) {
        rgb[i] = scale(rgb[i], 0, 255);
     }
     if (!a && a != 0) {
        a = 1;
     }
     else {
        a = scale(a, 0, 1);
     }
     rgb[3] = a;
     return rgb;
  }
  
  function getHsla(string) {
     if (!string) {
        return;
     }
     var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
     var match = string.match(hsl);
     if (match) {
        var alpha = parseFloat(match[4]);
        var h = scale(parseInt(match[1]), 0, 360),
            s = scale(parseFloat(match[2]), 0, 100),
            l = scale(parseFloat(match[3]), 0, 100),
            a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
        return [h, s, l, a];
     }
  }
  
  function getHwb(string) {
     if (!string) {
        return;
     }
     var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
     var match = string.match(hwb);
     if (match) {
      var alpha = parseFloat(match[4]);
        var h = scale(parseInt(match[1]), 0, 360),
            w = scale(parseFloat(match[2]), 0, 100),
            b = scale(parseFloat(match[3]), 0, 100),
            a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
        return [h, w, b, a];
     }
  }
  
  function getRgb(string) {
     var rgba = getRgba(string);
     return rgba && rgba.slice(0, 3);
  }
  
  function getHsl(string) {
    var hsla = getHsla(string);
    return hsla && hsla.slice(0, 3);
  }
  
  function getAlpha(string) {
     var vals = getRgba(string);
     if (vals) {
        return vals[3];
     }
     else if (vals = getHsla(string)) {
        return vals[3];
     }
     else if (vals = getHwb(string)) {
        return vals[3];
     }
  }
  
  // generators
  function hexString(rgb) {
     return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
                + hexDouble(rgb[2]);
  }
  
  function rgbString(rgba, alpha) {
     if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
        return rgbaString(rgba, alpha);
     }
     return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
  }
  
  function rgbaString(rgba, alpha) {
     if (alpha === undefined) {
        alpha = (rgba[3] !== undefined ? rgba[3] : 1);
     }
     return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
             + ", " + alpha + ")";
  }
  
  function percentString(rgba, alpha) {
     if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
        return percentaString(rgba, alpha);
     }
     var r = Math.round(rgba[0]/255 * 100),
         g = Math.round(rgba[1]/255 * 100),
         b = Math.round(rgba[2]/255 * 100);
  
     return "rgb(" + r + "%, " + g + "%, " + b + "%)";
  }
  
  function percentaString(rgba, alpha) {
     var r = Math.round(rgba[0]/255 * 100),
         g = Math.round(rgba[1]/255 * 100),
         b = Math.round(rgba[2]/255 * 100);
     return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
  }
  
  function hslString(hsla, alpha) {
     if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
        return hslaString(hsla, alpha);
     }
     return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
  }
  
  function hslaString(hsla, alpha) {
     if (alpha === undefined) {
        alpha = (hsla[3] !== undefined ? hsla[3] : 1);
     }
     return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
             + alpha + ")";
  }
  
  // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
  // (hwb have alpha optional & 1 is default value)
  function hwbString(hwb, alpha) {
     if (alpha === undefined) {
        alpha = (hwb[3] !== undefined ? hwb[3] : 1);
     }
     return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
             + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
  }
  
  function keyword(rgb) {
    return reverseNames[rgb.slice(0, 3)];
  }
  
  // helpers
  function scale(num, min, max) {
     return Math.min(Math.max(min, num), max);
  }
  
  function hexDouble(num) {
    var str = num.toString(16).toUpperCase();
    return (str.length < 2) ? "0" + str : str;
  }
  
  
  //create a list of reverse color names
  var reverseNames = {};
  for (var name in colorNames) {
     reverseNames[colorNames[name]] = name;
  }
  
  },{"6":6}],3:[function(require,module,exports){
  /* MIT license */
  var convert = require(5);
  var string = require(2);
  
  var Color = function (obj) {
  	if (obj instanceof Color) {
  		return obj;
  	}
  	if (!(this instanceof Color)) {
  		return new Color(obj);
  	}
  
  	this.valid = false;
  	this.values = {
  		rgb: [0, 0, 0],
  		hsl: [0, 0, 0],
  		hsv: [0, 0, 0],
  		hwb: [0, 0, 0],
  		cmyk: [0, 0, 0, 0],
  		alpha: 1
  	};
  
  	// parse Color() argument
  	var vals;
  	if (typeof obj === 'string') {
  		vals = string.getRgba(obj);
  		if (vals) {
  			this.setValues('rgb', vals);
  		} else if (vals = string.getHsla(obj)) {
  			this.setValues('hsl', vals);
  		} else if (vals = string.getHwb(obj)) {
  			this.setValues('hwb', vals);
  		}
  	} else if (typeof obj === 'object') {
  		vals = obj;
  		if (vals.r !== undefined || vals.red !== undefined) {
  			this.setValues('rgb', vals);
  		} else if (vals.l !== undefined || vals.lightness !== undefined) {
  			this.setValues('hsl', vals);
  		} else if (vals.v !== undefined || vals.value !== undefined) {
  			this.setValues('hsv', vals);
  		} else if (vals.w !== undefined || vals.whiteness !== undefined) {
  			this.setValues('hwb', vals);
  		} else if (vals.c !== undefined || vals.cyan !== undefined) {
  			this.setValues('cmyk', vals);
  		}
  	}
  };
  
  Color.prototype = {
  	isValid: function () {
  		return this.valid;
  	},
  	rgb: function () {
  		return this.setSpace('rgb', arguments);
  	},
  	hsl: function () {
  		return this.setSpace('hsl', arguments);
  	},
  	hsv: function () {
  		return this.setSpace('hsv', arguments);
  	},
  	hwb: function () {
  		return this.setSpace('hwb', arguments);
  	},
  	cmyk: function () {
  		return this.setSpace('cmyk', arguments);
  	},
  
  	rgbArray: function () {
  		return this.values.rgb;
  	},
  	hslArray: function () {
  		return this.values.hsl;
  	},
  	hsvArray: function () {
  		return this.values.hsv;
  	},
  	hwbArray: function () {
  		var values = this.values;
  		if (values.alpha !== 1) {
  			return values.hwb.concat([values.alpha]);
  		}
  		return values.hwb;
  	},
  	cmykArray: function () {
  		return this.values.cmyk;
  	},
  	rgbaArray: function () {
  		var values = this.values;
  		return values.rgb.concat([values.alpha]);
  	},
  	hslaArray: function () {
  		var values = this.values;
  		return values.hsl.concat([values.alpha]);
  	},
  	alpha: function (val) {
  		if (val === undefined) {
  			return this.values.alpha;
  		}
  		this.setValues('alpha', val);
  		return this;
  	},
  
  	red: function (val) {
  		return this.setChannel('rgb', 0, val);
  	},
  	green: function (val) {
  		return this.setChannel('rgb', 1, val);
  	},
  	blue: function (val) {
  		return this.setChannel('rgb', 2, val);
  	},
  	hue: function (val) {
  		if (val) {
  			val %= 360;
  			val = val < 0 ? 360 + val : val;
  		}
  		return this.setChannel('hsl', 0, val);
  	},
  	saturation: function (val) {
  		return this.setChannel('hsl', 1, val);
  	},
  	lightness: function (val) {
  		return this.setChannel('hsl', 2, val);
  	},
  	saturationv: function (val) {
  		return this.setChannel('hsv', 1, val);
  	},
  	whiteness: function (val) {
  		return this.setChannel('hwb', 1, val);
  	},
  	blackness: function (val) {
  		return this.setChannel('hwb', 2, val);
  	},
  	value: function (val) {
  		return this.setChannel('hsv', 2, val);
  	},
  	cyan: function (val) {
  		return this.setChannel('cmyk', 0, val);
  	},
  	magenta: function (val) {
  		return this.setChannel('cmyk', 1, val);
  	},
  	yellow: function (val) {
  		return this.setChannel('cmyk', 2, val);
  	},
  	black: function (val) {
  		return this.setChannel('cmyk', 3, val);
  	},
  
  	hexString: function () {
  		return string.hexString(this.values.rgb);
  	},
  	rgbString: function () {
  		return string.rgbString(this.values.rgb, this.values.alpha);
  	},
  	rgbaString: function () {
  		return string.rgbaString(this.values.rgb, this.values.alpha);
  	},
  	percentString: function () {
  		return string.percentString(this.values.rgb, this.values.alpha);
  	},
  	hslString: function () {
  		return string.hslString(this.values.hsl, this.values.alpha);
  	},
  	hslaString: function () {
  		return string.hslaString(this.values.hsl, this.values.alpha);
  	},
  	hwbString: function () {
  		return string.hwbString(this.values.hwb, this.values.alpha);
  	},
  	keyword: function () {
  		return string.keyword(this.values.rgb, this.values.alpha);
  	},
  
  	rgbNumber: function () {
  		var rgb = this.values.rgb;
  		return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
  	},
  
  	luminosity: function () {
  		// http://www.w3.org/TR/WCAG20/#relativeluminancedef
  		var rgb = this.values.rgb;
  		var lum = [];
  		for (var i = 0; i < rgb.length; i++) {
  			var chan = rgb[i] / 255;
  			lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
  		}
  		return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
  	},
  
  	contrast: function (color2) {
  		// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
  		var lum1 = this.luminosity();
  		var lum2 = color2.luminosity();
  		if (lum1 > lum2) {
  			return (lum1 + 0.05) / (lum2 + 0.05);
  		}
  		return (lum2 + 0.05) / (lum1 + 0.05);
  	},
  
  	level: function (color2) {
  		var contrastRatio = this.contrast(color2);
  		if (contrastRatio >= 7.1) {
  			return 'AAA';
  		}
  
  		return (contrastRatio >= 4.5) ? 'AA' : '';
  	},
  
  	dark: function () {
  		// YIQ equation from http://24ways.org/2010/calculating-color-contrast
  		var rgb = this.values.rgb;
  		var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
  		return yiq < 128;
  	},
  
  	light: function () {
  		return !this.dark();
  	},
  
  	negate: function () {
  		var rgb = [];
  		for (var i = 0; i < 3; i++) {
  			rgb[i] = 255 - this.values.rgb[i];
  		}
  		this.setValues('rgb', rgb);
  		return this;
  	},
  
  	lighten: function (ratio) {
  		var hsl = this.values.hsl;
  		hsl[2] += hsl[2] * ratio;
  		this.setValues('hsl', hsl);
  		return this;
  	},
  
  	darken: function (ratio) {
  		var hsl = this.values.hsl;
  		hsl[2] -= hsl[2] * ratio;
  		this.setValues('hsl', hsl);
  		return this;
  	},
  
  	saturate: function (ratio) {
  		var hsl = this.values.hsl;
  		hsl[1] += hsl[1] * ratio;
  		this.setValues('hsl', hsl);
  		return this;
  	},
  
  	desaturate: function (ratio) {
  		var hsl = this.values.hsl;
  		hsl[1] -= hsl[1] * ratio;
  		this.setValues('hsl', hsl);
  		return this;
  	},
  
  	whiten: function (ratio) {
  		var hwb = this.values.hwb;
  		hwb[1] += hwb[1] * ratio;
  		this.setValues('hwb', hwb);
  		return this;
  	},
  
  	blacken: function (ratio) {
  		var hwb = this.values.hwb;
  		hwb[2] += hwb[2] * ratio;
  		this.setValues('hwb', hwb);
  		return this;
  	},
  
  	greyscale: function () {
  		var rgb = this.values.rgb;
  		// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
  		var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
  		this.setValues('rgb', [val, val, val]);
  		return this;
  	},
  
  	clearer: function (ratio) {
  		var alpha = this.values.alpha;
  		this.setValues('alpha', alpha - (alpha * ratio));
  		return this;
  	},
  
  	opaquer: function (ratio) {
  		var alpha = this.values.alpha;
  		this.setValues('alpha', alpha + (alpha * ratio));
  		return this;
  	},
  
  	rotate: function (degrees) {
  		var hsl = this.values.hsl;
  		var hue = (hsl[0] + degrees) % 360;
  		hsl[0] = hue < 0 ? 360 + hue : hue;
  		this.setValues('hsl', hsl);
  		return this;
  	},
  
  	/**
  	 * Ported from sass implementation in C
  	 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
  	 */
  	mix: function (mixinColor, weight) {
  		var color1 = this;
  		var color2 = mixinColor;
  		var p = weight === undefined ? 0.5 : weight;
  
  		var w = 2 * p - 1;
  		var a = color1.alpha() - color2.alpha();
  
  		var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
  		var w2 = 1 - w1;
  
  		return this
  			.rgb(
  				w1 * color1.red() + w2 * color2.red(),
  				w1 * color1.green() + w2 * color2.green(),
  				w1 * color1.blue() + w2 * color2.blue()
  			)
  			.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
  	},
  
  	toJSON: function () {
  		return this.rgb();
  	},
  
  	clone: function () {
  		// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
  		// making the final build way to big to embed in Chart.js. So let's do it manually,
  		// assuming that values to clone are 1 dimension arrays containing only numbers,
  		// except 'alpha' which is a number.
  		var result = new Color();
  		var source = this.values;
  		var target = result.values;
  		var value, type;
  
  		for (var prop in source) {
  			if (source.hasOwnProperty(prop)) {
  				value = source[prop];
  				type = ({}).toString.call(value);
  				if (type === '[object Array]') {
  					target[prop] = value.slice(0);
  				} else if (type === '[object Number]') {
  					target[prop] = value;
  				} else {
  					console.error('unexpected color value:', value);
  				}
  			}
  		}
  
  		return result;
  	}
  };
  
  Color.prototype.spaces = {
  	rgb: ['red', 'green', 'blue'],
  	hsl: ['hue', 'saturation', 'lightness'],
  	hsv: ['hue', 'saturation', 'value'],
  	hwb: ['hue', 'whiteness', 'blackness'],
  	cmyk: ['cyan', 'magenta', 'yellow', 'black']
  };
  
  Color.prototype.maxes = {
  	rgb: [255, 255, 255],
  	hsl: [360, 100, 100],
  	hsv: [360, 100, 100],
  	hwb: [360, 100, 100],
  	cmyk: [100, 100, 100, 100]
  };
  
  Color.prototype.getValues = function (space) {
  	var values = this.values;
  	var vals = {};
  
  	for (var i = 0; i < space.length; i++) {
  		vals[space.charAt(i)] = values[space][i];
  	}
  
  	if (values.alpha !== 1) {
  		vals.a = values.alpha;
  	}
  
  	// {r: 255, g: 255, b: 255, a: 0.4}
  	return vals;
  };
  
  Color.prototype.setValues = function (space, vals) {
  	var values = this.values;
  	var spaces = this.spaces;
  	var maxes = this.maxes;
  	var alpha = 1;
  	var i;
  
  	this.valid = true;
  
  	if (space === 'alpha') {
  		alpha = vals;
  	} else if (vals.length) {
  		// [10, 10, 10]
  		values[space] = vals.slice(0, space.length);
  		alpha = vals[space.length];
  	} else if (vals[space.charAt(0)] !== undefined) {
  		// {r: 10, g: 10, b: 10}
  		for (i = 0; i < space.length; i++) {
  			values[space][i] = vals[space.charAt(i)];
  		}
  
  		alpha = vals.a;
  	} else if (vals[spaces[space][0]] !== undefined) {
  		// {red: 10, green: 10, blue: 10}
  		var chans = spaces[space];
  
  		for (i = 0; i < space.length; i++) {
  			values[space][i] = vals[chans[i]];
  		}
  
  		alpha = vals.alpha;
  	}
  
  	values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
  
  	if (space === 'alpha') {
  		return false;
  	}
  
  	var capped;
  
  	// cap values of the space prior converting all values
  	for (i = 0; i < space.length; i++) {
  		capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
  		values[space][i] = Math.round(capped);
  	}
  
  	// convert to all the other color spaces
  	for (var sname in spaces) {
  		if (sname !== space) {
  			values[sname] = convert[space][sname](values[space]);
  		}
  	}
  
  	return true;
  };
  
  Color.prototype.setSpace = function (space, args) {
  	var vals = args[0];
  
  	if (vals === undefined) {
  		// color.rgb()
  		return this.getValues(space);
  	}
  
  	// color.rgb(10, 10, 10)
  	if (typeof vals === 'number') {
  		vals = Array.prototype.slice.call(args);
  	}
  
  	this.setValues(space, vals);
  	return this;
  };
  
  Color.prototype.setChannel = function (space, index, val) {
  	var svalues = this.values[space];
  	if (val === undefined) {
  		// color.red()
  		return svalues[index];
  	} else if (val === svalues[index]) {
  		// color.red(color.red())
  		return this;
  	}
  
  	// color.red(100)
  	svalues[index] = val;
  	this.setValues(space, svalues);
  
  	return this;
  };
  
  if (typeof window !== 'undefined') {
  	window.Color = Color;
  }
  
  module.exports = Color;
  
  },{"2":2,"5":5}],4:[function(require,module,exports){
  /* MIT license */
  
  module.exports = {
    rgb2hsl: rgb2hsl,
    rgb2hsv: rgb2hsv,
    rgb2hwb: rgb2hwb,
    rgb2cmyk: rgb2cmyk,
    rgb2keyword: rgb2keyword,
    rgb2xyz: rgb2xyz,
    rgb2lab: rgb2lab,
    rgb2lch: rgb2lch,
  
    hsl2rgb: hsl2rgb,
    hsl2hsv: hsl2hsv,
    hsl2hwb: hsl2hwb,
    hsl2cmyk: hsl2cmyk,
    hsl2keyword: hsl2keyword,
  
    hsv2rgb: hsv2rgb,
    hsv2hsl: hsv2hsl,
    hsv2hwb: hsv2hwb,
    hsv2cmyk: hsv2cmyk,
    hsv2keyword: hsv2keyword,
  
    hwb2rgb: hwb2rgb,
    hwb2hsl: hwb2hsl,
    hwb2hsv: hwb2hsv,
    hwb2cmyk: hwb2cmyk,
    hwb2keyword: hwb2keyword,
  
    cmyk2rgb: cmyk2rgb,
    cmyk2hsl: cmyk2hsl,
    cmyk2hsv: cmyk2hsv,
    cmyk2hwb: cmyk2hwb,
    cmyk2keyword: cmyk2keyword,
  
    keyword2rgb: keyword2rgb,
    keyword2hsl: keyword2hsl,
    keyword2hsv: keyword2hsv,
    keyword2hwb: keyword2hwb,
    keyword2cmyk: keyword2cmyk,
    keyword2lab: keyword2lab,
    keyword2xyz: keyword2xyz,
  
    xyz2rgb: xyz2rgb,
    xyz2lab: xyz2lab,
    xyz2lch: xyz2lch,
  
    lab2xyz: lab2xyz,
    lab2rgb: lab2rgb,
    lab2lch: lab2lch,
  
    lch2lab: lch2lab,
    lch2xyz: lch2xyz,
    lch2rgb: lch2rgb
  }
  
  
  function rgb2hsl(rgb) {
    var r = rgb[0]/255,
        g = rgb[1]/255,
        b = rgb[2]/255,
        min = Math.min(r, g, b),
        max = Math.max(r, g, b),
        delta = max - min,
        h, s, l;
  
    if (max == min)
      h = 0;
    else if (r == max)
      h = (g - b) / delta;
    else if (g == max)
      h = 2 + (b - r) / delta;
    else if (b == max)
      h = 4 + (r - g)/ delta;
  
    h = Math.min(h * 60, 360);
  
    if (h < 0)
      h += 360;
  
    l = (min + max) / 2;
  
    if (max == min)
      s = 0;
    else if (l <= 0.5)
      s = delta / (max + min);
    else
      s = delta / (2 - max - min);
  
    return [h, s * 100, l * 100];
  }
  
  function rgb2hsv(rgb) {
    var r = rgb[0],
        g = rgb[1],
        b = rgb[2],
        min = Math.min(r, g, b),
        max = Math.max(r, g, b),
        delta = max - min,
        h, s, v;
  
    if (max == 0)
      s = 0;
    else
      s = (delta/max * 1000)/10;
  
    if (max == min)
      h = 0;
    else if (r == max)
      h = (g - b) / delta;
    else if (g == max)
      h = 2 + (b - r) / delta;
    else if (b == max)
      h = 4 + (r - g) / delta;
  
    h = Math.min(h * 60, 360);
  
    if (h < 0)
      h += 360;
  
    v = ((max / 255) * 1000) / 10;
  
    return [h, s, v];
  }
  
  function rgb2hwb(rgb) {
    var r = rgb[0],
        g = rgb[1],
        b = rgb[2],
        h = rgb2hsl(rgb)[0],
        w = 1/255 * Math.min(r, Math.min(g, b)),
        b = 1 - 1/255 * Math.max(r, Math.max(g, b));
  
    return [h, w * 100, b * 100];
  }
  
  function rgb2cmyk(rgb) {
    var r = rgb[0] / 255,
        g = rgb[1] / 255,
        b = rgb[2] / 255,
        c, m, y, k;
  
    k = Math.min(1 - r, 1 - g, 1 - b);
    c = (1 - r - k) / (1 - k) || 0;
    m = (1 - g - k) / (1 - k) || 0;
    y = (1 - b - k) / (1 - k) || 0;
    return [c * 100, m * 100, y * 100, k * 100];
  }
  
  function rgb2keyword(rgb) {
    return reverseKeywords[JSON.stringify(rgb)];
  }
  
  function rgb2xyz(rgb) {
    var r = rgb[0] / 255,
        g = rgb[1] / 255,
        b = rgb[2] / 255;
  
    // assume sRGB
    r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
    g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
    b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
  
    var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
    var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
    var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
  
    return [x * 100, y *100, z * 100];
  }
  
  function rgb2lab(rgb) {
    var xyz = rgb2xyz(rgb),
          x = xyz[0],
          y = xyz[1],
          z = xyz[2],
          l, a, b;
  
    x /= 95.047;
    y /= 100;
    z /= 108.883;
  
    x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
    y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
    z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
  
    l = (116 * y) - 16;
    a = 500 * (x - y);
    b = 200 * (y - z);
  
    return [l, a, b];
  }
  
  function rgb2lch(args) {
    return lab2lch(rgb2lab(args));
  }
  
  function hsl2rgb(hsl) {
    var h = hsl[0] / 360,
        s = hsl[1] / 100,
        l = hsl[2] / 100,
        t1, t2, t3, rgb, val;
  
    if (s == 0) {
      val = l * 255;
      return [val, val, val];
    }
  
    if (l < 0.5)
      t2 = l * (1 + s);
    else
      t2 = l + s - l * s;
    t1 = 2 * l - t2;
  
    rgb = [0, 0, 0];
    for (var i = 0; i < 3; i++) {
      t3 = h + 1 / 3 * - (i - 1);
      t3 < 0 && t3++;
      t3 > 1 && t3--;
  
      if (6 * t3 < 1)
        val = t1 + (t2 - t1) * 6 * t3;
      else if (2 * t3 < 1)
        val = t2;
      else if (3 * t3 < 2)
        val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
      else
        val = t1;
  
      rgb[i] = val * 255;
    }
  
    return rgb;
  }
  
  function hsl2hsv(hsl) {
    var h = hsl[0],
        s = hsl[1] / 100,
        l = hsl[2] / 100,
        sv, v;
  
    if(l === 0) {
        // no need to do calc on black
        // also avoids divide by 0 error
        return [0, 0, 0];
    }
  
    l *= 2;
    s *= (l <= 1) ? l : 2 - l;
    v = (l + s) / 2;
    sv = (2 * s) / (l + s);
    return [h, sv * 100, v * 100];
  }
  
  function hsl2hwb(args) {
    return rgb2hwb(hsl2rgb(args));
  }
  
  function hsl2cmyk(args) {
    return rgb2cmyk(hsl2rgb(args));
  }
  
  function hsl2keyword(args) {
    return rgb2keyword(hsl2rgb(args));
  }
  
  
  function hsv2rgb(hsv) {
    var h = hsv[0] / 60,
        s = hsv[1] / 100,
        v = hsv[2] / 100,
        hi = Math.floor(h) % 6;
  
    var f = h - Math.floor(h),
        p = 255 * v * (1 - s),
        q = 255 * v * (1 - (s * f)),
        t = 255 * v * (1 - (s * (1 - f))),
        v = 255 * v;
  
    switch(hi) {
      case 0:
        return [v, t, p];
      case 1:
        return [q, v, p];
      case 2:
        return [p, v, t];
      case 3:
        return [p, q, v];
      case 4:
        return [t, p, v];
      case 5:
        return [v, p, q];
    }
  }
  
  function hsv2hsl(hsv) {
    var h = hsv[0],
        s = hsv[1] / 100,
        v = hsv[2] / 100,
        sl, l;
  
    l = (2 - s) * v;
    sl = s * v;
    sl /= (l <= 1) ? l : 2 - l;
    sl = sl || 0;
    l /= 2;
    return [h, sl * 100, l * 100];
  }
  
  function hsv2hwb(args) {
    return rgb2hwb(hsv2rgb(args))
  }
  
  function hsv2cmyk(args) {
    return rgb2cmyk(hsv2rgb(args));
  }
  
  function hsv2keyword(args) {
    return rgb2keyword(hsv2rgb(args));
  }
  
  // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
  function hwb2rgb(hwb) {
    var h = hwb[0] / 360,
        wh = hwb[1] / 100,
        bl = hwb[2] / 100,
        ratio = wh + bl,
        i, v, f, n;
  
    // wh + bl cant be > 1
    if (ratio > 1) {
      wh /= ratio;
      bl /= ratio;
    }
  
    i = Math.floor(6 * h);
    v = 1 - bl;
    f = 6 * h - i;
    if ((i & 0x01) != 0) {
      f = 1 - f;
    }
    n = wh + f * (v - wh);  // linear interpolation
  
    switch (i) {
      default:
      case 6:
      case 0: r = v; g = n; b = wh; break;
      case 1: r = n; g = v; b = wh; break;
      case 2: r = wh; g = v; b = n; break;
      case 3: r = wh; g = n; b = v; break;
      case 4: r = n; g = wh; b = v; break;
      case 5: r = v; g = wh; b = n; break;
    }
  
    return [r * 255, g * 255, b * 255];
  }
  
  function hwb2hsl(args) {
    return rgb2hsl(hwb2rgb(args));
  }
  
  function hwb2hsv(args) {
    return rgb2hsv(hwb2rgb(args));
  }
  
  function hwb2cmyk(args) {
    return rgb2cmyk(hwb2rgb(args));
  }
  
  function hwb2keyword(args) {
    return rgb2keyword(hwb2rgb(args));
  }
  
  function cmyk2rgb(cmyk) {
    var c = cmyk[0] / 100,
        m = cmyk[1] / 100,
        y = cmyk[2] / 100,
        k = cmyk[3] / 100,
        r, g, b;
  
    r = 1 - Math.min(1, c * (1 - k) + k);
    g = 1 - Math.min(1, m * (1 - k) + k);
    b = 1 - Math.min(1, y * (1 - k) + k);
    return [r * 255, g * 255, b * 255];
  }
  
  function cmyk2hsl(args) {
    return rgb2hsl(cmyk2rgb(args));
  }
  
  function cmyk2hsv(args) {
    return rgb2hsv(cmyk2rgb(args));
  }
  
  function cmyk2hwb(args) {
    return rgb2hwb(cmyk2rgb(args));
  }
  
  function cmyk2keyword(args) {
    return rgb2keyword(cmyk2rgb(args));
  }
  
  
  function xyz2rgb(xyz) {
    var x = xyz[0] / 100,
        y = xyz[1] / 100,
        z = xyz[2] / 100,
        r, g, b;
  
    r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
    g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
    b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
  
    // assume sRGB
    r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
      : r = (r * 12.92);
  
    g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
      : g = (g * 12.92);
  
    b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
      : b = (b * 12.92);
  
    r = Math.min(Math.max(0, r), 1);
    g = Math.min(Math.max(0, g), 1);
    b = Math.min(Math.max(0, b), 1);
  
    return [r * 255, g * 255, b * 255];
  }
  
  function xyz2lab(xyz) {
    var x = xyz[0],
        y = xyz[1],
        z = xyz[2],
        l, a, b;
  
    x /= 95.047;
    y /= 100;
    z /= 108.883;
  
    x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
    y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
    z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
  
    l = (116 * y) - 16;
    a = 500 * (x - y);
    b = 200 * (y - z);
  
    return [l, a, b];
  }
  
  function xyz2lch(args) {
    return lab2lch(xyz2lab(args));
  }
  
  function lab2xyz(lab) {
    var l = lab[0],
        a = lab[1],
        b = lab[2],
        x, y, z, y2;
  
    if (l <= 8) {
      y = (l * 100) / 903.3;
      y2 = (7.787 * (y / 100)) + (16 / 116);
    } else {
      y = 100 * Math.pow((l + 16) / 116, 3);
      y2 = Math.pow(y / 100, 1/3);
    }
  
    x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
  
    z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
  
    return [x, y, z];
  }
  
  function lab2lch(lab) {
    var l = lab[0],
        a = lab[1],
        b = lab[2],
        hr, h, c;
  
    hr = Math.atan2(b, a);
    h = hr * 360 / 2 / Math.PI;
    if (h < 0) {
      h += 360;
    }
    c = Math.sqrt(a * a + b * b);
    return [l, c, h];
  }
  
  function lab2rgb(args) {
    return xyz2rgb(lab2xyz(args));
  }
  
  function lch2lab(lch) {
    var l = lch[0],
        c = lch[1],
        h = lch[2],
        a, b, hr;
  
    hr = h / 360 * 2 * Math.PI;
    a = c * Math.cos(hr);
    b = c * Math.sin(hr);
    return [l, a, b];
  }
  
  function lch2xyz(args) {
    return lab2xyz(lch2lab(args));
  }
  
  function lch2rgb(args) {
    return lab2rgb(lch2lab(args));
  }
  
  function keyword2rgb(keyword) {
    return cssKeywords[keyword];
  }
  
  function keyword2hsl(args) {
    return rgb2hsl(keyword2rgb(args));
  }
  
  function keyword2hsv(args) {
    return rgb2hsv(keyword2rgb(args));
  }
  
  function keyword2hwb(args) {
    return rgb2hwb(keyword2rgb(args));
  }
  
  function keyword2cmyk(args) {
    return rgb2cmyk(keyword2rgb(args));
  }
  
  function keyword2lab(args) {
    return rgb2lab(keyword2rgb(args));
  }
  
  function keyword2xyz(args) {
    return rgb2xyz(keyword2rgb(args));
  }
  
  var cssKeywords = {
    aliceblue:  [240,248,255],
    antiquewhite: [250,235,215],
    aqua: [0,255,255],
    aquamarine: [127,255,212],
    azure:  [240,255,255],
    beige:  [245,245,220],
    bisque: [255,228,196],
    black:  [0,0,0],
    blanchedalmond: [255,235,205],
    blue: [0,0,255],
    blueviolet: [138,43,226],
    brown:  [165,42,42],
    burlywood:  [222,184,135],
    cadetblue:  [95,158,160],
    chartreuse: [127,255,0],
    chocolate:  [210,105,30],
    coral:  [255,127,80],
    cornflowerblue: [100,149,237],
    cornsilk: [255,248,220],
    crimson:  [220,20,60],
    cyan: [0,255,255],
    darkblue: [0,0,139],
    darkcyan: [0,139,139],
    darkgoldenrod:  [184,134,11],
    darkgray: [169,169,169],
    darkgreen:  [0,100,0],
    darkgrey: [169,169,169],
    darkkhaki:  [189,183,107],
    darkmagenta:  [139,0,139],
    darkolivegreen: [85,107,47],
    darkorange: [255,140,0],
    darkorchid: [153,50,204],
    darkred:  [139,0,0],
    darksalmon: [233,150,122],
    darkseagreen: [143,188,143],
    darkslateblue:  [72,61,139],
    darkslategray:  [47,79,79],
    darkslategrey:  [47,79,79],
    darkturquoise:  [0,206,209],
    darkviolet: [148,0,211],
    deeppink: [255,20,147],
    deepskyblue:  [0,191,255],
    dimgray:  [105,105,105],
    dimgrey:  [105,105,105],
    dodgerblue: [30,144,255],
    firebrick:  [178,34,34],
    floralwhite:  [255,250,240],
    forestgreen:  [34,139,34],
    fuchsia:  [255,0,255],
    gainsboro:  [220,220,220],
    ghostwhite: [248,248,255],
    gold: [255,215,0],
    goldenrod:  [218,165,32],
    gray: [128,128,128],
    green:  [0,128,0],
    greenyellow:  [173,255,47],
    grey: [128,128,128],
    honeydew: [240,255,240],
    hotpink:  [255,105,180],
    indianred:  [205,92,92],
    indigo: [75,0,130],
    ivory:  [255,255,240],
    khaki:  [240,230,140],
    lavender: [230,230,250],
    lavenderblush:  [255,240,245],
    lawngreen:  [124,252,0],
    lemonchiffon: [255,250,205],
    lightblue:  [173,216,230],
    lightcoral: [240,128,128],
    lightcyan:  [224,255,255],
    lightgoldenrodyellow: [250,250,210],
    lightgray:  [211,211,211],
    lightgreen: [144,238,144],
    lightgrey:  [211,211,211],
    lightpink:  [255,182,193],
    lightsalmon:  [255,160,122],
    lightseagreen:  [32,178,170],
    lightskyblue: [135,206,250],
    lightslategray: [119,136,153],
    lightslategrey: [119,136,153],
    lightsteelblue: [176,196,222],
    lightyellow:  [255,255,224],
    lime: [0,255,0],
    limegreen:  [50,205,50],
    linen:  [250,240,230],
    magenta:  [255,0,255],
    maroon: [128,0,0],
    mediumaquamarine: [102,205,170],
    mediumblue: [0,0,205],
    mediumorchid: [186,85,211],
    mediumpurple: [147,112,219],
    mediumseagreen: [60,179,113],
    mediumslateblue:  [123,104,238],
    mediumspringgreen:  [0,250,154],
    mediumturquoise:  [72,209,204],
    mediumvioletred:  [199,21,133],
    midnightblue: [25,25,112],
    mintcream:  [245,255,250],
    mistyrose:  [255,228,225],
    moccasin: [255,228,181],
    navajowhite:  [255,222,173],
    navy: [0,0,128],
    oldlace:  [253,245,230],
    olive:  [128,128,0],
    olivedrab:  [107,142,35],
    orange: [255,165,0],
    orangered:  [255,69,0],
    orchid: [218,112,214],
    palegoldenrod:  [238,232,170],
    palegreen:  [152,251,152],
    paleturquoise:  [175,238,238],
    palevioletred:  [219,112,147],
    papayawhip: [255,239,213],
    peachpuff:  [255,218,185],
    peru: [205,133,63],
    pink: [255,192,203],
    plum: [221,160,221],
    powderblue: [176,224,230],
    purple: [128,0,128],
    rebeccapurple: [102, 51, 153],
    red:  [255,0,0],
    rosybrown:  [188,143,143],
    royalblue:  [65,105,225],
    saddlebrown:  [139,69,19],
    salmon: [250,128,114],
    sandybrown: [244,164,96],
    seagreen: [46,139,87],
    seashell: [255,245,238],
    sienna: [160,82,45],
    silver: [192,192,192],
    skyblue:  [135,206,235],
    slateblue:  [106,90,205],
    slategray:  [112,128,144],
    slategrey:  [112,128,144],
    snow: [255,250,250],
    springgreen:  [0,255,127],
    steelblue:  [70,130,180],
    tan:  [210,180,140],
    teal: [0,128,128],
    thistle:  [216,191,216],
    tomato: [255,99,71],
    turquoise:  [64,224,208],
    violet: [238,130,238],
    wheat:  [245,222,179],
    white:  [255,255,255],
    whitesmoke: [245,245,245],
    yellow: [255,255,0],
    yellowgreen:  [154,205,50]
  };
  
  var reverseKeywords = {};
  for (var key in cssKeywords) {
    reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
  }
  
  },{}],5:[function(require,module,exports){
  var conversions = require(4);
  
  var convert = function() {
     return new Converter();
  }
  
  for (var func in conversions) {
    // export Raw versions
    convert[func + "Raw"] =  (function(func) {
      // accept array or plain args
      return function(arg) {
        if (typeof arg == "number")
          arg = Array.prototype.slice.call(arguments);
        return conversions[func](arg);
      }
    })(func);
  
    var pair = /(\w+)2(\w+)/.exec(func),
        from = pair[1],
        to = pair[2];
  
    // export rgb2hsl and ["rgb"]["hsl"]
    convert[from] = convert[from] || {};
  
    convert[from][to] = convert[func] = (function(func) {
      return function(arg) {
        if (typeof arg == "number")
          arg = Array.prototype.slice.call(arguments);
  
        var val = conversions[func](arg);
        if (typeof val == "string" || val === undefined)
          return val; // keyword
  
        for (var i = 0; i < val.length; i++)
          val[i] = Math.round(val[i]);
        return val;
      }
    })(func);
  }
  
  
  /* Converter does lazy conversion and caching */
  var Converter = function() {
     this.convs = {};
  };
  
  /* Either get the values for a space or
    set the values for a space, depending on args */
  Converter.prototype.routeSpace = function(space, args) {
     var values = args[0];
     if (values === undefined) {
        // color.rgb()
        return this.getValues(space);
     }
     // color.rgb(10, 10, 10)
     if (typeof values == "number") {
        values = Array.prototype.slice.call(args);
     }
  
     return this.setValues(space, values);
  };
  
  /* Set the values for a space, invalidating cache */
  Converter.prototype.setValues = function(space, values) {
     this.space = space;
     this.convs = {};
     this.convs[space] = values;
     return this;
  };
  
  /* Get the values for a space. If there's already
    a conversion for the space, fetch it, otherwise
    compute it */
  Converter.prototype.getValues = function(space) {
     var vals = this.convs[space];
     if (!vals) {
        var fspace = this.space,
            from = this.convs[fspace];
        vals = convert[fspace][space](from);
  
        this.convs[space] = vals;
     }
    return vals;
  };
  
  ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
     Converter.prototype[space] = function(vals) {
        return this.routeSpace(space, arguments);
     }
  });
  
  module.exports = convert;
  },{"4":4}],6:[function(require,module,exports){
  'use strict'
  
  module.exports = {
  	"aliceblue": [240, 248, 255],
  	"antiquewhite": [250, 235, 215],
  	"aqua": [0, 255, 255],
  	"aquamarine": [127, 255, 212],
  	"azure": [240, 255, 255],
  	"beige": [245, 245, 220],
  	"bisque": [255, 228, 196],
  	"black": [0, 0, 0],
  	"blanchedalmond": [255, 235, 205],
  	"blue": [0, 0, 255],
  	"blueviolet": [138, 43, 226],
  	"brown": [165, 42, 42],
  	"burlywood": [222, 184, 135],
  	"cadetblue": [95, 158, 160],
  	"chartreuse": [127, 255, 0],
  	"chocolate": [210, 105, 30],
  	"coral": [255, 127, 80],
  	"cornflowerblue": [100, 149, 237],
  	"cornsilk": [255, 248, 220],
  	"crimson": [220, 20, 60],
  	"cyan": [0, 255, 255],
  	"darkblue": [0, 0, 139],
  	"darkcyan": [0, 139, 139],
  	"darkgoldenrod": [184, 134, 11],
  	"darkgray": [169, 169, 169],
  	"darkgreen": [0, 100, 0],
  	"darkgrey": [169, 169, 169],
  	"darkkhaki": [189, 183, 107],
  	"darkmagenta": [139, 0, 139],
  	"darkolivegreen": [85, 107, 47],
  	"darkorange": [255, 140, 0],
  	"darkorchid": [153, 50, 204],
  	"darkred": [139, 0, 0],
  	"darksalmon": [233, 150, 122],
  	"darkseagreen": [143, 188, 143],
  	"darkslateblue": [72, 61, 139],
  	"darkslategray": [47, 79, 79],
  	"darkslategrey": [47, 79, 79],
  	"darkturquoise": [0, 206, 209],
  	"darkviolet": [148, 0, 211],
  	"deeppink": [255, 20, 147],
  	"deepskyblue": [0, 191, 255],
  	"dimgray": [105, 105, 105],
  	"dimgrey": [105, 105, 105],
  	"dodgerblue": [30, 144, 255],
  	"firebrick": [178, 34, 34],
  	"floralwhite": [255, 250, 240],
  	"forestgreen": [34, 139, 34],
  	"fuchsia": [255, 0, 255],
  	"gainsboro": [220, 220, 220],
  	"ghostwhite": [248, 248, 255],
  	"gold": [255, 215, 0],
  	"goldenrod": [218, 165, 32],
  	"gray": [128, 128, 128],
  	"green": [0, 128, 0],
  	"greenyellow": [173, 255, 47],
  	"grey": [128, 128, 128],
  	"honeydew": [240, 255, 240],
  	"hotpink": [255, 105, 180],
  	"indianred": [205, 92, 92],
  	"indigo": [75, 0, 130],
  	"ivory": [255, 255, 240],
  	"khaki": [240, 230, 140],
  	"lavender": [230, 230, 250],
  	"lavenderblush": [255, 240, 245],
  	"lawngreen": [124, 252, 0],
  	"lemonchiffon": [255, 250, 205],
  	"lightblue": [173, 216, 230],
  	"lightcoral": [240, 128, 128],
  	"lightcyan": [224, 255, 255],
  	"lightgoldenrodyellow": [250, 250, 210],
  	"lightgray": [211, 211, 211],
  	"lightgreen": [144, 238, 144],
  	"lightgrey": [211, 211, 211],
  	"lightpink": [255, 182, 193],
  	"lightsalmon": [255, 160, 122],
  	"lightseagreen": [32, 178, 170],
  	"lightskyblue": [135, 206, 250],
  	"lightslategray": [119, 136, 153],
  	"lightslategrey": [119, 136, 153],
  	"lightsteelblue": [176, 196, 222],
  	"lightyellow": [255, 255, 224],
  	"lime": [0, 255, 0],
  	"limegreen": [50, 205, 50],
  	"linen": [250, 240, 230],
  	"magenta": [255, 0, 255],
  	"maroon": [128, 0, 0],
  	"mediumaquamarine": [102, 205, 170],
  	"mediumblue": [0, 0, 205],
  	"mediumorchid": [186, 85, 211],
  	"mediumpurple": [147, 112, 219],
  	"mediumseagreen": [60, 179, 113],
  	"mediumslateblue": [123, 104, 238],
  	"mediumspringgreen": [0, 250, 154],
  	"mediumturquoise": [72, 209, 204],
  	"mediumvioletred": [199, 21, 133],
  	"midnightblue": [25, 25, 112],
  	"mintcream": [245, 255, 250],
  	"mistyrose": [255, 228, 225],
  	"moccasin": [255, 228, 181],
  	"navajowhite": [255, 222, 173],
  	"navy": [0, 0, 128],
  	"oldlace": [253, 245, 230],
  	"olive": [128, 128, 0],
  	"olivedrab": [107, 142, 35],
  	"orange": [255, 165, 0],
  	"orangered": [255, 69, 0],
  	"orchid": [218, 112, 214],
  	"palegoldenrod": [238, 232, 170],
  	"palegreen": [152, 251, 152],
  	"paleturquoise": [175, 238, 238],
  	"palevioletred": [219, 112, 147],
  	"papayawhip": [255, 239, 213],
  	"peachpuff": [255, 218, 185],
  	"peru": [205, 133, 63],
  	"pink": [255, 192, 203],
  	"plum": [221, 160, 221],
  	"powderblue": [176, 224, 230],
  	"purple": [128, 0, 128],
  	"rebeccapurple": [102, 51, 153],
  	"red": [255, 0, 0],
  	"rosybrown": [188, 143, 143],
  	"royalblue": [65, 105, 225],
  	"saddlebrown": [139, 69, 19],
  	"salmon": [250, 128, 114],
  	"sandybrown": [244, 164, 96],
  	"seagreen": [46, 139, 87],
  	"seashell": [255, 245, 238],
  	"sienna": [160, 82, 45],
  	"silver": [192, 192, 192],
  	"skyblue": [135, 206, 235],
  	"slateblue": [106, 90, 205],
  	"slategray": [112, 128, 144],
  	"slategrey": [112, 128, 144],
  	"snow": [255, 250, 250],
  	"springgreen": [0, 255, 127],
  	"steelblue": [70, 130, 180],
  	"tan": [210, 180, 140],
  	"teal": [0, 128, 128],
  	"thistle": [216, 191, 216],
  	"tomato": [255, 99, 71],
  	"turquoise": [64, 224, 208],
  	"violet": [238, 130, 238],
  	"wheat": [245, 222, 179],
  	"white": [255, 255, 255],
  	"whitesmoke": [245, 245, 245],
  	"yellow": [255, 255, 0],
  	"yellowgreen": [154, 205, 50]
  };
  
  },{}],7:[function(require,module,exports){
  /**
   * @namespace Chart
   */
  var Chart = require(30)();
  
  Chart.helpers = require(46);
  
  // @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
  require(28)(Chart);
  
  Chart.Animation = require(22);
  Chart.animationService = require(23);
  Chart.defaults = require(26);
  Chart.Element = require(27);
  Chart.elements = require(41);
  Chart.Interaction = require(29);
  Chart.layouts = require(31);
  Chart.platform = require(49);
  Chart.plugins = require(32);
  Chart.Scale = require(33);
  Chart.scaleService = require(34);
  Chart.Ticks = require(35);
  Chart.Tooltip = require(36);
  
  require(24)(Chart);
  require(25)(Chart);
  
  require(56)(Chart);
  require(54)(Chart);
  require(55)(Chart);
  require(57)(Chart);
  require(58)(Chart);
  require(59)(Chart);
  
  // Controllers must be loaded after elements
  // See Chart.core.datasetController.dataElementType
  require(15)(Chart);
  require(16)(Chart);
  require(17)(Chart);
  require(18)(Chart);
  require(19)(Chart);
  require(20)(Chart);
  require(21)(Chart);
  
  require(8)(Chart);
  require(9)(Chart);
  require(10)(Chart);
  require(11)(Chart);
  require(12)(Chart);
  require(13)(Chart);
  require(14)(Chart);
  
  // Loading built-in plugins
  var plugins = require(50);
  for (var k in plugins) {
  	if (plugins.hasOwnProperty(k)) {
  		Chart.plugins.register(plugins[k]);
  	}
  }
  
  Chart.platform.initialize();
  
  module.exports = Chart;
  if (typeof window !== 'undefined') {
  	window.Chart = Chart;
  }
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, not available anymore
   * @namespace Chart.Legend
   * @deprecated since version 2.1.5
   * @todo remove at version 3
   * @private
   */
  Chart.Legend = plugins.legend._element;
  
  /**
   * Provided for backward compatibility, not available anymore
   * @namespace Chart.Title
   * @deprecated since version 2.1.5
   * @todo remove at version 3
   * @private
   */
  Chart.Title = plugins.title._element;
  
  /**
   * Provided for backward compatibility, use Chart.plugins instead
   * @namespace Chart.pluginService
   * @deprecated since version 2.1.5
   * @todo remove at version 3
   * @private
   */
  Chart.pluginService = Chart.plugins;
  
  /**
   * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
   * effect, instead simply create/register plugins via plain JavaScript objects.
   * @interface Chart.PluginBase
   * @deprecated since version 2.5.0
   * @todo remove at version 3
   * @private
   */
  Chart.PluginBase = Chart.Element.extend({});
  
  /**
   * Provided for backward compatibility, use Chart.helpers.canvas instead.
   * @namespace Chart.canvasHelpers
   * @deprecated since version 2.6.0
   * @todo remove at version 3
   * @private
   */
  Chart.canvasHelpers = Chart.helpers.canvas;
  
  /**
   * Provided for backward compatibility, use Chart.layouts instead.
   * @namespace Chart.layoutService
   * @deprecated since version 2.8.0
   * @todo remove at version 3
   * @private
   */
  Chart.layoutService = Chart.layouts;
  
  },{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"41":41,"46":46,"49":49,"50":50,"54":54,"55":55,"56":56,"57":57,"58":58,"59":59,"8":8,"9":9}],8:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.Bar = function(context, config) {
  		config.type = 'bar';
  
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],9:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.Bubble = function(context, config) {
  		config.type = 'bubble';
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],10:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.Doughnut = function(context, config) {
  		config.type = 'doughnut';
  
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],11:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.Line = function(context, config) {
  		config.type = 'line';
  
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],12:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.PolarArea = function(context, config) {
  		config.type = 'polarArea';
  
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],13:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  
  	Chart.Radar = function(context, config) {
  		config.type = 'radar';
  
  		return new Chart(context, config);
  	};
  
  };
  
  },{}],14:[function(require,module,exports){
  'use strict';
  
  module.exports = function(Chart) {
  	Chart.Scatter = function(context, config) {
  		config.type = 'scatter';
  		return new Chart(context, config);
  	};
  };
  
  },{}],15:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('bar', {
  	hover: {
  		mode: 'label'
  	},
  
  	scales: {
  		xAxes: [{
  			type: 'category',
  
  			// Specific to Bar Controller
  			categoryPercentage: 0.8,
  			barPercentage: 0.9,
  
  			// offset settings
  			offset: true,
  
  			// grid line settings
  			gridLines: {
  				offsetGridLines: true
  			}
  		}],
  
  		yAxes: [{
  			type: 'linear'
  		}]
  	}
  });
  
  defaults._set('horizontalBar', {
  	hover: {
  		mode: 'index',
  		axis: 'y'
  	},
  
  	scales: {
  		xAxes: [{
  			type: 'linear',
  			position: 'bottom'
  		}],
  
  		yAxes: [{
  			position: 'left',
  			type: 'category',
  
  			// Specific to Horizontal Bar Controller
  			categoryPercentage: 0.8,
  			barPercentage: 0.9,
  
  			// offset settings
  			offset: true,
  
  			// grid line settings
  			gridLines: {
  				offsetGridLines: true
  			}
  		}]
  	},
  
  	elements: {
  		rectangle: {
  			borderSkipped: 'left'
  		}
  	},
  
  	tooltips: {
  		callbacks: {
  			title: function(item, data) {
  				// Pick first xLabel for now
  				var title = '';
  
  				if (item.length > 0) {
  					if (item[0].yLabel) {
  						title = item[0].yLabel;
  					} else if (data.labels.length > 0 && item[0].index < data.labels.length) {
  						title = data.labels[item[0].index];
  					}
  				}
  
  				return title;
  			},
  
  			label: function(item, data) {
  				var datasetLabel = data.datasets[item.datasetIndex].label || '';
  				return datasetLabel + ': ' + item.xLabel;
  			}
  		},
  		mode: 'index',
  		axis: 'y'
  	}
  });
  
  /**
   * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
   * @private
   */
  function computeMinSampleSize(scale, pixels) {
  	var min = scale.isHorizontal() ? scale.width : scale.height;
  	var ticks = scale.getTicks();
  	var prev, curr, i, ilen;
  
  	for (i = 1, ilen = pixels.length; i < ilen; ++i) {
  		min = Math.min(min, pixels[i] - pixels[i - 1]);
  	}
  
  	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
  		curr = scale.getPixelForTick(i);
  		min = i > 0 ? Math.min(min, curr - prev) : min;
  		prev = curr;
  	}
  
  	return min;
  }
  
  /**
   * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
   * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
   * mode currently always generates bars equally sized (until we introduce scriptable options?).
   * @private
   */
  function computeFitCategoryTraits(index, ruler, options) {
  	var thickness = options.barThickness;
  	var count = ruler.stackCount;
  	var curr = ruler.pixels[index];
  	var size, ratio;
  
  	if (helpers.isNullOrUndef(thickness)) {
  		size = ruler.min * options.categoryPercentage;
  		ratio = options.barPercentage;
  	} else {
  		// When bar thickness is enforced, category and bar percentages are ignored.
  		// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
  		// and deprecate barPercentage since this value is ignored when thickness is absolute.
  		size = thickness * count;
  		ratio = 1;
  	}
  
  	return {
  		chunk: size / count,
  		ratio: ratio,
  		start: curr - (size / 2)
  	};
  }
  
  /**
   * Computes an "optimal" category that globally arranges bars side by side (no gap when
   * percentage options are 1), based on the previous and following categories. This mode
   * generates bars with different widths when data are not evenly spaced.
   * @private
   */
  function computeFlexCategoryTraits(index, ruler, options) {
  	var pixels = ruler.pixels;
  	var curr = pixels[index];
  	var prev = index > 0 ? pixels[index - 1] : null;
  	var next = index < pixels.length - 1 ? pixels[index + 1] : null;
  	var percent = options.categoryPercentage;
  	var start, size;
  
  	if (prev === null) {
  		// first data: its size is double based on the next point or,
  		// if it's also the last data, we use the scale end extremity.
  		prev = curr - (next === null ? ruler.end - curr : next - curr);
  	}
  
  	if (next === null) {
  		// last data: its size is also double based on the previous point.
  		next = curr + curr - prev;
  	}
  
  	start = curr - ((curr - prev) / 2) * percent;
  	size = ((next - prev) / 2) * percent;
  
  	return {
  		chunk: size / ruler.stackCount,
  		ratio: options.barPercentage,
  		start: start
  	};
  }
  
  module.exports = function(Chart) {
  
  	Chart.controllers.bar = Chart.DatasetController.extend({
  
  		dataElementType: elements.Rectangle,
  
  		initialize: function() {
  			var me = this;
  			var meta;
  
  			Chart.DatasetController.prototype.initialize.apply(me, arguments);
  
  			meta = me.getMeta();
  			meta.stack = me.getDataset().stack;
  			meta.bar = true;
  		},
  
  		update: function(reset) {
  			var me = this;
  			var rects = me.getMeta().data;
  			var i, ilen;
  
  			me._ruler = me.getRuler();
  
  			for (i = 0, ilen = rects.length; i < ilen; ++i) {
  				me.updateElement(rects[i], i, reset);
  			}
  		},
  
  		updateElement: function(rectangle, index, reset) {
  			var me = this;
  			var chart = me.chart;
  			var meta = me.getMeta();
  			var dataset = me.getDataset();
  			var custom = rectangle.custom || {};
  			var rectangleOptions = chart.options.elements.rectangle;
  
  			rectangle._xScale = me.getScaleForId(meta.xAxisID);
  			rectangle._yScale = me.getScaleForId(meta.yAxisID);
  			rectangle._datasetIndex = me.index;
  			rectangle._index = index;
  
  			rectangle._model = {
  				datasetLabel: dataset.label,
  				label: chart.data.labels[index],
  				borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
  				backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
  				borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
  				borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
  			};
  
  			me.updateElementGeometry(rectangle, index, reset);
  
  			rectangle.pivot();
  		},
  
  		/**
  		 * @private
  		 */
  		updateElementGeometry: function(rectangle, index, reset) {
  			var me = this;
  			var model = rectangle._model;
  			var vscale = me.getValueScale();
  			var base = vscale.getBasePixel();
  			var horizontal = vscale.isHorizontal();
  			var ruler = me._ruler || me.getRuler();
  			var vpixels = me.calculateBarValuePixels(me.index, index);
  			var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
  
  			model.horizontal = horizontal;
  			model.base = reset ? base : vpixels.base;
  			model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
  			model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
  			model.height = horizontal ? ipixels.size : undefined;
  			model.width = horizontal ? undefined : ipixels.size;
  		},
  
  		/**
  		 * @private
  		 */
  		getValueScaleId: function() {
  			return this.getMeta().yAxisID;
  		},
  
  		/**
  		 * @private
  		 */
  		getIndexScaleId: function() {
  			return this.getMeta().xAxisID;
  		},
  
  		/**
  		 * @private
  		 */
  		getValueScale: function() {
  			return this.getScaleForId(this.getValueScaleId());
  		},
  
  		/**
  		 * @private
  		 */
  		getIndexScale: function() {
  			return this.getScaleForId(this.getIndexScaleId());
  		},
  
  		/**
  		 * Returns the stacks based on groups and bar visibility.
  		 * @param {Number} [last] - The dataset index
  		 * @returns {Array} The stack list
  		 * @private
  		 */
  		_getStacks: function(last) {
  			var me = this;
  			var chart = me.chart;
  			var scale = me.getIndexScale();
  			var stacked = scale.options.stacked;
  			var ilen = last === undefined ? chart.data.datasets.length : last + 1;
  			var stacks = [];
  			var i, meta;
  
  			for (i = 0; i < ilen; ++i) {
  				meta = chart.getDatasetMeta(i);
  				if (meta.bar && chart.isDatasetVisible(i) &&
  					(stacked === false ||
  					(stacked === true && stacks.indexOf(meta.stack) === -1) ||
  					(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
  					stacks.push(meta.stack);
  				}
  			}
  
  			return stacks;
  		},
  
  		/**
  		 * Returns the effective number of stacks based on groups and bar visibility.
  		 * @private
  		 */
  		getStackCount: function() {
  			return this._getStacks().length;
  		},
  
  		/**
  		 * Returns the stack index for the given dataset based on groups and bar visibility.
  		 * @param {Number} [datasetIndex] - The dataset index
  		 * @param {String} [name] - The stack name to find
  		 * @returns {Number} The stack index
  		 * @private
  		 */
  		getStackIndex: function(datasetIndex, name) {
  			var stacks = this._getStacks(datasetIndex);
  			var index = (name !== undefined)
  				? stacks.indexOf(name)
  				: -1; // indexOf returns -1 if element is not present
  
  			return (index === -1)
  				? stacks.length - 1
  				: index;
  		},
  
  		/**
  		 * @private
  		 */
  		getRuler: function() {
  			var me = this;
  			var scale = me.getIndexScale();
  			var stackCount = me.getStackCount();
  			var datasetIndex = me.index;
  			var isHorizontal = scale.isHorizontal();
  			var start = isHorizontal ? scale.left : scale.top;
  			var end = start + (isHorizontal ? scale.width : scale.height);
  			var pixels = [];
  			var i, ilen, min;
  
  			for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
  				pixels.push(scale.getPixelForValue(null, i, datasetIndex));
  			}
  
  			min = helpers.isNullOrUndef(scale.options.barThickness)
  				? computeMinSampleSize(scale, pixels)
  				: -1;
  
  			return {
  				min: min,
  				pixels: pixels,
  				start: start,
  				end: end,
  				stackCount: stackCount,
  				scale: scale
  			};
  		},
  
  		/**
  		 * Note: pixel values are not clamped to the scale area.
  		 * @private
  		 */
  		calculateBarValuePixels: function(datasetIndex, index) {
  			var me = this;
  			var chart = me.chart;
  			var meta = me.getMeta();
  			var scale = me.getValueScale();
  			var datasets = chart.data.datasets;
  			var value = scale.getRightValue(datasets[datasetIndex].data[index]);
  			var stacked = scale.options.stacked;
  			var stack = meta.stack;
  			var start = 0;
  			var i, imeta, ivalue, base, head, size;
  
  			if (stacked || (stacked === undefined && stack !== undefined)) {
  				for (i = 0; i < datasetIndex; ++i) {
  					imeta = chart.getDatasetMeta(i);
  
  					if (imeta.bar &&
  						imeta.stack === stack &&
  						imeta.controller.getValueScaleId() === scale.id &&
  						chart.isDatasetVisible(i)) {
  
  						ivalue = scale.getRightValue(datasets[i].data[index]);
  						if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
  							start += ivalue;
  						}
  					}
  				}
  			}
  
  			base = scale.getPixelForValue(start);
  			head = scale.getPixelForValue(start + value);
  			size = (head - base) / 2;
  
  			return {
  				size: size,
  				base: base,
  				head: head,
  				center: head + size / 2
  			};
  		},
  
  		/**
  		 * @private
  		 */
  		calculateBarIndexPixels: function(datasetIndex, index, ruler) {
  			var me = this;
  			var options = ruler.scale.options;
  			var range = options.barThickness === 'flex'
  				? computeFlexCategoryTraits(index, ruler, options)
  				: computeFitCategoryTraits(index, ruler, options);
  
  			var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
  			var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
  			var size = Math.min(
  				helpers.valueOrDefault(options.maxBarThickness, Infinity),
  				range.chunk * range.ratio);
  
  			return {
  				base: center - size / 2,
  				head: center + size / 2,
  				center: center,
  				size: size
  			};
  		},
  
  		draw: function() {
  			var me = this;
  			var chart = me.chart;
  			var scale = me.getValueScale();
  			var rects = me.getMeta().data;
  			var dataset = me.getDataset();
  			var ilen = rects.length;
  			var i = 0;
  
  			helpers.canvas.clipArea(chart.ctx, chart.chartArea);
  
  			for (; i < ilen; ++i) {
  				if (!isNaN(scale.getRightValue(dataset.data[i]))) {
  					rects[i].draw();
  				}
  			}
  
  			helpers.canvas.unclipArea(chart.ctx);
  		},
  	});
  
  	Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
  		/**
  		 * @private
  		 */
  		getValueScaleId: function() {
  			return this.getMeta().xAxisID;
  		},
  
  		/**
  		 * @private
  		 */
  		getIndexScaleId: function() {
  			return this.getMeta().yAxisID;
  		}
  	});
  };
  
  },{"26":26,"41":41,"46":46}],16:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('bubble', {
  	hover: {
  		mode: 'single'
  	},
  
  	scales: {
  		xAxes: [{
  			type: 'linear', // bubble should probably use a linear scale by default
  			position: 'bottom',
  			id: 'x-axis-0' // need an ID so datasets can reference the scale
  		}],
  		yAxes: [{
  			type: 'linear',
  			position: 'left',
  			id: 'y-axis-0'
  		}]
  	},
  
  	tooltips: {
  		callbacks: {
  			title: function() {
  				// Title doesn't make sense for scatter since we format the data as a point
  				return '';
  			},
  			label: function(item, data) {
  				var datasetLabel = data.datasets[item.datasetIndex].label || '';
  				var dataPoint = data.datasets[item.datasetIndex].data[item.index];
  				return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
  			}
  		}
  	}
  });
  
  
  module.exports = function(Chart) {
  
  	Chart.controllers.bubble = Chart.DatasetController.extend({
  		/**
  		 * @protected
  		 */
  		dataElementType: elements.Point,
  
  		/**
  		 * @protected
  		 */
  		update: function(reset) {
  			var me = this;
  			var meta = me.getMeta();
  			var points = meta.data;
  
  			// Update Points
  			helpers.each(points, function(point, index) {
  				me.updateElement(point, index, reset);
  			});
  		},
  
  		/**
  		 * @protected
  		 */
  		updateElement: function(point, index, reset) {
  			var me = this;
  			var meta = me.getMeta();
  			var custom = point.custom || {};
  			var xScale = me.getScaleForId(meta.xAxisID);
  			var yScale = me.getScaleForId(meta.yAxisID);
  			var options = me._resolveElementOptions(point, index);
  			var data = me.getDataset().data[index];
  			var dsIndex = me.index;
  
  			var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
  			var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
  
  			point._xScale = xScale;
  			point._yScale = yScale;
  			point._options = options;
  			point._datasetIndex = dsIndex;
  			point._index = index;
  			point._model = {
  				backgroundColor: options.backgroundColor,
  				borderColor: options.borderColor,
  				borderWidth: options.borderWidth,
  				hitRadius: options.hitRadius,
  				pointStyle: options.pointStyle,
  				rotation: options.rotation,
  				radius: reset ? 0 : options.radius,
  				skip: custom.skip || isNaN(x) || isNaN(y),
  				x: x,
  				y: y,
  			};
  
  			point.pivot();
  		},
  
  		/**
  		 * @protected
  		 */
  		setHoverStyle: function(point) {
  			var model = point._model;
  			var options = point._options;
  			point.$previousStyle = {
  				backgroundColor: model.backgroundColor,
  				borderColor: model.borderColor,
  				borderWidth: model.borderWidth,
  				radius: model.radius
  			};
  			model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor));
  			model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
  			model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
  			model.radius = options.radius + options.hoverRadius;
  		},
  
  		/**
  		 * @private
  		 */
  		_resolveElementOptions: function(point, index) {
  			var me = this;
  			var chart = me.chart;
  			var datasets = chart.data.datasets;
  			var dataset = datasets[me.index];
  			var custom = point.custom || {};
  			var options = chart.options.elements.point;
  			var resolve = helpers.options.resolve;
  			var data = dataset.data[index];
  			var values = {};
  			var i, ilen, key;
  
  			// Scriptable options
  			var context = {
  				chart: chart,
  				dataIndex: index,
  				dataset: dataset,
  				datasetIndex: me.index
  			};
  
  			var keys = [
  				'backgroundColor',
  				'borderColor',
  				'borderWidth',
  				'hoverBackgroundColor',
  				'hoverBorderColor',
  				'hoverBorderWidth',
  				'hoverRadius',
  				'hitRadius',
  				'pointStyle',
  				'rotation'
  			];
  
  			for (i = 0, ilen = keys.length; i < ilen; ++i) {
  				key = keys[i];
  				values[key] = resolve([
  					custom[key],
  					dataset[key],
  					options[key]
  				], context, index);
  			}
  
  			// Custom radius resolution
  			values.radius = resolve([
  				custom.radius,
  				data ? data.r : undefined,
  				dataset.radius,
  				options.radius
  			], context, index);
  			return values;
  		}
  	});
  };
  
  },{"26":26,"41":41,"46":46}],17:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('doughnut', {
  	animation: {
  		// Boolean - Whether we animate the rotation of the Doughnut
  		animateRotate: true,
  		// Boolean - Whether we animate scaling the Doughnut from the centre
  		animateScale: false
  	},
  	hover: {
  		mode: 'single'
  	},
  	legendCallback: function(chart) {
  		var text = [];
  		text.push('<ul class="' + chart.id + '-legend">');
  
  		var data = chart.data;
  		var datasets = data.datasets;
  		var labels = data.labels;
  
  		if (datasets.length) {
  			for (var i = 0; i < datasets[0].data.length; ++i) {
  				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
  				if (labels[i]) {
  					text.push(labels[i]);
  				}
  				text.push('</li>');
  			}
  		}
  
  		text.push('</ul>');
  		return text.join('');
  	},
  	legend: {
  		labels: {
  			generateLabels: function(chart) {
  				var data = chart.data;
  				if (data.labels.length && data.datasets.length) {
  					return data.labels.map(function(label, i) {
  						var meta = chart.getDatasetMeta(0);
  						var ds = data.datasets[0];
  						var arc = meta.data[i];
  						var custom = arc && arc.custom || {};
  						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
  						var arcOpts = chart.options.elements.arc;
  						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
  						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
  						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
  
  						return {
  							text: label,
  							fillStyle: fill,
  							strokeStyle: stroke,
  							lineWidth: bw,
  							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
  
  							// Extra data used for toggling the correct item
  							index: i
  						};
  					});
  				}
  				return [];
  			}
  		},
  
  		onClick: function(e, legendItem) {
  			var index = legendItem.index;
  			var chart = this.chart;
  			var i, ilen, meta;
  
  			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  				meta = chart.getDatasetMeta(i);
  				// toggle visibility of index if exists
  				if (meta.data[index]) {
  					meta.data[index].hidden = !meta.data[index].hidden;
  				}
  			}
  
  			chart.update();
  		}
  	},
  
  	// The percentage of the chart that we cut out of the middle.
  	cutoutPercentage: 50,
  
  	// The rotation of the chart, where the first data arc begins.
  	rotation: Math.PI * -0.5,
  
  	// The total circumference of the chart.
  	circumference: Math.PI * 2.0,
  
  	// Need to override these to give a nice default
  	tooltips: {
  		callbacks: {
  			title: function() {
  				return '';
  			},
  			label: function(tooltipItem, data) {
  				var dataLabel = data.labels[tooltipItem.index];
  				var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
  
  				if (helpers.isArray(dataLabel)) {
  					// show value on first line of multiline label
  					// need to clone because we are changing the value
  					dataLabel = dataLabel.slice();
  					dataLabel[0] += value;
  				} else {
  					dataLabel += value;
  				}
  
  				return dataLabel;
  			}
  		}
  	}
  });
  
  defaults._set('pie', helpers.clone(defaults.doughnut));
  defaults._set('pie', {
  	cutoutPercentage: 0
  });
  
  module.exports = function(Chart) {
  
  	Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
  
  		dataElementType: elements.Arc,
  
  		linkScales: helpers.noop,
  
  		// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
  		getRingIndex: function(datasetIndex) {
  			var ringIndex = 0;
  
  			for (var j = 0; j < datasetIndex; ++j) {
  				if (this.chart.isDatasetVisible(j)) {
  					++ringIndex;
  				}
  			}
  
  			return ringIndex;
  		},
  
  		update: function(reset) {
  			var me = this;
  			var chart = me.chart;
  			var chartArea = chart.chartArea;
  			var opts = chart.options;
  			var arcOpts = opts.elements.arc;
  			var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
  			var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
  			var minSize = Math.min(availableWidth, availableHeight);
  			var offset = {x: 0, y: 0};
  			var meta = me.getMeta();
  			var cutoutPercentage = opts.cutoutPercentage;
  			var circumference = opts.circumference;
  
  			// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
  			if (circumference < Math.PI * 2.0) {
  				var startAngle = opts.rotation % (Math.PI * 2.0);
  				startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
  				var endAngle = startAngle + circumference;
  				var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
  				var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
  				var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
  				var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
  				var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
  				var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
  				var cutout = cutoutPercentage / 100.0;
  				var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
  				var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
  				var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
  				minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
  				offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
  			}
  
  			chart.borderWidth = me.getMaxBorderWidth(meta.data);
  			chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
  			chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
  			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
  			chart.offsetX = offset.x * chart.outerRadius;
  			chart.offsetY = offset.y * chart.outerRadius;
  
  			meta.total = me.calculateTotal();
  
  			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
  			me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
  
  			helpers.each(meta.data, function(arc, index) {
  				me.updateElement(arc, index, reset);
  			});
  		},
  
  		updateElement: function(arc, index, reset) {
  			var me = this;
  			var chart = me.chart;
  			var chartArea = chart.chartArea;
  			var opts = chart.options;
  			var animationOpts = opts.animation;
  			var centerX = (chartArea.left + chartArea.right) / 2;
  			var centerY = (chartArea.top + chartArea.bottom) / 2;
  			var startAngle = opts.rotation; // non reset case handled later
  			var endAngle = opts.rotation; // non reset case handled later
  			var dataset = me.getDataset();
  			var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
  			var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
  			var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
  			var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
  
  			helpers.extend(arc, {
  				// Utility
  				_datasetIndex: me.index,
  				_index: index,
  
  				// Desired view properties
  				_model: {
  					x: centerX + chart.offsetX,
  					y: centerY + chart.offsetY,
  					startAngle: startAngle,
  					endAngle: endAngle,
  					circumference: circumference,
  					outerRadius: outerRadius,
  					innerRadius: innerRadius,
  					label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
  				}
  			});
  
  			var model = arc._model;
  
  			// Resets the visual styles
  			var custom = arc.custom || {};
  			var valueOrDefault = helpers.valueAtIndexOrDefault;
  			var elementOpts = this.chart.options.elements.arc;
  			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
  			model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
  			model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
  
  			// Set correct angles if not resetting
  			if (!reset || !animationOpts.animateRotate) {
  				if (index === 0) {
  					model.startAngle = opts.rotation;
  				} else {
  					model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
  				}
  
  				model.endAngle = model.startAngle + model.circumference;
  			}
  
  			arc.pivot();
  		},
  
  		calculateTotal: function() {
  			var dataset = this.getDataset();
  			var meta = this.getMeta();
  			var total = 0;
  			var value;
  
  			helpers.each(meta.data, function(element, index) {
  				value = dataset.data[index];
  				if (!isNaN(value) && !element.hidden) {
  					total += Math.abs(value);
  				}
  			});
  
  			/* if (total === 0) {
  				total = NaN;
  			}*/
  
  			return total;
  		},
  
  		calculateCircumference: function(value) {
  			var total = this.getMeta().total;
  			if (total > 0 && !isNaN(value)) {
  				return (Math.PI * 2.0) * (Math.abs(value) / total);
  			}
  			return 0;
  		},
  
  		// gets the max border or hover width to properly scale pie charts
  		getMaxBorderWidth: function(arcs) {
  			var max = 0;
  			var index = this.index;
  			var length = arcs.length;
  			var borderWidth;
  			var hoverWidth;
  
  			for (var i = 0; i < length; i++) {
  				borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
  				hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
  
  				max = borderWidth > max ? borderWidth : max;
  				max = hoverWidth > max ? hoverWidth : max;
  			}
  			return max;
  		}
  	});
  };
  
  },{"26":26,"41":41,"46":46}],18:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('line', {
  	showLines: true,
  	spanGaps: false,
  
  	hover: {
  		mode: 'label'
  	},
  
  	scales: {
  		xAxes: [{
  			type: 'category',
  			id: 'x-axis-0'
  		}],
  		yAxes: [{
  			type: 'linear',
  			id: 'y-axis-0'
  		}]
  	}
  });
  
  module.exports = function(Chart) {
  
  	function lineEnabled(dataset, options) {
  		return helpers.valueOrDefault(dataset.showLine, options.showLines);
  	}
  
  	Chart.controllers.line = Chart.DatasetController.extend({
  
  		datasetElementType: elements.Line,
  
  		dataElementType: elements.Point,
  
  		update: function(reset) {
  			var me = this;
  			var meta = me.getMeta();
  			var line = meta.dataset;
  			var points = meta.data || [];
  			var options = me.chart.options;
  			var lineElementOptions = options.elements.line;
  			var scale = me.getScaleForId(meta.yAxisID);
  			var i, ilen, custom;
  			var dataset = me.getDataset();
  			var showLine = lineEnabled(dataset, options);
  
  			// Update Line
  			if (showLine) {
  				custom = line.custom || {};
  
  				// Compatibility: If the properties are defined with only the old name, use those values
  				if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
  					dataset.lineTension = dataset.tension;
  				}
  
  				// Utility
  				line._scale = scale;
  				line._datasetIndex = me.index;
  				// Data
  				line._children = points;
  				// Model
  				line._model = {
  					// Appearance
  					// The default behavior of lines is to break at null values, according
  					// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
  					// This option gives lines the ability to span gaps
  					spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
  					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
  					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
  					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
  					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
  					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
  					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
  					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
  					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
  					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
  					steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
  					cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
  				};
  
  				line.pivot();
  			}
  
  			// Update Points
  			for (i = 0, ilen = points.length; i < ilen; ++i) {
  				me.updateElement(points[i], i, reset);
  			}
  
  			if (showLine && line._model.tension !== 0) {
  				me.updateBezierControlPoints();
  			}
  
  			// Now pivot the point for animation
  			for (i = 0, ilen = points.length; i < ilen; ++i) {
  				points[i].pivot();
  			}
  		},
  
  		getPointBackgroundColor: function(point, index) {
  			var backgroundColor = this.chart.options.elements.point.backgroundColor;
  			var dataset = this.getDataset();
  			var custom = point.custom || {};
  
  			if (custom.backgroundColor) {
  				backgroundColor = custom.backgroundColor;
  			} else if (dataset.pointBackgroundColor) {
  				backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
  			} else if (dataset.backgroundColor) {
  				backgroundColor = dataset.backgroundColor;
  			}
  
  			return backgroundColor;
  		},
  
  		getPointBorderColor: function(point, index) {
  			var borderColor = this.chart.options.elements.point.borderColor;
  			var dataset = this.getDataset();
  			var custom = point.custom || {};
  
  			if (custom.borderColor) {
  				borderColor = custom.borderColor;
  			} else if (dataset.pointBorderColor) {
  				borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
  			} else if (dataset.borderColor) {
  				borderColor = dataset.borderColor;
  			}
  
  			return borderColor;
  		},
  
  		getPointBorderWidth: function(point, index) {
  			var borderWidth = this.chart.options.elements.point.borderWidth;
  			var dataset = this.getDataset();
  			var custom = point.custom || {};
  
  			if (!isNaN(custom.borderWidth)) {
  				borderWidth = custom.borderWidth;
  			} else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
  				borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
  			} else if (!isNaN(dataset.borderWidth)) {
  				borderWidth = dataset.borderWidth;
  			}
  
  			return borderWidth;
  		},
  
  		getPointRotation: function(point, index) {
  			var pointRotation = this.chart.options.elements.point.rotation;
  			var dataset = this.getDataset();
  			var custom = point.custom || {};
  
  			if (!isNaN(custom.rotation)) {
  				pointRotation = custom.rotation;
  			} else if (!isNaN(dataset.pointRotation) || helpers.isArray(dataset.pointRotation)) {
  				pointRotation = helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointRotation);
  			}
  			return pointRotation;
  		},
  
  		updateElement: function(point, index, reset) {
  			var me = this;
  			var meta = me.getMeta();
  			var custom = point.custom || {};
  			var dataset = me.getDataset();
  			var datasetIndex = me.index;
  			var value = dataset.data[index];
  			var yScale = me.getScaleForId(meta.yAxisID);
  			var xScale = me.getScaleForId(meta.xAxisID);
  			var pointOptions = me.chart.options.elements.point;
  			var x, y;
  
  			// Compatibility: If the properties are defined with only the old name, use those values
  			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
  				dataset.pointRadius = dataset.radius;
  			}
  			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
  				dataset.pointHitRadius = dataset.hitRadius;
  			}
  
  			x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
  			y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
  
  			// Utility
  			point._xScale = xScale;
  			point._yScale = yScale;
  			point._datasetIndex = datasetIndex;
  			point._index = index;
  
  			// Desired view properties
  			point._model = {
  				x: x,
  				y: y,
  				skip: custom.skip || isNaN(x) || isNaN(y),
  				// Appearance
  				radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
  				pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
  				rotation: me.getPointRotation(point, index),
  				backgroundColor: me.getPointBackgroundColor(point, index),
  				borderColor: me.getPointBorderColor(point, index),
  				borderWidth: me.getPointBorderWidth(point, index),
  				tension: meta.dataset._model ? meta.dataset._model.tension : 0,
  				steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
  				// Tooltip
  				hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
  			};
  		},
  
  		calculatePointY: function(value, index, datasetIndex) {
  			var me = this;
  			var chart = me.chart;
  			var meta = me.getMeta();
  			var yScale = me.getScaleForId(meta.yAxisID);
  			var sumPos = 0;
  			var sumNeg = 0;
  			var i, ds, dsMeta;
  
  			if (yScale.options.stacked) {
  				for (i = 0; i < datasetIndex; i++) {
  					ds = chart.data.datasets[i];
  					dsMeta = chart.getDatasetMeta(i);
  					if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
  						var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
  						if (stackedRightValue < 0) {
  							sumNeg += stackedRightValue || 0;
  						} else {
  							sumPos += stackedRightValue || 0;
  						}
  					}
  				}
  
  				var rightValue = Number(yScale.getRightValue(value));
  				if (rightValue < 0) {
  					return yScale.getPixelForValue(sumNeg + rightValue);
  				}
  				return yScale.getPixelForValue(sumPos + rightValue);
  			}
  
  			return yScale.getPixelForValue(value);
  		},
  
  		updateBezierControlPoints: function() {
  			var me = this;
  			var meta = me.getMeta();
  			var area = me.chart.chartArea;
  			var points = (meta.data || []);
  			var i, ilen, point, model, controlPoints;
  
  			// Only consider points that are drawn in case the spanGaps option is used
  			if (meta.dataset._model.spanGaps) {
  				points = points.filter(function(pt) {
  					return !pt._model.skip;
  				});
  			}
  
  			function capControlPoint(pt, min, max) {
  				return Math.max(Math.min(pt, max), min);
  			}
  
  			if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
  				helpers.splineCurveMonotone(points);
  			} else {
  				for (i = 0, ilen = points.length; i < ilen; ++i) {
  					point = points[i];
  					model = point._model;
  					controlPoints = helpers.splineCurve(
  						helpers.previousItem(points, i)._model,
  						model,
  						helpers.nextItem(points, i)._model,
  						meta.dataset._model.tension
  					);
  					model.controlPointPreviousX = controlPoints.previous.x;
  					model.controlPointPreviousY = controlPoints.previous.y;
  					model.controlPointNextX = controlPoints.next.x;
  					model.controlPointNextY = controlPoints.next.y;
  				}
  			}
  
  			if (me.chart.options.elements.line.capBezierPoints) {
  				for (i = 0, ilen = points.length; i < ilen; ++i) {
  					model = points[i]._model;
  					model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
  					model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
  					model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
  					model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
  				}
  			}
  		},
  
  		draw: function() {
  			var me = this;
  			var chart = me.chart;
  			var meta = me.getMeta();
  			var points = meta.data || [];
  			var area = chart.chartArea;
  			var ilen = points.length;
  			var halfBorderWidth;
  			var i = 0;
  
  			if (lineEnabled(me.getDataset(), chart.options)) {
  				halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
  
  				helpers.canvas.clipArea(chart.ctx, {
  					left: area.left,
  					right: area.right,
  					top: area.top - halfBorderWidth,
  					bottom: area.bottom + halfBorderWidth
  				});
  
  				meta.dataset.draw();
  
  				helpers.canvas.unclipArea(chart.ctx);
  			}
  
  			// Draw the points
  			for (; i < ilen; ++i) {
  				points[i].draw(area);
  			}
  		},
  
  		setHoverStyle: function(element) {
  			// Point
  			var dataset = this.chart.data.datasets[element._datasetIndex];
  			var index = element._index;
  			var custom = element.custom || {};
  			var model = element._model;
  
  			element.$previousStyle = {
  				backgroundColor: model.backgroundColor,
  				borderColor: model.borderColor,
  				borderWidth: model.borderWidth,
  				radius: model.radius
  			};
  
  			model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  			model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  			model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
  			model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
  		},
  	});
  };
  
  },{"26":26,"41":41,"46":46}],19:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('polarArea', {
  	scale: {
  		type: 'radialLinear',
  		angleLines: {
  			display: false
  		},
  		gridLines: {
  			circular: true
  		},
  		pointLabels: {
  			display: false
  		},
  		ticks: {
  			beginAtZero: true
  		}
  	},
  
  	// Boolean - Whether to animate the rotation of the chart
  	animation: {
  		animateRotate: true,
  		animateScale: true
  	},
  
  	startAngle: -0.5 * Math.PI,
  	legendCallback: function(chart) {
  		var text = [];
  		text.push('<ul class="' + chart.id + '-legend">');
  
  		var data = chart.data;
  		var datasets = data.datasets;
  		var labels = data.labels;
  
  		if (datasets.length) {
  			for (var i = 0; i < datasets[0].data.length; ++i) {
  				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
  				if (labels[i]) {
  					text.push(labels[i]);
  				}
  				text.push('</li>');
  			}
  		}
  
  		text.push('</ul>');
  		return text.join('');
  	},
  	legend: {
  		labels: {
  			generateLabels: function(chart) {
  				var data = chart.data;
  				if (data.labels.length && data.datasets.length) {
  					return data.labels.map(function(label, i) {
  						var meta = chart.getDatasetMeta(0);
  						var ds = data.datasets[0];
  						var arc = meta.data[i];
  						var custom = arc.custom || {};
  						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
  						var arcOpts = chart.options.elements.arc;
  						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
  						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
  						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
  
  						return {
  							text: label,
  							fillStyle: fill,
  							strokeStyle: stroke,
  							lineWidth: bw,
  							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
  
  							// Extra data used for toggling the correct item
  							index: i
  						};
  					});
  				}
  				return [];
  			}
  		},
  
  		onClick: function(e, legendItem) {
  			var index = legendItem.index;
  			var chart = this.chart;
  			var i, ilen, meta;
  
  			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  				meta = chart.getDatasetMeta(i);
  				meta.data[index].hidden = !meta.data[index].hidden;
  			}
  
  			chart.update();
  		}
  	},
  
  	// Need to override these to give a nice default
  	tooltips: {
  		callbacks: {
  			title: function() {
  				return '';
  			},
  			label: function(item, data) {
  				return data.labels[item.index] + ': ' + item.yLabel;
  			}
  		}
  	}
  });
  
  module.exports = function(Chart) {
  
  	Chart.controllers.polarArea = Chart.DatasetController.extend({
  
  		dataElementType: elements.Arc,
  
  		linkScales: helpers.noop,
  
  		update: function(reset) {
  			var me = this;
  			var dataset = me.getDataset();
  			var meta = me.getMeta();
  			var start = me.chart.options.startAngle || 0;
  			var starts = me._starts = [];
  			var angles = me._angles = [];
  			var i, ilen, angle;
  
  			me._updateRadius();
  
  			meta.count = me.countVisibleElements();
  
  			for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
  				starts[i] = start;
  				angle = me._computeAngle(i);
  				angles[i] = angle;
  				start += angle;
  			}
  
  			helpers.each(meta.data, function(arc, index) {
  				me.updateElement(arc, index, reset);
  			});
  		},
  
  		/**
  		 * @private
  		 */
  		_updateRadius: function() {
  			var me = this;
  			var chart = me.chart;
  			var chartArea = chart.chartArea;
  			var opts = chart.options;
  			var arcOpts = opts.elements.arc;
  			var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
  
  			chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
  			chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
  			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
  
  			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
  			me.innerRadius = me.outerRadius - chart.radiusLength;
  		},
  
  		updateElement: function(arc, index, reset) {
  			var me = this;
  			var chart = me.chart;
  			var dataset = me.getDataset();
  			var opts = chart.options;
  			var animationOpts = opts.animation;
  			var scale = chart.scale;
  			var labels = chart.data.labels;
  
  			var centerX = scale.xCenter;
  			var centerY = scale.yCenter;
  
  			// var negHalfPI = -0.5 * Math.PI;
  			var datasetStartAngle = opts.startAngle;
  			var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
  			var startAngle = me._starts[index];
  			var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);
  
  			var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
  
  			helpers.extend(arc, {
  				// Utility
  				_datasetIndex: me.index,
  				_index: index,
  				_scale: scale,
  
  				// Desired view properties
  				_model: {
  					x: centerX,
  					y: centerY,
  					innerRadius: 0,
  					outerRadius: reset ? resetRadius : distance,
  					startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
  					endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
  					label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
  				}
  			});
  
  			// Apply border and fill style
  			var elementOpts = this.chart.options.elements.arc;
  			var custom = arc.custom || {};
  			var valueOrDefault = helpers.valueAtIndexOrDefault;
  			var model = arc._model;
  
  			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
  			model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
  			model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
  
  			arc.pivot();
  		},
  
  		countVisibleElements: function() {
  			var dataset = this.getDataset();
  			var meta = this.getMeta();
  			var count = 0;
  
  			helpers.each(meta.data, function(element, index) {
  				if (!isNaN(dataset.data[index]) && !element.hidden) {
  					count++;
  				}
  			});
  
  			return count;
  		},
  
  		/**
  		 * @private
  		 */
  		_computeAngle: function(index) {
  			var me = this;
  			var count = this.getMeta().count;
  			var dataset = me.getDataset();
  			var meta = me.getMeta();
  
  			if (isNaN(dataset.data[index]) || meta.data[index].hidden) {
  				return 0;
  			}
  
  			// Scriptable options
  			var context = {
  				chart: me.chart,
  				dataIndex: index,
  				dataset: dataset,
  				datasetIndex: me.index
  			};
  
  			return helpers.options.resolve([
  				me.chart.options.elements.arc.angle,
  				(2 * Math.PI) / count
  			], context, index);
  		}
  	});
  };
  
  },{"26":26,"41":41,"46":46}],20:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('radar', {
  	scale: {
  		type: 'radialLinear'
  	},
  	elements: {
  		line: {
  			tension: 0 // no bezier in radar
  		}
  	}
  });
  
  module.exports = function(Chart) {
  
  	Chart.controllers.radar = Chart.DatasetController.extend({
  
  		datasetElementType: elements.Line,
  
  		dataElementType: elements.Point,
  
  		linkScales: helpers.noop,
  
  		update: function(reset) {
  			var me = this;
  			var meta = me.getMeta();
  			var line = meta.dataset;
  			var points = meta.data;
  			var custom = line.custom || {};
  			var dataset = me.getDataset();
  			var lineElementOptions = me.chart.options.elements.line;
  			var scale = me.chart.scale;
  
  			// Compatibility: If the properties are defined with only the old name, use those values
  			if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
  				dataset.lineTension = dataset.tension;
  			}
  
  			helpers.extend(meta.dataset, {
  				// Utility
  				_datasetIndex: me.index,
  				_scale: scale,
  				// Data
  				_children: points,
  				_loop: true,
  				// Model
  				_model: {
  					// Appearance
  					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
  					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
  					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
  					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
  					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
  					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
  					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
  					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
  					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
  				}
  			});
  
  			meta.dataset.pivot();
  
  			// Update Points
  			helpers.each(points, function(point, index) {
  				me.updateElement(point, index, reset);
  			}, me);
  
  			// Update bezier control points
  			me.updateBezierControlPoints();
  		},
  		updateElement: function(point, index, reset) {
  			var me = this;
  			var custom = point.custom || {};
  			var dataset = me.getDataset();
  			var scale = me.chart.scale;
  			var pointElementOptions = me.chart.options.elements.point;
  			var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
  
  			// Compatibility: If the properties are defined with only the old name, use those values
  			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
  				dataset.pointRadius = dataset.radius;
  			}
  			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
  				dataset.pointHitRadius = dataset.hitRadius;
  			}
  
  			helpers.extend(point, {
  				// Utility
  				_datasetIndex: me.index,
  				_index: index,
  				_scale: scale,
  
  				// Desired view properties
  				_model: {
  					x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
  					y: reset ? scale.yCenter : pointPosition.y,
  
  					// Appearance
  					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
  					radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
  					backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
  					borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
  					borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
  					pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
  					rotation: custom.rotation ? custom.rotation : helpers.valueAtIndexOrDefault(dataset.pointRotation, index, pointElementOptions.rotation),
  
  					// Tooltip
  					hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
  				}
  			});
  
  			point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
  		},
  		updateBezierControlPoints: function() {
  			var chartArea = this.chart.chartArea;
  			var meta = this.getMeta();
  
  			helpers.each(meta.data, function(point, index) {
  				var model = point._model;
  				var controlPoints = helpers.splineCurve(
  					helpers.previousItem(meta.data, index, true)._model,
  					model,
  					helpers.nextItem(meta.data, index, true)._model,
  					model.tension
  				);
  
  				// Prevent the bezier going outside of the bounds of the graph
  				model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
  				model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
  
  				model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
  				model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
  
  				// Now pivot the point for animation
  				point.pivot();
  			});
  		},
  
  		setHoverStyle: function(point) {
  			// Point
  			var dataset = this.chart.data.datasets[point._datasetIndex];
  			var custom = point.custom || {};
  			var index = point._index;
  			var model = point._model;
  
  			point.$previousStyle = {
  				backgroundColor: model.backgroundColor,
  				borderColor: model.borderColor,
  				borderWidth: model.borderWidth,
  				radius: model.radius
  			};
  
  			model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
  			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
  		},
  	});
  };
  
  },{"26":26,"41":41,"46":46}],21:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  
  defaults._set('scatter', {
  	hover: {
  		mode: 'single'
  	},
  
  	scales: {
  		xAxes: [{
  			id: 'x-axis-1',    // need an ID so datasets can reference the scale
  			type: 'linear',    // scatter should not use a category axis
  			position: 'bottom'
  		}],
  		yAxes: [{
  			id: 'y-axis-1',
  			type: 'linear',
  			position: 'left'
  		}]
  	},
  
  	showLines: false,
  
  	tooltips: {
  		callbacks: {
  			title: function() {
  				return '';     // doesn't make sense for scatter since data are formatted as a point
  			},
  			label: function(item) {
  				return '(' + item.xLabel + ', ' + item.yLabel + ')';
  			}
  		}
  	}
  });
  
  module.exports = function(Chart) {
  
  	// Scatter charts use line controllers
  	Chart.controllers.scatter = Chart.controllers.line;
  
  };
  
  },{"26":26}],22:[function(require,module,exports){
  'use strict';
  
  var Element = require(27);
  
  var exports = module.exports = Element.extend({
  	chart: null, // the animation associated chart instance
  	currentStep: 0, // the current animation step
  	numSteps: 60, // default number of steps
  	easing: '', // the easing to use for this animation
  	render: null, // render function used by the animation service
  
  	onAnimationProgress: null, // user specified callback to fire on each step of the animation
  	onAnimationComplete: null, // user specified callback to fire when the animation finishes
  });
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use Chart.Animation instead
   * @prop Chart.Animation#animationObject
   * @deprecated since version 2.6.0
   * @todo remove at version 3
   */
  Object.defineProperty(exports.prototype, 'animationObject', {
  	get: function() {
  		return this;
  	}
  });
  
  /**
   * Provided for backward compatibility, use Chart.Animation#chart instead
   * @prop Chart.Animation#chartInstance
   * @deprecated since version 2.6.0
   * @todo remove at version 3
   */
  Object.defineProperty(exports.prototype, 'chartInstance', {
  	get: function() {
  		return this.chart;
  	},
  	set: function(value) {
  		this.chart = value;
  	}
  });
  
  },{"27":27}],23:[function(require,module,exports){
  /* global window: false */
  'use strict';
  
  var defaults = require(26);
  var helpers = require(46);
  
  defaults._set('global', {
  	animation: {
  		duration: 1000,
  		easing: 'easeOutQuart',
  		onProgress: helpers.noop,
  		onComplete: helpers.noop
  	}
  });
  
  module.exports = {
  	frameDuration: 17,
  	animations: [],
  	dropFrames: 0,
  	request: null,
  
  	/**
  	 * @param {Chart} chart - The chart to animate.
  	 * @param {Chart.Animation} animation - The animation that we will animate.
  	 * @param {Number} duration - The animation duration in ms.
  	 * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
  	 */
  	addAnimation: function(chart, animation, duration, lazy) {
  		var animations = this.animations;
  		var i, ilen;
  
  		animation.chart = chart;
  
  		if (!lazy) {
  			chart.animating = true;
  		}
  
  		for (i = 0, ilen = animations.length; i < ilen; ++i) {
  			if (animations[i].chart === chart) {
  				animations[i] = animation;
  				return;
  			}
  		}
  
  		animations.push(animation);
  
  		// If there are no animations queued, manually kickstart a digest, for lack of a better word
  		if (animations.length === 1) {
  			this.requestAnimationFrame();
  		}
  	},
  
  	cancelAnimation: function(chart) {
  		var index = helpers.findIndex(this.animations, function(animation) {
  			return animation.chart === chart;
  		});
  
  		if (index !== -1) {
  			this.animations.splice(index, 1);
  			chart.animating = false;
  		}
  	},
  
  	requestAnimationFrame: function() {
  		var me = this;
  		if (me.request === null) {
  			// Skip animation frame requests until the active one is executed.
  			// This can happen when processing mouse events, e.g. 'mousemove'
  			// and 'mouseout' events will trigger multiple renders.
  			me.request = helpers.requestAnimFrame.call(window, function() {
  				me.request = null;
  				me.startDigest();
  			});
  		}
  	},
  
  	/**
  	 * @private
  	 */
  	startDigest: function() {
  		var me = this;
  		var startTime = Date.now();
  		var framesToDrop = 0;
  
  		if (me.dropFrames > 1) {
  			framesToDrop = Math.floor(me.dropFrames);
  			me.dropFrames = me.dropFrames % 1;
  		}
  
  		me.advance(1 + framesToDrop);
  
  		var endTime = Date.now();
  
  		me.dropFrames += (endTime - startTime) / me.frameDuration;
  
  		// Do we have more stuff to animate?
  		if (me.animations.length > 0) {
  			me.requestAnimationFrame();
  		}
  	},
  
  	/**
  	 * @private
  	 */
  	advance: function(count) {
  		var animations = this.animations;
  		var animation, chart;
  		var i = 0;
  
  		while (i < animations.length) {
  			animation = animations[i];
  			chart = animation.chart;
  
  			animation.currentStep = (animation.currentStep || 0) + count;
  			animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
  
  			helpers.callback(animation.render, [chart, animation], chart);
  			helpers.callback(animation.onAnimationProgress, [animation], chart);
  
  			if (animation.currentStep >= animation.numSteps) {
  				helpers.callback(animation.onAnimationComplete, [animation], chart);
  				chart.animating = false;
  				animations.splice(i, 1);
  			} else {
  				++i;
  			}
  		}
  	}
  };
  
  },{"26":26,"46":46}],24:[function(require,module,exports){
  'use strict';
  
  var Animation = require(22);
  var animations = require(23);
  var defaults = require(26);
  var helpers = require(46);
  var Interaction = require(29);
  var layouts = require(31);
  var platform = require(49);
  var plugins = require(32);
  var scaleService = require(34);
  var Tooltip = require(36);
  
  module.exports = function(Chart) {
  
  	// Create a dictionary of chart types, to allow for extension of existing types
  	Chart.types = {};
  
  	// Store a reference to each instance - allowing us to globally resize chart instances on window resize.
  	// Destroy method on the chart will remove the instance of the chart from this reference.
  	Chart.instances = {};
  
  	// Controllers available for dataset visualization eg. bar, line, slice, etc.
  	Chart.controllers = {};
  
  	/**
  	 * Initializes the given config with global and chart default values.
  	 */
  	function initConfig(config) {
  		config = config || {};
  
  		// Do NOT use configMerge() for the data object because this method merges arrays
  		// and so would change references to labels and datasets, preventing data updates.
  		var data = config.data = config.data || {};
  		data.datasets = data.datasets || [];
  		data.labels = data.labels || [];
  
  		config.options = helpers.configMerge(
  			defaults.global,
  			defaults[config.type],
  			config.options || {});
  
  		return config;
  	}
  
  	/**
  	 * Updates the config of the chart
  	 * @param chart {Chart} chart to update the options for
  	 */
  	function updateConfig(chart) {
  		var newOptions = chart.options;
  
  		helpers.each(chart.scales, function(scale) {
  			layouts.removeBox(chart, scale);
  		});
  
  		newOptions = helpers.configMerge(
  			Chart.defaults.global,
  			Chart.defaults[chart.config.type],
  			newOptions);
  
  		chart.options = chart.config.options = newOptions;
  		chart.ensureScalesHaveIDs();
  		chart.buildOrUpdateScales();
  		// Tooltip
  		chart.tooltip._options = newOptions.tooltips;
  		chart.tooltip.initialize();
  	}
  
  	function positionIsHorizontal(position) {
  		return position === 'top' || position === 'bottom';
  	}
  
  	helpers.extend(Chart.prototype, /** @lends Chart */ {
  		/**
  		 * @private
  		 */
  		construct: function(item, config) {
  			var me = this;
  
  			config = initConfig(config);
  
  			var context = platform.acquireContext(item, config);
  			var canvas = context && context.canvas;
  			var height = canvas && canvas.height;
  			var width = canvas && canvas.width;
  
  			me.id = helpers.uid();
  			me.ctx = context;
  			me.canvas = canvas;
  			me.config = config;
  			me.width = width;
  			me.height = height;
  			me.aspectRatio = height ? width / height : null;
  			me.options = config.options;
  			me._bufferedRender = false;
  
  			/**
  			 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
  			 * the "instance" still need to be defined since it might be called from plugins.
  			 * @prop Chart#chart
  			 * @deprecated since version 2.6.0
  			 * @todo remove at version 3
  			 * @private
  			 */
  			me.chart = me;
  			me.controller = me; // chart.chart.controller #inception
  
  			// Add the chart instance to the global namespace
  			Chart.instances[me.id] = me;
  
  			// Define alias to the config data: `chart.data === chart.config.data`
  			Object.defineProperty(me, 'data', {
  				get: function() {
  					return me.config.data;
  				},
  				set: function(value) {
  					me.config.data = value;
  				}
  			});
  
  			if (!context || !canvas) {
  				// The given item is not a compatible context2d element, let's return before finalizing
  				// the chart initialization but after setting basic chart / controller properties that
  				// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
  				// https://github.com/chartjs/Chart.js/issues/2807
  				console.error("Failed to create chart: can't acquire context from the given item");
  				return;
  			}
  
  			me.initialize();
  			me.update();
  		},
  
  		/**
  		 * @private
  		 */
  		initialize: function() {
  			var me = this;
  
  			// Before init plugin notification
  			plugins.notify(me, 'beforeInit');
  
  			helpers.retinaScale(me, me.options.devicePixelRatio);
  
  			me.bindEvents();
  
  			if (me.options.responsive) {
  				// Initial resize before chart draws (must be silent to preserve initial animations).
  				me.resize(true);
  			}
  
  			// Make sure scales have IDs and are built before we build any controllers.
  			me.ensureScalesHaveIDs();
  			me.buildOrUpdateScales();
  			me.initToolTip();
  
  			// After init plugin notification
  			plugins.notify(me, 'afterInit');
  
  			return me;
  		},
  
  		clear: function() {
  			helpers.canvas.clear(this);
  			return this;
  		},
  
  		stop: function() {
  			// Stops any current animation loop occurring
  			animations.cancelAnimation(this);
  			return this;
  		},
  
  		resize: function(silent) {
  			var me = this;
  			var options = me.options;
  			var canvas = me.canvas;
  			var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
  
  			// the canvas render width and height will be casted to integers so make sure that
  			// the canvas display style uses the same integer values to avoid blurring effect.
  
  			// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed
  			var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas)));
  			var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas)));
  
  			if (me.width === newWidth && me.height === newHeight) {
  				return;
  			}
  
  			canvas.width = me.width = newWidth;
  			canvas.height = me.height = newHeight;
  			canvas.style.width = newWidth + 'px';
  			canvas.style.height = newHeight + 'px';
  
  			helpers.retinaScale(me, options.devicePixelRatio);
  
  			if (!silent) {
  				// Notify any plugins about the resize
  				var newSize = {width: newWidth, height: newHeight};
  				plugins.notify(me, 'resize', [newSize]);
  
  				// Notify of resize
  				if (me.options.onResize) {
  					me.options.onResize(me, newSize);
  				}
  
  				me.stop();
  				me.update({
  					duration: me.options.responsiveAnimationDuration
  				});
  			}
  		},
  
  		ensureScalesHaveIDs: function() {
  			var options = this.options;
  			var scalesOptions = options.scales || {};
  			var scaleOptions = options.scale;
  
  			helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
  				xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
  			});
  
  			helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
  				yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
  			});
  
  			if (scaleOptions) {
  				scaleOptions.id = scaleOptions.id || 'scale';
  			}
  		},
  
  		/**
  		 * Builds a map of scale ID to scale object for future lookup.
  		 */
  		buildOrUpdateScales: function() {
  			var me = this;
  			var options = me.options;
  			var scales = me.scales || {};
  			var items = [];
  			var updated = Object.keys(scales).reduce(function(obj, id) {
  				obj[id] = false;
  				return obj;
  			}, {});
  
  			if (options.scales) {
  				items = items.concat(
  					(options.scales.xAxes || []).map(function(xAxisOptions) {
  						return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
  					}),
  					(options.scales.yAxes || []).map(function(yAxisOptions) {
  						return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
  					})
  				);
  			}
  
  			if (options.scale) {
  				items.push({
  					options: options.scale,
  					dtype: 'radialLinear',
  					isDefault: true,
  					dposition: 'chartArea'
  				});
  			}
  
  			helpers.each(items, function(item) {
  				var scaleOptions = item.options;
  				var id = scaleOptions.id;
  				var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype);
  
  				if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
  					scaleOptions.position = item.dposition;
  				}
  
  				updated[id] = true;
  				var scale = null;
  				if (id in scales && scales[id].type === scaleType) {
  					scale = scales[id];
  					scale.options = scaleOptions;
  					scale.ctx = me.ctx;
  					scale.chart = me;
  				} else {
  					var scaleClass = scaleService.getScaleConstructor(scaleType);
  					if (!scaleClass) {
  						return;
  					}
  					scale = new scaleClass({
  						id: id,
  						type: scaleType,
  						options: scaleOptions,
  						ctx: me.ctx,
  						chart: me
  					});
  					scales[scale.id] = scale;
  				}
  
  				scale.mergeTicksOptions();
  
  				// TODO(SB): I think we should be able to remove this custom case (options.scale)
  				// and consider it as a regular scale part of the "scales"" map only! This would
  				// make the logic easier and remove some useless? custom code.
  				if (item.isDefault) {
  					me.scale = scale;
  				}
  			});
  			// clear up discarded scales
  			helpers.each(updated, function(hasUpdated, id) {
  				if (!hasUpdated) {
  					delete scales[id];
  				}
  			});
  
  			me.scales = scales;
  
  			scaleService.addScalesToLayout(this);
  		},
  
  		buildOrUpdateControllers: function() {
  			var me = this;
  			var types = [];
  			var newControllers = [];
  
  			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
  				var meta = me.getDatasetMeta(datasetIndex);
  				var type = dataset.type || me.config.type;
  
  				if (meta.type && meta.type !== type) {
  					me.destroyDatasetMeta(datasetIndex);
  					meta = me.getDatasetMeta(datasetIndex);
  				}
  				meta.type = type;
  
  				types.push(meta.type);
  
  				if (meta.controller) {
  					meta.controller.updateIndex(datasetIndex);
  					meta.controller.linkScales();
  				} else {
  					var ControllerClass = Chart.controllers[meta.type];
  					if (ControllerClass === undefined) {
  						throw new Error('"' + meta.type + '" is not a chart type.');
  					}
  
  					meta.controller = new ControllerClass(me, datasetIndex);
  					newControllers.push(meta.controller);
  				}
  			}, me);
  
  			return newControllers;
  		},
  
  		/**
  		 * Reset the elements of all datasets
  		 * @private
  		 */
  		resetElements: function() {
  			var me = this;
  			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
  				me.getDatasetMeta(datasetIndex).controller.reset();
  			}, me);
  		},
  
  		/**
  		* Resets the chart back to it's state before the initial animation
  		*/
  		reset: function() {
  			this.resetElements();
  			this.tooltip.initialize();
  		},
  
  		update: function(config) {
  			var me = this;
  
  			if (!config || typeof config !== 'object') {
  				// backwards compatibility
  				config = {
  					duration: config,
  					lazy: arguments[1]
  				};
  			}
  
  			updateConfig(me);
  
  			// plugins options references might have change, let's invalidate the cache
  			// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
  			plugins._invalidate(me);
  
  			if (plugins.notify(me, 'beforeUpdate') === false) {
  				return;
  			}
  
  			// In case the entire data object changed
  			me.tooltip._data = me.data;
  
  			// Make sure dataset controllers are updated and new controllers are reset
  			var newControllers = me.buildOrUpdateControllers();
  
  			// Make sure all dataset controllers have correct meta data counts
  			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
  				me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
  			}, me);
  
  			me.updateLayout();
  
  			// Can only reset the new controllers after the scales have been updated
  			if (me.options.animation && me.options.animation.duration) {
  				helpers.each(newControllers, function(controller) {
  					controller.reset();
  				});
  			}
  
  			me.updateDatasets();
  
  			// Need to reset tooltip in case it is displayed with elements that are removed
  			// after update.
  			me.tooltip.initialize();
  
  			// Last active contains items that were previously in the tooltip.
  			// When we reset the tooltip, we need to clear it
  			me.lastActive = [];
  
  			// Do this before render so that any plugins that need final scale updates can use it
  			plugins.notify(me, 'afterUpdate');
  
  			if (me._bufferedRender) {
  				me._bufferedRequest = {
  					duration: config.duration,
  					easing: config.easing,
  					lazy: config.lazy
  				};
  			} else {
  				me.render(config);
  			}
  		},
  
  		/**
  		 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
  		 * hook, in which case, plugins will not be called on `afterLayout`.
  		 * @private
  		 */
  		updateLayout: function() {
  			var me = this;
  
  			if (plugins.notify(me, 'beforeLayout') === false) {
  				return;
  			}
  
  			layouts.update(this, this.width, this.height);
  
  			/**
  			 * Provided for backward compatibility, use `afterLayout` instead.
  			 * @method IPlugin#afterScaleUpdate
  			 * @deprecated since version 2.5.0
  			 * @todo remove at version 3
  			 * @private
  			 */
  			plugins.notify(me, 'afterScaleUpdate');
  			plugins.notify(me, 'afterLayout');
  		},
  
  		/**
  		 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
  		 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
  		 * @private
  		 */
  		updateDatasets: function() {
  			var me = this;
  
  			if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
  				return;
  			}
  
  			for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
  				me.updateDataset(i);
  			}
  
  			plugins.notify(me, 'afterDatasetsUpdate');
  		},
  
  		/**
  		 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
  		 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
  		 * @private
  		 */
  		updateDataset: function(index) {
  			var me = this;
  			var meta = me.getDatasetMeta(index);
  			var args = {
  				meta: meta,
  				index: index
  			};
  
  			if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
  				return;
  			}
  
  			meta.controller.update();
  
  			plugins.notify(me, 'afterDatasetUpdate', [args]);
  		},
  
  		render: function(config) {
  			var me = this;
  
  			if (!config || typeof config !== 'object') {
  				// backwards compatibility
  				config = {
  					duration: config,
  					lazy: arguments[1]
  				};
  			}
  
  			var duration = config.duration;
  			var lazy = config.lazy;
  
  			if (plugins.notify(me, 'beforeRender') === false) {
  				return;
  			}
  
  			var animationOptions = me.options.animation;
  			var onComplete = function(animation) {
  				plugins.notify(me, 'afterRender');
  				helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
  			};
  
  			if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
  				var animation = new Animation({
  					numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
  					easing: config.easing || animationOptions.easing,
  
  					render: function(chart, animationObject) {
  						var easingFunction = helpers.easing.effects[animationObject.easing];
  						var currentStep = animationObject.currentStep;
  						var stepDecimal = currentStep / animationObject.numSteps;
  
  						chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
  					},
  
  					onAnimationProgress: animationOptions.onProgress,
  					onAnimationComplete: onComplete
  				});
  
  				animations.addAnimation(me, animation, duration, lazy);
  			} else {
  				me.draw();
  
  				// See https://github.com/chartjs/Chart.js/issues/3781
  				onComplete(new Animation({numSteps: 0, chart: me}));
  			}
  
  			return me;
  		},
  
  		draw: function(easingValue) {
  			var me = this;
  
  			me.clear();
  
  			if (helpers.isNullOrUndef(easingValue)) {
  				easingValue = 1;
  			}
  
  			me.transition(easingValue);
  
  			if (me.width <= 0 || me.height <= 0) {
  				return;
  			}
  
  			if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
  				return;
  			}
  
  			// Draw all the scales
  			helpers.each(me.boxes, function(box) {
  				box.draw(me.chartArea);
  			}, me);
  
  			if (me.scale) {
  				me.scale.draw();
  			}
  
  			me.drawDatasets(easingValue);
  			me._drawTooltip(easingValue);
  
  			plugins.notify(me, 'afterDraw', [easingValue]);
  		},
  
  		/**
  		 * @private
  		 */
  		transition: function(easingValue) {
  			var me = this;
  
  			for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
  				if (me.isDatasetVisible(i)) {
  					me.getDatasetMeta(i).controller.transition(easingValue);
  				}
  			}
  
  			me.tooltip.transition(easingValue);
  		},
  
  		/**
  		 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
  		 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
  		 * @private
  		 */
  		drawDatasets: function(easingValue) {
  			var me = this;
  
  			if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
  				return;
  			}
  
  			// Draw datasets reversed to support proper line stacking
  			for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
  				if (me.isDatasetVisible(i)) {
  					me.drawDataset(i, easingValue);
  				}
  			}
  
  			plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
  		},
  
  		/**
  		 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
  		 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
  		 * @private
  		 */
  		drawDataset: function(index, easingValue) {
  			var me = this;
  			var meta = me.getDatasetMeta(index);
  			var args = {
  				meta: meta,
  				index: index,
  				easingValue: easingValue
  			};
  
  			if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
  				return;
  			}
  
  			meta.controller.draw(easingValue);
  
  			plugins.notify(me, 'afterDatasetDraw', [args]);
  		},
  
  		/**
  		 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
  		 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
  		 * @private
  		 */
  		_drawTooltip: function(easingValue) {
  			var me = this;
  			var tooltip = me.tooltip;
  			var args = {
  				tooltip: tooltip,
  				easingValue: easingValue
  			};
  
  			if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
  				return;
  			}
  
  			tooltip.draw();
  
  			plugins.notify(me, 'afterTooltipDraw', [args]);
  		},
  
  		// Get the single element that was clicked on
  		// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
  		getElementAtEvent: function(e) {
  			return Interaction.modes.single(this, e);
  		},
  
  		getElementsAtEvent: function(e) {
  			return Interaction.modes.label(this, e, {intersect: true});
  		},
  
  		getElementsAtXAxis: function(e) {
  			return Interaction.modes['x-axis'](this, e, {intersect: true});
  		},
  
  		getElementsAtEventForMode: function(e, mode, options) {
  			var method = Interaction.modes[mode];
  			if (typeof method === 'function') {
  				return method(this, e, options);
  			}
  
  			return [];
  		},
  
  		getDatasetAtEvent: function(e) {
  			return Interaction.modes.dataset(this, e, {intersect: true});
  		},
  
  		getDatasetMeta: function(datasetIndex) {
  			var me = this;
  			var dataset = me.data.datasets[datasetIndex];
  			if (!dataset._meta) {
  				dataset._meta = {};
  			}
  
  			var meta = dataset._meta[me.id];
  			if (!meta) {
  				meta = dataset._meta[me.id] = {
  					type: null,
  					data: [],
  					dataset: null,
  					controller: null,
  					hidden: null,			// See isDatasetVisible() comment
  					xAxisID: null,
  					yAxisID: null
  				};
  			}
  
  			return meta;
  		},
  
  		getVisibleDatasetCount: function() {
  			var count = 0;
  			for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
  				if (this.isDatasetVisible(i)) {
  					count++;
  				}
  			}
  			return count;
  		},
  
  		isDatasetVisible: function(datasetIndex) {
  			var meta = this.getDatasetMeta(datasetIndex);
  
  			// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
  			// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
  			return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
  		},
  
  		generateLegend: function() {
  			return this.options.legendCallback(this);
  		},
  
  		/**
  		 * @private
  		 */
  		destroyDatasetMeta: function(datasetIndex) {
  			var id = this.id;
  			var dataset = this.data.datasets[datasetIndex];
  			var meta = dataset._meta && dataset._meta[id];
  
  			if (meta) {
  				meta.controller.destroy();
  				delete dataset._meta[id];
  			}
  		},
  
  		destroy: function() {
  			var me = this;
  			var canvas = me.canvas;
  			var i, ilen;
  
  			me.stop();
  
  			// dataset controllers need to cleanup associated data
  			for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
  				me.destroyDatasetMeta(i);
  			}
  
  			if (canvas) {
  				me.unbindEvents();
  				helpers.canvas.clear(me);
  				platform.releaseContext(me.ctx);
  				me.canvas = null;
  				me.ctx = null;
  			}
  
  			plugins.notify(me, 'destroy');
  
  			delete Chart.instances[me.id];
  		},
  
  		toBase64Image: function() {
  			return this.canvas.toDataURL.apply(this.canvas, arguments);
  		},
  
  		initToolTip: function() {
  			var me = this;
  			me.tooltip = new Tooltip({
  				_chart: me,
  				_chartInstance: me, // deprecated, backward compatibility
  				_data: me.data,
  				_options: me.options.tooltips
  			}, me);
  		},
  
  		/**
  		 * @private
  		 */
  		bindEvents: function() {
  			var me = this;
  			var listeners = me._listeners = {};
  			var listener = function() {
  				me.eventHandler.apply(me, arguments);
  			};
  
  			helpers.each(me.options.events, function(type) {
  				platform.addEventListener(me, type, listener);
  				listeners[type] = listener;
  			});
  
  			// Elements used to detect size change should not be injected for non responsive charts.
  			// See https://github.com/chartjs/Chart.js/issues/2210
  			if (me.options.responsive) {
  				listener = function() {
  					me.resize();
  				};
  
  				platform.addEventListener(me, 'resize', listener);
  				listeners.resize = listener;
  			}
  		},
  
  		/**
  		 * @private
  		 */
  		unbindEvents: function() {
  			var me = this;
  			var listeners = me._listeners;
  			if (!listeners) {
  				return;
  			}
  
  			delete me._listeners;
  			helpers.each(listeners, function(listener, type) {
  				platform.removeEventListener(me, type, listener);
  			});
  		},
  
  		updateHoverStyle: function(elements, mode, enabled) {
  			var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
  			var element, i, ilen;
  
  			for (i = 0, ilen = elements.length; i < ilen; ++i) {
  				element = elements[i];
  				if (element) {
  					this.getDatasetMeta(element._datasetIndex).controller[method](element);
  				}
  			}
  		},
  
  		/**
  		 * @private
  		 */
  		eventHandler: function(e) {
  			var me = this;
  			var tooltip = me.tooltip;
  
  			if (plugins.notify(me, 'beforeEvent', [e]) === false) {
  				return;
  			}
  
  			// Buffer any update calls so that renders do not occur
  			me._bufferedRender = true;
  			me._bufferedRequest = null;
  
  			var changed = me.handleEvent(e);
  			// for smooth tooltip animations issue #4989
  			// the tooltip should be the source of change
  			// Animation check workaround:
  			// tooltip._start will be null when tooltip isn't animating
  			if (tooltip) {
  				changed = tooltip._start
  					? tooltip.handleEvent(e)
  					: changed | tooltip.handleEvent(e);
  			}
  
  			plugins.notify(me, 'afterEvent', [e]);
  
  			var bufferedRequest = me._bufferedRequest;
  			if (bufferedRequest) {
  				// If we have an update that was triggered, we need to do a normal render
  				me.render(bufferedRequest);
  			} else if (changed && !me.animating) {
  				// If entering, leaving, or changing elements, animate the change via pivot
  				me.stop();
  
  				// We only need to render at this point. Updating will cause scales to be
  				// recomputed generating flicker & using more memory than necessary.
  				me.render({
  					duration: me.options.hover.animationDuration,
  					lazy: true
  				});
  			}
  
  			me._bufferedRender = false;
  			me._bufferedRequest = null;
  
  			return me;
  		},
  
  		/**
  		 * Handle an event
  		 * @private
  		 * @param {IEvent} event the event to handle
  		 * @return {Boolean} true if the chart needs to re-render
  		 */
  		handleEvent: function(e) {
  			var me = this;
  			var options = me.options || {};
  			var hoverOptions = options.hover;
  			var changed = false;
  
  			me.lastActive = me.lastActive || [];
  
  			// Find Active Elements for hover and tooltips
  			if (e.type === 'mouseout') {
  				me.active = [];
  			} else {
  				me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
  			}
  
  			// Invoke onHover hook
  			// Need to call with native event here to not break backwards compatibility
  			helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
  
  			if (e.type === 'mouseup' || e.type === 'click') {
  				if (options.onClick) {
  					// Use e.native here for backwards compatibility
  					options.onClick.call(me, e.native, me.active);
  				}
  			}
  
  			// Remove styling for last active (even if it may still be active)
  			if (me.lastActive.length) {
  				me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
  			}
  
  			// Built in hover styling
  			if (me.active.length && hoverOptions.mode) {
  				me.updateHoverStyle(me.active, hoverOptions.mode, true);
  			}
  
  			changed = !helpers.arrayEquals(me.active, me.lastActive);
  
  			// Remember Last Actives
  			me.lastActive = me.active;
  
  			return changed;
  		}
  	});
  
  	/**
  	 * Provided for backward compatibility, use Chart instead.
  	 * @class Chart.Controller
  	 * @deprecated since version 2.6.0
  	 * @todo remove at version 3
  	 * @private
  	 */
  	Chart.Controller = Chart;
  };
  
  },{"22":22,"23":23,"26":26,"29":29,"31":31,"32":32,"34":34,"36":36,"46":46,"49":49}],25:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  
  module.exports = function(Chart) {
  
  	var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
  
  	/**
  	 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
  	 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
  	 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
  	 */
  	function listenArrayEvents(array, listener) {
  		if (array._chartjs) {
  			array._chartjs.listeners.push(listener);
  			return;
  		}
  
  		Object.defineProperty(array, '_chartjs', {
  			configurable: true,
  			enumerable: false,
  			value: {
  				listeners: [listener]
  			}
  		});
  
  		arrayEvents.forEach(function(key) {
  			var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
  			var base = array[key];
  
  			Object.defineProperty(array, key, {
  				configurable: true,
  				enumerable: false,
  				value: function() {
  					var args = Array.prototype.slice.call(arguments);
  					var res = base.apply(this, args);
  
  					helpers.each(array._chartjs.listeners, function(object) {
  						if (typeof object[method] === 'function') {
  							object[method].apply(object, args);
  						}
  					});
  
  					return res;
  				}
  			});
  		});
  	}
  
  	/**
  	 * Removes the given array event listener and cleanup extra attached properties (such as
  	 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
  	 */
  	function unlistenArrayEvents(array, listener) {
  		var stub = array._chartjs;
  		if (!stub) {
  			return;
  		}
  
  		var listeners = stub.listeners;
  		var index = listeners.indexOf(listener);
  		if (index !== -1) {
  			listeners.splice(index, 1);
  		}
  
  		if (listeners.length > 0) {
  			return;
  		}
  
  		arrayEvents.forEach(function(key) {
  			delete array[key];
  		});
  
  		delete array._chartjs;
  	}
  
  	// Base class for all dataset controllers (line, bar, etc)
  	Chart.DatasetController = function(chart, datasetIndex) {
  		this.initialize(chart, datasetIndex);
  	};
  
  	helpers.extend(Chart.DatasetController.prototype, {
  
  		/**
  		 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
  		 * @type {Chart.core.element}
  		 */
  		datasetElementType: null,
  
  		/**
  		 * Element type used to generate a meta data (e.g. Chart.element.Point).
  		 * @type {Chart.core.element}
  		 */
  		dataElementType: null,
  
  		initialize: function(chart, datasetIndex) {
  			var me = this;
  			me.chart = chart;
  			me.index = datasetIndex;
  			me.linkScales();
  			me.addElements();
  		},
  
  		updateIndex: function(datasetIndex) {
  			this.index = datasetIndex;
  		},
  
  		linkScales: function() {
  			var me = this;
  			var meta = me.getMeta();
  			var dataset = me.getDataset();
  
  			if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
  				meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
  			}
  			if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
  				meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
  			}
  		},
  
  		getDataset: function() {
  			return this.chart.data.datasets[this.index];
  		},
  
  		getMeta: function() {
  			return this.chart.getDatasetMeta(this.index);
  		},
  
  		getScaleForId: function(scaleID) {
  			return this.chart.scales[scaleID];
  		},
  
  		reset: function() {
  			this.update(true);
  		},
  
  		/**
  		 * @private
  		 */
  		destroy: function() {
  			if (this._data) {
  				unlistenArrayEvents(this._data, this);
  			}
  		},
  
  		createMetaDataset: function() {
  			var me = this;
  			var type = me.datasetElementType;
  			return type && new type({
  				_chart: me.chart,
  				_datasetIndex: me.index
  			});
  		},
  
  		createMetaData: function(index) {
  			var me = this;
  			var type = me.dataElementType;
  			return type && new type({
  				_chart: me.chart,
  				_datasetIndex: me.index,
  				_index: index
  			});
  		},
  
  		addElements: function() {
  			var me = this;
  			var meta = me.getMeta();
  			var data = me.getDataset().data || [];
  			var metaData = meta.data;
  			var i, ilen;
  
  			for (i = 0, ilen = data.length; i < ilen; ++i) {
  				metaData[i] = metaData[i] || me.createMetaData(i);
  			}
  
  			meta.dataset = meta.dataset || me.createMetaDataset();
  		},
  
  		addElementAndReset: function(index) {
  			var element = this.createMetaData(index);
  			this.getMeta().data.splice(index, 0, element);
  			this.updateElement(element, index, true);
  		},
  
  		buildOrUpdateElements: function() {
  			var me = this;
  			var dataset = me.getDataset();
  			var data = dataset.data || (dataset.data = []);
  
  			// In order to correctly handle data addition/deletion animation (an thus simulate
  			// real-time charts), we need to monitor these data modifications and synchronize
  			// the internal meta data accordingly.
  			if (me._data !== data) {
  				if (me._data) {
  					// This case happens when the user replaced the data array instance.
  					unlistenArrayEvents(me._data, me);
  				}
  
  				listenArrayEvents(data, me);
  				me._data = data;
  			}
  
  			// Re-sync meta data in case the user replaced the data array or if we missed
  			// any updates and so make sure that we handle number of datapoints changing.
  			me.resyncElements();
  		},
  
  		update: helpers.noop,
  
  		transition: function(easingValue) {
  			var meta = this.getMeta();
  			var elements = meta.data || [];
  			var ilen = elements.length;
  			var i = 0;
  
  			for (; i < ilen; ++i) {
  				elements[i].transition(easingValue);
  			}
  
  			if (meta.dataset) {
  				meta.dataset.transition(easingValue);
  			}
  		},
  
  		draw: function() {
  			var meta = this.getMeta();
  			var elements = meta.data || [];
  			var ilen = elements.length;
  			var i = 0;
  
  			if (meta.dataset) {
  				meta.dataset.draw();
  			}
  
  			for (; i < ilen; ++i) {
  				elements[i].draw();
  			}
  		},
  
  		removeHoverStyle: function(element) {
  			helpers.merge(element._model, element.$previousStyle || {});
  			delete element.$previousStyle;
  		},
  
  		setHoverStyle: function(element) {
  			var dataset = this.chart.data.datasets[element._datasetIndex];
  			var index = element._index;
  			var custom = element.custom || {};
  			var valueOrDefault = helpers.valueAtIndexOrDefault;
  			var getHoverColor = helpers.getHoverColor;
  			var model = element._model;
  
  			element.$previousStyle = {
  				backgroundColor: model.backgroundColor,
  				borderColor: model.borderColor,
  				borderWidth: model.borderWidth
  			};
  
  			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
  			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
  			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
  		},
  
  		/**
  		 * @private
  		 */
  		resyncElements: function() {
  			var me = this;
  			var meta = me.getMeta();
  			var data = me.getDataset().data;
  			var numMeta = meta.data.length;
  			var numData = data.length;
  
  			if (numData < numMeta) {
  				meta.data.splice(numData, numMeta - numData);
  			} else if (numData > numMeta) {
  				me.insertElements(numMeta, numData - numMeta);
  			}
  		},
  
  		/**
  		 * @private
  		 */
  		insertElements: function(start, count) {
  			for (var i = 0; i < count; ++i) {
  				this.addElementAndReset(start + i);
  			}
  		},
  
  		/**
  		 * @private
  		 */
  		onDataPush: function() {
  			this.insertElements(this.getDataset().data.length - 1, arguments.length);
  		},
  
  		/**
  		 * @private
  		 */
  		onDataPop: function() {
  			this.getMeta().data.pop();
  		},
  
  		/**
  		 * @private
  		 */
  		onDataShift: function() {
  			this.getMeta().data.shift();
  		},
  
  		/**
  		 * @private
  		 */
  		onDataSplice: function(start, count) {
  			this.getMeta().data.splice(start, count);
  			this.insertElements(start, arguments.length - 2);
  		},
  
  		/**
  		 * @private
  		 */
  		onDataUnshift: function() {
  			this.insertElements(0, arguments.length);
  		}
  	});
  
  	Chart.DatasetController.extend = helpers.inherits;
  };
  
  },{"46":46}],26:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  
  module.exports = {
  	/**
  	 * @private
  	 */
  	_set: function(scope, values) {
  		return helpers.merge(this[scope] || (this[scope] = {}), values);
  	}
  };
  
  },{"46":46}],27:[function(require,module,exports){
  'use strict';
  
  var color = require(3);
  var helpers = require(46);
  
  function interpolate(start, view, model, ease) {
  	var keys = Object.keys(model);
  	var i, ilen, key, actual, origin, target, type, c0, c1;
  
  	for (i = 0, ilen = keys.length; i < ilen; ++i) {
  		key = keys[i];
  
  		target = model[key];
  
  		// if a value is added to the model after pivot() has been called, the view
  		// doesn't contain it, so let's initialize the view to the target value.
  		if (!view.hasOwnProperty(key)) {
  			view[key] = target;
  		}
  
  		actual = view[key];
  
  		if (actual === target || key[0] === '_') {
  			continue;
  		}
  
  		if (!start.hasOwnProperty(key)) {
  			start[key] = actual;
  		}
  
  		origin = start[key];
  
  		type = typeof target;
  
  		if (type === typeof origin) {
  			if (type === 'string') {
  				c0 = color(origin);
  				if (c0.valid) {
  					c1 = color(target);
  					if (c1.valid) {
  						view[key] = c1.mix(c0, ease).rgbString();
  						continue;
  					}
  				}
  			} else if (type === 'number' && isFinite(origin) && isFinite(target)) {
  				view[key] = origin + (target - origin) * ease;
  				continue;
  			}
  		}
  
  		view[key] = target;
  	}
  }
  
  var Element = function(configuration) {
  	helpers.extend(this, configuration);
  	this.initialize.apply(this, arguments);
  };
  
  helpers.extend(Element.prototype, {
  
  	initialize: function() {
  		this.hidden = false;
  	},
  
  	pivot: function() {
  		var me = this;
  		if (!me._view) {
  			me._view = helpers.clone(me._model);
  		}
  		me._start = {};
  		return me;
  	},
  
  	transition: function(ease) {
  		var me = this;
  		var model = me._model;
  		var start = me._start;
  		var view = me._view;
  
  		// No animation -> No Transition
  		if (!model || ease === 1) {
  			me._view = model;
  			me._start = null;
  			return me;
  		}
  
  		if (!view) {
  			view = me._view = {};
  		}
  
  		if (!start) {
  			start = me._start = {};
  		}
  
  		interpolate(start, view, model, ease);
  
  		return me;
  	},
  
  	tooltipPosition: function() {
  		return {
  			x: this._model.x,
  			y: this._model.y
  		};
  	},
  
  	hasValue: function() {
  		return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
  	}
  });
  
  Element.extend = helpers.inherits;
  
  module.exports = Element;
  
  },{"3":3,"46":46}],28:[function(require,module,exports){
  /* global window: false */
  /* global document: false */
  'use strict';
  
  var color = require(3);
  var defaults = require(26);
  var helpers = require(46);
  var scaleService = require(34);
  
  module.exports = function() {
  
  	// -- Basic js utility methods
  
  	helpers.configMerge = function(/* objects ... */) {
  		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
  			merger: function(key, target, source, options) {
  				var tval = target[key] || {};
  				var sval = source[key];
  
  				if (key === 'scales') {
  					// scale config merging is complex. Add our own function here for that
  					target[key] = helpers.scaleMerge(tval, sval);
  				} else if (key === 'scale') {
  					// used in polar area & radar charts since there is only one scale
  					target[key] = helpers.merge(tval, [scaleService.getScaleDefaults(sval.type), sval]);
  				} else {
  					helpers._merger(key, target, source, options);
  				}
  			}
  		});
  	};
  
  	helpers.scaleMerge = function(/* objects ... */) {
  		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
  			merger: function(key, target, source, options) {
  				if (key === 'xAxes' || key === 'yAxes') {
  					var slen = source[key].length;
  					var i, type, scale;
  
  					if (!target[key]) {
  						target[key] = [];
  					}
  
  					for (i = 0; i < slen; ++i) {
  						scale = source[key][i];
  						type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
  
  						if (i >= target[key].length) {
  							target[key].push({});
  						}
  
  						if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
  							// new/untyped scale or type changed: let's apply the new defaults
  							// then merge source scale to correctly overwrite the defaults.
  							helpers.merge(target[key][i], [scaleService.getScaleDefaults(type), scale]);
  						} else {
  							// scales type are the same
  							helpers.merge(target[key][i], scale);
  						}
  					}
  				} else {
  					helpers._merger(key, target, source, options);
  				}
  			}
  		});
  	};
  
  	helpers.where = function(collection, filterCallback) {
  		if (helpers.isArray(collection) && Array.prototype.filter) {
  			return collection.filter(filterCallback);
  		}
  		var filtered = [];
  
  		helpers.each(collection, function(item) {
  			if (filterCallback(item)) {
  				filtered.push(item);
  			}
  		});
  
  		return filtered;
  	};
  	helpers.findIndex = Array.prototype.findIndex ?
  		function(array, callback, scope) {
  			return array.findIndex(callback, scope);
  		} :
  		function(array, callback, scope) {
  			scope = scope === undefined ? array : scope;
  			for (var i = 0, ilen = array.length; i < ilen; ++i) {
  				if (callback.call(scope, array[i], i, array)) {
  					return i;
  				}
  			}
  			return -1;
  		};
  	helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
  		// Default to start of the array
  		if (helpers.isNullOrUndef(startIndex)) {
  			startIndex = -1;
  		}
  		for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
  			var currentItem = arrayToSearch[i];
  			if (filterCallback(currentItem)) {
  				return currentItem;
  			}
  		}
  	};
  	helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
  		// Default to end of the array
  		if (helpers.isNullOrUndef(startIndex)) {
  			startIndex = arrayToSearch.length;
  		}
  		for (var i = startIndex - 1; i >= 0; i--) {
  			var currentItem = arrayToSearch[i];
  			if (filterCallback(currentItem)) {
  				return currentItem;
  			}
  		}
  	};
  
  	// -- Math methods
  	helpers.isNumber = function(n) {
  		return !isNaN(parseFloat(n)) && isFinite(n);
  	};
  	helpers.almostEquals = function(x, y, epsilon) {
  		return Math.abs(x - y) < epsilon;
  	};
  	helpers.almostWhole = function(x, epsilon) {
  		var rounded = Math.round(x);
  		return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
  	};
  	helpers.max = function(array) {
  		return array.reduce(function(max, value) {
  			if (!isNaN(value)) {
  				return Math.max(max, value);
  			}
  			return max;
  		}, Number.NEGATIVE_INFINITY);
  	};
  	helpers.min = function(array) {
  		return array.reduce(function(min, value) {
  			if (!isNaN(value)) {
  				return Math.min(min, value);
  			}
  			return min;
  		}, Number.POSITIVE_INFINITY);
  	};
  	helpers.sign = Math.sign ?
  		function(x) {
  			return Math.sign(x);
  		} :
  		function(x) {
  			x = +x; // convert to a number
  			if (x === 0 || isNaN(x)) {
  				return x;
  			}
  			return x > 0 ? 1 : -1;
  		};
  	helpers.log10 = Math.log10 ?
  		function(x) {
  			return Math.log10(x);
  		} :
  		function(x) {
  			var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
  			// Check for whole powers of 10,
  			// which due to floating point rounding error should be corrected.
  			var powerOf10 = Math.round(exponent);
  			var isPowerOf10 = x === Math.pow(10, powerOf10);
  
  			return isPowerOf10 ? powerOf10 : exponent;
  		};
  	helpers.toRadians = function(degrees) {
  		return degrees * (Math.PI / 180);
  	};
  	helpers.toDegrees = function(radians) {
  		return radians * (180 / Math.PI);
  	};
  	// Gets the angle from vertical upright to the point about a centre.
  	helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
  		var distanceFromXCenter = anglePoint.x - centrePoint.x;
  		var distanceFromYCenter = anglePoint.y - centrePoint.y;
  		var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
  
  		var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
  
  		if (angle < (-0.5 * Math.PI)) {
  			angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
  		}
  
  		return {
  			angle: angle,
  			distance: radialDistanceFromCenter
  		};
  	};
  	helpers.distanceBetweenPoints = function(pt1, pt2) {
  		return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
  	};
  	helpers.aliasPixel = function(pixelWidth) {
  		return (pixelWidth % 2 === 0) ? 0 : 0.5;
  	};
  	helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
  		// Props to Rob Spencer at scaled innovation for his post on splining between points
  		// http://scaledinnovation.com/analytics/splines/aboutSplines.html
  
  		// This function must also respect "skipped" points
  
  		var previous = firstPoint.skip ? middlePoint : firstPoint;
  		var current = middlePoint;
  		var next = afterPoint.skip ? middlePoint : afterPoint;
  
  		var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
  		var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
  
  		var s01 = d01 / (d01 + d12);
  		var s12 = d12 / (d01 + d12);
  
  		// If all points are the same, s01 & s02 will be inf
  		s01 = isNaN(s01) ? 0 : s01;
  		s12 = isNaN(s12) ? 0 : s12;
  
  		var fa = t * s01; // scaling factor for triangle Ta
  		var fb = t * s12;
  
  		return {
  			previous: {
  				x: current.x - fa * (next.x - previous.x),
  				y: current.y - fa * (next.y - previous.y)
  			},
  			next: {
  				x: current.x + fb * (next.x - previous.x),
  				y: current.y + fb * (next.y - previous.y)
  			}
  		};
  	};
  	helpers.EPSILON = Number.EPSILON || 1e-14;
  	helpers.splineCurveMonotone = function(points) {
  		// This function calculates BÃ©zier control points in a similar way than |splineCurve|,
  		// but preserves monotonicity of the provided data and ensures no local extremums are added
  		// between the dataset discrete points due to the interpolation.
  		// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
  
  		var pointsWithTangents = (points || []).map(function(point) {
  			return {
  				model: point._model,
  				deltaK: 0,
  				mK: 0
  			};
  		});
  
  		// Calculate slopes (deltaK) and initialize tangents (mK)
  		var pointsLen = pointsWithTangents.length;
  		var i, pointBefore, pointCurrent, pointAfter;
  		for (i = 0; i < pointsLen; ++i) {
  			pointCurrent = pointsWithTangents[i];
  			if (pointCurrent.model.skip) {
  				continue;
  			}
  
  			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
  			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
  			if (pointAfter && !pointAfter.model.skip) {
  				var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
  
  				// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
  				pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
  			}
  
  			if (!pointBefore || pointBefore.model.skip) {
  				pointCurrent.mK = pointCurrent.deltaK;
  			} else if (!pointAfter || pointAfter.model.skip) {
  				pointCurrent.mK = pointBefore.deltaK;
  			} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
  				pointCurrent.mK = 0;
  			} else {
  				pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
  			}
  		}
  
  		// Adjust tangents to ensure monotonic properties
  		var alphaK, betaK, tauK, squaredMagnitude;
  		for (i = 0; i < pointsLen - 1; ++i) {
  			pointCurrent = pointsWithTangents[i];
  			pointAfter = pointsWithTangents[i + 1];
  			if (pointCurrent.model.skip || pointAfter.model.skip) {
  				continue;
  			}
  
  			if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
  				pointCurrent.mK = pointAfter.mK = 0;
  				continue;
  			}
  
  			alphaK = pointCurrent.mK / pointCurrent.deltaK;
  			betaK = pointAfter.mK / pointCurrent.deltaK;
  			squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
  			if (squaredMagnitude <= 9) {
  				continue;
  			}
  
  			tauK = 3 / Math.sqrt(squaredMagnitude);
  			pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
  			pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
  		}
  
  		// Compute control points
  		var deltaX;
  		for (i = 0; i < pointsLen; ++i) {
  			pointCurrent = pointsWithTangents[i];
  			if (pointCurrent.model.skip) {
  				continue;
  			}
  
  			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
  			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
  			if (pointBefore && !pointBefore.model.skip) {
  				deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
  				pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
  				pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
  			}
  			if (pointAfter && !pointAfter.model.skip) {
  				deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
  				pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
  				pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
  			}
  		}
  	};
  	helpers.nextItem = function(collection, index, loop) {
  		if (loop) {
  			return index >= collection.length - 1 ? collection[0] : collection[index + 1];
  		}
  		return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
  	};
  	helpers.previousItem = function(collection, index, loop) {
  		if (loop) {
  			return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
  		}
  		return index <= 0 ? collection[0] : collection[index - 1];
  	};
  	// Implementation of the nice number algorithm used in determining where axis labels will go
  	helpers.niceNum = function(range, round) {
  		var exponent = Math.floor(helpers.log10(range));
  		var fraction = range / Math.pow(10, exponent);
  		var niceFraction;
  
  		if (round) {
  			if (fraction < 1.5) {
  				niceFraction = 1;
  			} else if (fraction < 3) {
  				niceFraction = 2;
  			} else if (fraction < 7) {
  				niceFraction = 5;
  			} else {
  				niceFraction = 10;
  			}
  		} else if (fraction <= 1.0) {
  			niceFraction = 1;
  		} else if (fraction <= 2) {
  			niceFraction = 2;
  		} else if (fraction <= 5) {
  			niceFraction = 5;
  		} else {
  			niceFraction = 10;
  		}
  
  		return niceFraction * Math.pow(10, exponent);
  	};
  	// Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
  	helpers.requestAnimFrame = (function() {
  		if (typeof window === 'undefined') {
  			return function(callback) {
  				callback();
  			};
  		}
  		return window.requestAnimationFrame ||
  			window.webkitRequestAnimationFrame ||
  			window.mozRequestAnimationFrame ||
  			window.oRequestAnimationFrame ||
  			window.msRequestAnimationFrame ||
  			function(callback) {
  				return window.setTimeout(callback, 1000 / 60);
  			};
  	}());
  	// -- DOM methods
  	helpers.getRelativePosition = function(evt, chart) {
  		var mouseX, mouseY;
  		var e = evt.originalEvent || evt;
  		var canvas = evt.target || evt.srcElement;
  		var boundingRect = canvas.getBoundingClientRect();
  
  		var touches = e.touches;
  		if (touches && touches.length > 0) {
  			mouseX = touches[0].clientX;
  			mouseY = touches[0].clientY;
  
  		} else {
  			mouseX = e.clientX;
  			mouseY = e.clientY;
  		}
  
  		// Scale mouse coordinates into canvas coordinates
  		// by following the pattern laid out by 'jerryj' in the comments of
  		// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
  		var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
  		var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
  		var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
  		var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
  		var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
  		var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
  
  		// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
  		// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
  		mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
  		mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
  
  		return {
  			x: mouseX,
  			y: mouseY
  		};
  
  	};
  
  	// Private helper function to convert max-width/max-height values that may be percentages into a number
  	function parseMaxStyle(styleValue, node, parentProperty) {
  		var valueInPixels;
  		if (typeof styleValue === 'string') {
  			valueInPixels = parseInt(styleValue, 10);
  
  			if (styleValue.indexOf('%') !== -1) {
  				// percentage * size in dimension
  				valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
  			}
  		} else {
  			valueInPixels = styleValue;
  		}
  
  		return valueInPixels;
  	}
  
  	/**
  	 * Returns if the given value contains an effective constraint.
  	 * @private
  	 */
  	function isConstrainedValue(value) {
  		return value !== undefined && value !== null && value !== 'none';
  	}
  
  	// Private helper to get a constraint dimension
  	// @param domNode : the node to check the constraint on
  	// @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
  	// @param percentageProperty : property of parent to use when calculating width as a percentage
  	// @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
  	function getConstraintDimension(domNode, maxStyle, percentageProperty) {
  		var view = document.defaultView;
  		var parentNode = helpers._getParentNode(domNode);
  		var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
  		var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
  		var hasCNode = isConstrainedValue(constrainedNode);
  		var hasCContainer = isConstrainedValue(constrainedContainer);
  		var infinity = Number.POSITIVE_INFINITY;
  
  		if (hasCNode || hasCContainer) {
  			return Math.min(
  				hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
  				hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
  		}
  
  		return 'none';
  	}
  	// returns Number or undefined if no constraint
  	helpers.getConstraintWidth = function(domNode) {
  		return getConstraintDimension(domNode, 'max-width', 'clientWidth');
  	};
  	// returns Number or undefined if no constraint
  	helpers.getConstraintHeight = function(domNode) {
  		return getConstraintDimension(domNode, 'max-height', 'clientHeight');
  	};
  	/**
  	 * @private
   	 */
  	helpers._calculatePadding = function(container, padding, parentDimension) {
  		padding = helpers.getStyle(container, padding);
  
  		return padding.indexOf('%') > -1 ? parentDimension / parseInt(padding, 10) : parseInt(padding, 10);
  	};
  	/**
  	 * @private
  	 */
  	helpers._getParentNode = function(domNode) {
  		var parent = domNode.parentNode;
  		if (parent && parent.host) {
  			parent = parent.host;
  		}
  		return parent;
  	};
  	helpers.getMaximumWidth = function(domNode) {
  		var container = helpers._getParentNode(domNode);
  		if (!container) {
  			return domNode.clientWidth;
  		}
  
  		var clientWidth = container.clientWidth;
  		var paddingLeft = helpers._calculatePadding(container, 'padding-left', clientWidth);
  		var paddingRight = helpers._calculatePadding(container, 'padding-right', clientWidth);
  
  		var w = clientWidth - paddingLeft - paddingRight;
  		var cw = helpers.getConstraintWidth(domNode);
  		return isNaN(cw) ? w : Math.min(w, cw);
  	};
  	helpers.getMaximumHeight = function(domNode) {
  		var container = helpers._getParentNode(domNode);
  		if (!container) {
  			return domNode.clientHeight;
  		}
  
  		var clientHeight = container.clientHeight;
  		var paddingTop = helpers._calculatePadding(container, 'padding-top', clientHeight);
  		var paddingBottom = helpers._calculatePadding(container, 'padding-bottom', clientHeight);
  
  		var h = clientHeight - paddingTop - paddingBottom;
  		var ch = helpers.getConstraintHeight(domNode);
  		return isNaN(ch) ? h : Math.min(h, ch);
  	};
  	helpers.getStyle = function(el, property) {
  		return el.currentStyle ?
  			el.currentStyle[property] :
  			document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
  	};
  	helpers.retinaScale = function(chart, forceRatio) {
  		var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
  		if (pixelRatio === 1) {
  			return;
  		}
  
  		var canvas = chart.canvas;
  		var height = chart.height;
  		var width = chart.width;
  
  		canvas.height = height * pixelRatio;
  		canvas.width = width * pixelRatio;
  		chart.ctx.scale(pixelRatio, pixelRatio);
  
  		// If no style has been set on the canvas, the render size is used as display size,
  		// making the chart visually bigger, so let's enforce it to the "correct" values.
  		// See https://github.com/chartjs/Chart.js/issues/3575
  		if (!canvas.style.height && !canvas.style.width) {
  			canvas.style.height = height + 'px';
  			canvas.style.width = width + 'px';
  		}
  	};
  	// -- Canvas methods
  	helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
  		return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
  	};
  	helpers.longestText = function(ctx, font, arrayOfThings, cache) {
  		cache = cache || {};
  		var data = cache.data = cache.data || {};
  		var gc = cache.garbageCollect = cache.garbageCollect || [];
  
  		if (cache.font !== font) {
  			data = cache.data = {};
  			gc = cache.garbageCollect = [];
  			cache.font = font;
  		}
  
  		ctx.font = font;
  		var longest = 0;
  		helpers.each(arrayOfThings, function(thing) {
  			// Undefined strings and arrays should not be measured
  			if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
  				longest = helpers.measureText(ctx, data, gc, longest, thing);
  			} else if (helpers.isArray(thing)) {
  				// if it is an array lets measure each element
  				// to do maybe simplify this function a bit so we can do this more recursively?
  				helpers.each(thing, function(nestedThing) {
  					// Undefined strings and arrays should not be measured
  					if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
  						longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
  					}
  				});
  			}
  		});
  
  		var gcLen = gc.length / 2;
  		if (gcLen > arrayOfThings.length) {
  			for (var i = 0; i < gcLen; i++) {
  				delete data[gc[i]];
  			}
  			gc.splice(0, gcLen);
  		}
  		return longest;
  	};
  	helpers.measureText = function(ctx, data, gc, longest, string) {
  		var textWidth = data[string];
  		if (!textWidth) {
  			textWidth = data[string] = ctx.measureText(string).width;
  			gc.push(string);
  		}
  		if (textWidth > longest) {
  			longest = textWidth;
  		}
  		return longest;
  	};
  	helpers.numberOfLabelLines = function(arrayOfThings) {
  		var numberOfLines = 1;
  		helpers.each(arrayOfThings, function(thing) {
  			if (helpers.isArray(thing)) {
  				if (thing.length > numberOfLines) {
  					numberOfLines = thing.length;
  				}
  			}
  		});
  		return numberOfLines;
  	};
  
  	helpers.color = !color ?
  		function(value) {
  			console.error('Color.js not found!');
  			return value;
  		} :
  		function(value) {
  			/* global CanvasGradient */
  			if (value instanceof CanvasGradient) {
  				value = defaults.global.defaultColor;
  			}
  
  			return color(value);
  		};
  
  	helpers.getHoverColor = function(colorValue) {
  		/* global CanvasPattern */
  		return (colorValue instanceof CanvasPattern) ?
  			colorValue :
  			helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
  	};
  };
  
  },{"26":26,"3":3,"34":34,"46":46}],29:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  
  /**
   * Helper function to get relative position for an event
   * @param {Event|IEvent} event - The event to get the position for
   * @param {Chart} chart - The chart
   * @returns {Point} the event position
   */
  function getRelativePosition(e, chart) {
  	if (e.native) {
  		return {
  			x: e.x,
  			y: e.y
  		};
  	}
  
  	return helpers.getRelativePosition(e, chart);
  }
  
  /**
   * Helper function to traverse all of the visible elements in the chart
   * @param chart {chart} the chart
   * @param handler {Function} the callback to execute for each visible item
   */
  function parseVisibleItems(chart, handler) {
  	var datasets = chart.data.datasets;
  	var meta, i, j, ilen, jlen;
  
  	for (i = 0, ilen = datasets.length; i < ilen; ++i) {
  		if (!chart.isDatasetVisible(i)) {
  			continue;
  		}
  
  		meta = chart.getDatasetMeta(i);
  		for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
  			var element = meta.data[j];
  			if (!element._view.skip) {
  				handler(element);
  			}
  		}
  	}
  }
  
  /**
   * Helper function to get the items that intersect the event position
   * @param items {ChartElement[]} elements to filter
   * @param position {Point} the point to be nearest to
   * @return {ChartElement[]} the nearest items
   */
  function getIntersectItems(chart, position) {
  	var elements = [];
  
  	parseVisibleItems(chart, function(element) {
  		if (element.inRange(position.x, position.y)) {
  			elements.push(element);
  		}
  	});
  
  	return elements;
  }
  
  /**
   * Helper function to get the items nearest to the event position considering all visible items in teh chart
   * @param chart {Chart} the chart to look at elements from
   * @param position {Point} the point to be nearest to
   * @param intersect {Boolean} if true, only consider items that intersect the position
   * @param distanceMetric {Function} function to provide the distance between points
   * @return {ChartElement[]} the nearest items
   */
  function getNearestItems(chart, position, intersect, distanceMetric) {
  	var minDistance = Number.POSITIVE_INFINITY;
  	var nearestItems = [];
  
  	parseVisibleItems(chart, function(element) {
  		if (intersect && !element.inRange(position.x, position.y)) {
  			return;
  		}
  
  		var center = element.getCenterPoint();
  		var distance = distanceMetric(position, center);
  
  		if (distance < minDistance) {
  			nearestItems = [element];
  			minDistance = distance;
  		} else if (distance === minDistance) {
  			// Can have multiple items at the same distance in which case we sort by size
  			nearestItems.push(element);
  		}
  	});
  
  	return nearestItems;
  }
  
  /**
   * Get a distance metric function for two points based on the
   * axis mode setting
   * @param {String} axis the axis mode. x|y|xy
   */
  function getDistanceMetricForAxis(axis) {
  	var useX = axis.indexOf('x') !== -1;
  	var useY = axis.indexOf('y') !== -1;
  
  	return function(pt1, pt2) {
  		var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
  		var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
  		return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
  	};
  }
  
  function indexMode(chart, e, options) {
  	var position = getRelativePosition(e, chart);
  	// Default axis for index mode is 'x' to match old behaviour
  	options.axis = options.axis || 'x';
  	var distanceMetric = getDistanceMetricForAxis(options.axis);
  	var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
  	var elements = [];
  
  	if (!items.length) {
  		return [];
  	}
  
  	chart.data.datasets.forEach(function(dataset, datasetIndex) {
  		if (chart.isDatasetVisible(datasetIndex)) {
  			var meta = chart.getDatasetMeta(datasetIndex);
  			var element = meta.data[items[0]._index];
  
  			// don't count items that are skipped (null data)
  			if (element && !element._view.skip) {
  				elements.push(element);
  			}
  		}
  	});
  
  	return elements;
  }
  
  /**
   * @interface IInteractionOptions
   */
  /**
   * If true, only consider items that intersect the point
   * @name IInterfaceOptions#boolean
   * @type Boolean
   */
  
  /**
   * Contains interaction related functions
   * @namespace Chart.Interaction
   */
  module.exports = {
  	// Helper function for different modes
  	modes: {
  		single: function(chart, e) {
  			var position = getRelativePosition(e, chart);
  			var elements = [];
  
  			parseVisibleItems(chart, function(element) {
  				if (element.inRange(position.x, position.y)) {
  					elements.push(element);
  					return elements;
  				}
  			});
  
  			return elements.slice(0, 1);
  		},
  
  		/**
  		 * @function Chart.Interaction.modes.label
  		 * @deprecated since version 2.4.0
  		 * @todo remove at version 3
  		 * @private
  		 */
  		label: indexMode,
  
  		/**
  		 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
  		 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
  		 * @function Chart.Interaction.modes.index
  		 * @since v2.4.0
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @param options {IInteractionOptions} options to use during interaction
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		index: indexMode,
  
  		/**
  		 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
  		 * If the options.intersect is false, we find the nearest item and return the items in that dataset
  		 * @function Chart.Interaction.modes.dataset
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @param options {IInteractionOptions} options to use during interaction
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		dataset: function(chart, e, options) {
  			var position = getRelativePosition(e, chart);
  			options.axis = options.axis || 'xy';
  			var distanceMetric = getDistanceMetricForAxis(options.axis);
  			var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
  
  			if (items.length > 0) {
  				items = chart.getDatasetMeta(items[0]._datasetIndex).data;
  			}
  
  			return items;
  		},
  
  		/**
  		 * @function Chart.Interaction.modes.x-axis
  		 * @deprecated since version 2.4.0. Use index mode and intersect == true
  		 * @todo remove at version 3
  		 * @private
  		 */
  		'x-axis': function(chart, e) {
  			return indexMode(chart, e, {intersect: false});
  		},
  
  		/**
  		 * Point mode returns all elements that hit test based on the event position
  		 * of the event
  		 * @function Chart.Interaction.modes.intersect
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		point: function(chart, e) {
  			var position = getRelativePosition(e, chart);
  			return getIntersectItems(chart, position);
  		},
  
  		/**
  		 * nearest mode returns the element closest to the point
  		 * @function Chart.Interaction.modes.intersect
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @param options {IInteractionOptions} options to use
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		nearest: function(chart, e, options) {
  			var position = getRelativePosition(e, chart);
  			options.axis = options.axis || 'xy';
  			var distanceMetric = getDistanceMetricForAxis(options.axis);
  			var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);
  
  			// We have multiple items at the same distance from the event. Now sort by smallest
  			if (nearestItems.length > 1) {
  				nearestItems.sort(function(a, b) {
  					var sizeA = a.getArea();
  					var sizeB = b.getArea();
  					var ret = sizeA - sizeB;
  
  					if (ret === 0) {
  						// if equal sort by dataset index
  						ret = a._datasetIndex - b._datasetIndex;
  					}
  
  					return ret;
  				});
  			}
  
  			// Return only 1 item
  			return nearestItems.slice(0, 1);
  		},
  
  		/**
  		 * x mode returns the elements that hit-test at the current x coordinate
  		 * @function Chart.Interaction.modes.x
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @param options {IInteractionOptions} options to use
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		x: function(chart, e, options) {
  			var position = getRelativePosition(e, chart);
  			var items = [];
  			var intersectsItem = false;
  
  			parseVisibleItems(chart, function(element) {
  				if (element.inXRange(position.x)) {
  					items.push(element);
  				}
  
  				if (element.inRange(position.x, position.y)) {
  					intersectsItem = true;
  				}
  			});
  
  			// If we want to trigger on an intersect and we don't have any items
  			// that intersect the position, return nothing
  			if (options.intersect && !intersectsItem) {
  				items = [];
  			}
  			return items;
  		},
  
  		/**
  		 * y mode returns the elements that hit-test at the current y coordinate
  		 * @function Chart.Interaction.modes.y
  		 * @param chart {chart} the chart we are returning items from
  		 * @param e {Event} the event we are find things at
  		 * @param options {IInteractionOptions} options to use
  		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
  		 */
  		y: function(chart, e, options) {
  			var position = getRelativePosition(e, chart);
  			var items = [];
  			var intersectsItem = false;
  
  			parseVisibleItems(chart, function(element) {
  				if (element.inYRange(position.y)) {
  					items.push(element);
  				}
  
  				if (element.inRange(position.x, position.y)) {
  					intersectsItem = true;
  				}
  			});
  
  			// If we want to trigger on an intersect and we don't have any items
  			// that intersect the position, return nothing
  			if (options.intersect && !intersectsItem) {
  				items = [];
  			}
  			return items;
  		}
  	}
  };
  
  },{"46":46}],30:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  
  defaults._set('global', {
  	responsive: true,
  	responsiveAnimationDuration: 0,
  	maintainAspectRatio: true,
  	events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
  	hover: {
  		onHover: null,
  		mode: 'nearest',
  		intersect: true,
  		animationDuration: 400
  	},
  	onClick: null,
  	defaultColor: 'rgba(0,0,0,0.1)',
  	defaultFontColor: '#666',
  	defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
  	defaultFontSize: 12,
  	defaultFontStyle: 'normal',
  	showLines: true,
  
  	// Element defaults defined in element extensions
  	elements: {},
  
  	// Layout options such as padding
  	layout: {
  		padding: {
  			top: 0,
  			right: 0,
  			bottom: 0,
  			left: 0
  		}
  	}
  });
  
  module.exports = function() {
  
  	// Occupy the global variable of Chart, and create a simple base class
  	var Chart = function(item, config) {
  		this.construct(item, config);
  		return this;
  	};
  
  	Chart.Chart = Chart;
  
  	return Chart;
  };
  
  },{"26":26}],31:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  
  function filterByPosition(array, position) {
  	return helpers.where(array, function(v) {
  		return v.position === position;
  	});
  }
  
  function sortByWeight(array, reverse) {
  	array.forEach(function(v, i) {
  		v._tmpIndex_ = i;
  		return v;
  	});
  	array.sort(function(a, b) {
  		var v0 = reverse ? b : a;
  		var v1 = reverse ? a : b;
  		return v0.weight === v1.weight ?
  			v0._tmpIndex_ - v1._tmpIndex_ :
  			v0.weight - v1.weight;
  	});
  	array.forEach(function(v) {
  		delete v._tmpIndex_;
  	});
  }
  
  /**
   * @interface ILayoutItem
   * @prop {String} position - The position of the item in the chart layout. Possible values are
   * 'left', 'top', 'right', 'bottom', and 'chartArea'
   * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
   * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
   * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
   * @prop {Function} update - Takes two parameters: width and height. Returns size of item
   * @prop {Function} getPadding -  Returns an object with padding on the edges
   * @prop {Number} width - Width of item. Must be valid after update()
   * @prop {Number} height - Height of item. Must be valid after update()
   * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
   * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
   * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
   * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
   */
  
  // The layout service is very self explanatory.  It's responsible for the layout within a chart.
  // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
  // It is this service's responsibility of carrying out that layout.
  module.exports = {
  	defaults: {},
  
  	/**
  	 * Register a box to a chart.
  	 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
  	 * @param {Chart} chart - the chart to use
  	 * @param {ILayoutItem} item - the item to add to be layed out
  	 */
  	addBox: function(chart, item) {
  		if (!chart.boxes) {
  			chart.boxes = [];
  		}
  
  		// initialize item with default values
  		item.fullWidth = item.fullWidth || false;
  		item.position = item.position || 'top';
  		item.weight = item.weight || 0;
  
  		chart.boxes.push(item);
  	},
  
  	/**
  	 * Remove a layoutItem from a chart
  	 * @param {Chart} chart - the chart to remove the box from
  	 * @param {Object} layoutItem - the item to remove from the layout
  	 */
  	removeBox: function(chart, layoutItem) {
  		var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
  		if (index !== -1) {
  			chart.boxes.splice(index, 1);
  		}
  	},
  
  	/**
  	 * Sets (or updates) options on the given `item`.
  	 * @param {Chart} chart - the chart in which the item lives (or will be added to)
  	 * @param {Object} item - the item to configure with the given options
  	 * @param {Object} options - the new item options.
  	 */
  	configure: function(chart, item, options) {
  		var props = ['fullWidth', 'position', 'weight'];
  		var ilen = props.length;
  		var i = 0;
  		var prop;
  
  		for (; i < ilen; ++i) {
  			prop = props[i];
  			if (options.hasOwnProperty(prop)) {
  				item[prop] = options[prop];
  			}
  		}
  	},
  
  	/**
  	 * Fits boxes of the given chart into the given size by having each box measure itself
  	 * then running a fitting algorithm
  	 * @param {Chart} chart - the chart
  	 * @param {Number} width - the width to fit into
  	 * @param {Number} height - the height to fit into
  	 */
  	update: function(chart, width, height) {
  		if (!chart) {
  			return;
  		}
  
  		var layoutOptions = chart.options.layout || {};
  		var padding = helpers.options.toPadding(layoutOptions.padding);
  		var leftPadding = padding.left;
  		var rightPadding = padding.right;
  		var topPadding = padding.top;
  		var bottomPadding = padding.bottom;
  
  		var leftBoxes = filterByPosition(chart.boxes, 'left');
  		var rightBoxes = filterByPosition(chart.boxes, 'right');
  		var topBoxes = filterByPosition(chart.boxes, 'top');
  		var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
  		var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
  
  		// Sort boxes by weight. A higher weight is further away from the chart area
  		sortByWeight(leftBoxes, true);
  		sortByWeight(rightBoxes, false);
  		sortByWeight(topBoxes, true);
  		sortByWeight(bottomBoxes, false);
  
  		// Essentially we now have any number of boxes on each of the 4 sides.
  		// Our canvas looks like the following.
  		// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
  		// B1 is the bottom axis
  		// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
  		// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
  		// an error will be thrown.
  		//
  		// |----------------------------------------------------|
  		// |                  T1 (Full Width)                   |
  		// |----------------------------------------------------|
  		// |    |    |                 T2                  |    |
  		// |    |----|-------------------------------------|----|
  		// |    |    | C1 |                           | C2 |    |
  		// |    |    |----|                           |----|    |
  		// |    |    |                                     |    |
  		// | L1 | L2 |           ChartArea (C0)            | R1 |
  		// |    |    |                                     |    |
  		// |    |    |----|                           |----|    |
  		// |    |    | C3 |                           | C4 |    |
  		// |    |----|-------------------------------------|----|
  		// |    |    |                 B1                  |    |
  		// |----------------------------------------------------|
  		// |                  B2 (Full Width)                   |
  		// |----------------------------------------------------|
  		//
  		// What we do to find the best sizing, we do the following
  		// 1. Determine the minimum size of the chart area.
  		// 2. Split the remaining width equally between each vertical axis
  		// 3. Split the remaining height equally between each horizontal axis
  		// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
  		// 5. Adjust the sizes of each axis based on it's minimum reported size.
  		// 6. Refit each axis
  		// 7. Position each axis in the final location
  		// 8. Tell the chart the final location of the chart area
  		// 9. Tell any axes that overlay the chart area the positions of the chart area
  
  		// Step 1
  		var chartWidth = width - leftPadding - rightPadding;
  		var chartHeight = height - topPadding - bottomPadding;
  		var chartAreaWidth = chartWidth / 2; // min 50%
  		var chartAreaHeight = chartHeight / 2; // min 50%
  
  		// Step 2
  		var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
  
  		// Step 3
  		var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
  
  		// Step 4
  		var maxChartAreaWidth = chartWidth;
  		var maxChartAreaHeight = chartHeight;
  		var minBoxSizes = [];
  
  		function getMinimumBoxSize(box) {
  			var minSize;
  			var isHorizontal = box.isHorizontal();
  
  			if (isHorizontal) {
  				minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
  				maxChartAreaHeight -= minSize.height;
  			} else {
  				minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
  				maxChartAreaWidth -= minSize.width;
  			}
  
  			minBoxSizes.push({
  				horizontal: isHorizontal,
  				minSize: minSize,
  				box: box,
  			});
  		}
  
  		helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
  
  		// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
  		var maxHorizontalLeftPadding = 0;
  		var maxHorizontalRightPadding = 0;
  		var maxVerticalTopPadding = 0;
  		var maxVerticalBottomPadding = 0;
  
  		helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
  			if (horizontalBox.getPadding) {
  				var boxPadding = horizontalBox.getPadding();
  				maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
  				maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
  			}
  		});
  
  		helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
  			if (verticalBox.getPadding) {
  				var boxPadding = verticalBox.getPadding();
  				maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
  				maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
  			}
  		});
  
  		// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
  		// be if the axes are drawn at their minimum sizes.
  		// Steps 5 & 6
  		var totalLeftBoxesWidth = leftPadding;
  		var totalRightBoxesWidth = rightPadding;
  		var totalTopBoxesHeight = topPadding;
  		var totalBottomBoxesHeight = bottomPadding;
  
  		// Function to fit a box
  		function fitBox(box) {
  			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
  				return minBox.box === box;
  			});
  
  			if (minBoxSize) {
  				if (box.isHorizontal()) {
  					var scaleMargin = {
  						left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
  						right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
  						top: 0,
  						bottom: 0
  					};
  
  					// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
  					// on the margin. Sometimes they need to increase in size slightly
  					box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
  				} else {
  					box.update(minBoxSize.minSize.width, maxChartAreaHeight);
  				}
  			}
  		}
  
  		// Update, and calculate the left and right margins for the horizontal boxes
  		helpers.each(leftBoxes.concat(rightBoxes), fitBox);
  
  		helpers.each(leftBoxes, function(box) {
  			totalLeftBoxesWidth += box.width;
  		});
  
  		helpers.each(rightBoxes, function(box) {
  			totalRightBoxesWidth += box.width;
  		});
  
  		// Set the Left and Right margins for the horizontal boxes
  		helpers.each(topBoxes.concat(bottomBoxes), fitBox);
  
  		// Figure out how much margin is on the top and bottom of the vertical boxes
  		helpers.each(topBoxes, function(box) {
  			totalTopBoxesHeight += box.height;
  		});
  
  		helpers.each(bottomBoxes, function(box) {
  			totalBottomBoxesHeight += box.height;
  		});
  
  		function finalFitVerticalBox(box) {
  			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
  				return minSize.box === box;
  			});
  
  			var scaleMargin = {
  				left: 0,
  				right: 0,
  				top: totalTopBoxesHeight,
  				bottom: totalBottomBoxesHeight
  			};
  
  			if (minBoxSize) {
  				box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
  			}
  		}
  
  		// Let the left layout know the final margin
  		helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
  
  		// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
  		totalLeftBoxesWidth = leftPadding;
  		totalRightBoxesWidth = rightPadding;
  		totalTopBoxesHeight = topPadding;
  		totalBottomBoxesHeight = bottomPadding;
  
  		helpers.each(leftBoxes, function(box) {
  			totalLeftBoxesWidth += box.width;
  		});
  
  		helpers.each(rightBoxes, function(box) {
  			totalRightBoxesWidth += box.width;
  		});
  
  		helpers.each(topBoxes, function(box) {
  			totalTopBoxesHeight += box.height;
  		});
  		helpers.each(bottomBoxes, function(box) {
  			totalBottomBoxesHeight += box.height;
  		});
  
  		// We may be adding some padding to account for rotated x axis labels
  		var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
  		totalLeftBoxesWidth += leftPaddingAddition;
  		totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
  
  		var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
  		totalTopBoxesHeight += topPaddingAddition;
  		totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
  
  		// Figure out if our chart area changed. This would occur if the dataset layout label rotation
  		// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
  		// without calling `fit` again
  		var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
  		var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
  
  		if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
  			helpers.each(leftBoxes, function(box) {
  				box.height = newMaxChartAreaHeight;
  			});
  
  			helpers.each(rightBoxes, function(box) {
  				box.height = newMaxChartAreaHeight;
  			});
  
  			helpers.each(topBoxes, function(box) {
  				if (!box.fullWidth) {
  					box.width = newMaxChartAreaWidth;
  				}
  			});
  
  			helpers.each(bottomBoxes, function(box) {
  				if (!box.fullWidth) {
  					box.width = newMaxChartAreaWidth;
  				}
  			});
  
  			maxChartAreaHeight = newMaxChartAreaHeight;
  			maxChartAreaWidth = newMaxChartAreaWidth;
  		}
  
  		// Step 7 - Position the boxes
  		var left = leftPadding + leftPaddingAddition;
  		var top = topPadding + topPaddingAddition;
  
  		function placeBox(box) {
  			if (box.isHorizontal()) {
  				box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
  				box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
  				box.top = top;
  				box.bottom = top + box.height;
  
  				// Move to next point
  				top = box.bottom;
  
  			} else {
  
  				box.left = left;
  				box.right = left + box.width;
  				box.top = totalTopBoxesHeight;
  				box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
  
  				// Move to next point
  				left = box.right;
  			}
  		}
  
  		helpers.each(leftBoxes.concat(topBoxes), placeBox);
  
  		// Account for chart width and height
  		left += maxChartAreaWidth;
  		top += maxChartAreaHeight;
  
  		helpers.each(rightBoxes, placeBox);
  		helpers.each(bottomBoxes, placeBox);
  
  		// Step 8
  		chart.chartArea = {
  			left: totalLeftBoxesWidth,
  			top: totalTopBoxesHeight,
  			right: totalLeftBoxesWidth + maxChartAreaWidth,
  			bottom: totalTopBoxesHeight + maxChartAreaHeight
  		};
  
  		// Step 9
  		helpers.each(chartAreaBoxes, function(box) {
  			box.left = chart.chartArea.left;
  			box.top = chart.chartArea.top;
  			box.right = chart.chartArea.right;
  			box.bottom = chart.chartArea.bottom;
  
  			box.update(maxChartAreaWidth, maxChartAreaHeight);
  		});
  	}
  };
  
  },{"46":46}],32:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var helpers = require(46);
  
  defaults._set('global', {
  	plugins: {}
  });
  
  /**
   * The plugin service singleton
   * @namespace Chart.plugins
   * @since 2.1.0
   */
  module.exports = {
  	/**
  	 * Globally registered plugins.
  	 * @private
  	 */
  	_plugins: [],
  
  	/**
  	 * This identifier is used to invalidate the descriptors cache attached to each chart
  	 * when a global plugin is registered or unregistered. In this case, the cache ID is
  	 * incremented and descriptors are regenerated during following API calls.
  	 * @private
  	 */
  	_cacheId: 0,
  
  	/**
  	 * Registers the given plugin(s) if not already registered.
  	 * @param {Array|Object} plugins plugin instance(s).
  	 */
  	register: function(plugins) {
  		var p = this._plugins;
  		([]).concat(plugins).forEach(function(plugin) {
  			if (p.indexOf(plugin) === -1) {
  				p.push(plugin);
  			}
  		});
  
  		this._cacheId++;
  	},
  
  	/**
  	 * Unregisters the given plugin(s) only if registered.
  	 * @param {Array|Object} plugins plugin instance(s).
  	 */
  	unregister: function(plugins) {
  		var p = this._plugins;
  		([]).concat(plugins).forEach(function(plugin) {
  			var idx = p.indexOf(plugin);
  			if (idx !== -1) {
  				p.splice(idx, 1);
  			}
  		});
  
  		this._cacheId++;
  	},
  
  	/**
  	 * Remove all registered plugins.
  	 * @since 2.1.5
  	 */
  	clear: function() {
  		this._plugins = [];
  		this._cacheId++;
  	},
  
  	/**
  	 * Returns the number of registered plugins?
  	 * @returns {Number}
  	 * @since 2.1.5
  	 */
  	count: function() {
  		return this._plugins.length;
  	},
  
  	/**
  	 * Returns all registered plugin instances.
  	 * @returns {Array} array of plugin objects.
  	 * @since 2.1.5
  	 */
  	getAll: function() {
  		return this._plugins;
  	},
  
  	/**
  	 * Calls enabled plugins for `chart` on the specified hook and with the given args.
  	 * This method immediately returns as soon as a plugin explicitly returns false. The
  	 * returned value can be used, for instance, to interrupt the current action.
  	 * @param {Object} chart - The chart instance for which plugins should be called.
  	 * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
  	 * @param {Array} [args] - Extra arguments to apply to the hook call.
  	 * @returns {Boolean} false if any of the plugins return false, else returns true.
  	 */
  	notify: function(chart, hook, args) {
  		var descriptors = this.descriptors(chart);
  		var ilen = descriptors.length;
  		var i, descriptor, plugin, params, method;
  
  		for (i = 0; i < ilen; ++i) {
  			descriptor = descriptors[i];
  			plugin = descriptor.plugin;
  			method = plugin[hook];
  			if (typeof method === 'function') {
  				params = [chart].concat(args || []);
  				params.push(descriptor.options);
  				if (method.apply(plugin, params) === false) {
  					return false;
  				}
  			}
  		}
  
  		return true;
  	},
  
  	/**
  	 * Returns descriptors of enabled plugins for the given chart.
  	 * @returns {Array} [{ plugin, options }]
  	 * @private
  	 */
  	descriptors: function(chart) {
  		var cache = chart.$plugins || (chart.$plugins = {});
  		if (cache.id === this._cacheId) {
  			return cache.descriptors;
  		}
  
  		var plugins = [];
  		var descriptors = [];
  		var config = (chart && chart.config) || {};
  		var options = (config.options && config.options.plugins) || {};
  
  		this._plugins.concat(config.plugins || []).forEach(function(plugin) {
  			var idx = plugins.indexOf(plugin);
  			if (idx !== -1) {
  				return;
  			}
  
  			var id = plugin.id;
  			var opts = options[id];
  			if (opts === false) {
  				return;
  			}
  
  			if (opts === true) {
  				opts = helpers.clone(defaults.global.plugins[id]);
  			}
  
  			plugins.push(plugin);
  			descriptors.push({
  				plugin: plugin,
  				options: opts || {}
  			});
  		});
  
  		cache.descriptors = descriptors;
  		cache.id = this._cacheId;
  		return descriptors;
  	},
  
  	/**
  	 * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
  	 * but in some cases, this reference can be changed by the user when updating options.
  	 * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
  	 * @private
  	 */
  	_invalidate: function(chart) {
  		delete chart.$plugins;
  	}
  };
  
  /**
   * Plugin extension hooks.
   * @interface IPlugin
   * @since 2.1.0
   */
  /**
   * @method IPlugin#beforeInit
   * @desc Called before initializing `chart`.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#afterInit
   * @desc Called after `chart` has been initialized and before the first update.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeUpdate
   * @desc Called before updating `chart`. If any plugin returns `false`, the update
   * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart update.
   */
  /**
   * @method IPlugin#afterUpdate
   * @desc Called after `chart` has been updated and before rendering. Note that this
   * hook will not be called if the chart update has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeDatasetsUpdate
   * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
   * the datasets update is cancelled until another `update` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} false to cancel the datasets update.
   * @since version 2.1.5
  */
  /**
   * @method IPlugin#afterDatasetsUpdate
   * @desc Called after the `chart` datasets have been updated. Note that this hook
   * will not be called if the datasets update has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   * @since version 2.1.5
   */
  /**
   * @method IPlugin#beforeDatasetUpdate
   * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
   * returns `false`, the datasets update is cancelled until another `update` is triggered.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Number} args.index - The dataset index.
   * @param {Object} args.meta - The dataset metadata.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart datasets drawing.
   */
  /**
   * @method IPlugin#afterDatasetUpdate
   * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
   * that this hook will not be called if the datasets update has been previously cancelled.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Number} args.index - The dataset index.
   * @param {Object} args.meta - The dataset metadata.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeLayout
   * @desc Called before laying out `chart`. If any plugin returns `false`,
   * the layout update is cancelled until another `update` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart layout.
   */
  /**
   * @method IPlugin#afterLayout
   * @desc Called after the `chart` has been layed out. Note that this hook will not
   * be called if the layout update has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeRender
   * @desc Called before rendering `chart`. If any plugin returns `false`,
   * the rendering is cancelled until another `render` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart rendering.
   */
  /**
   * @method IPlugin#afterRender
   * @desc Called after the `chart` has been fully rendered (and animation completed). Note
   * that this hook will not be called if the rendering has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeDraw
   * @desc Called before drawing `chart` at every animation frame specified by the given
   * easing value. If any plugin returns `false`, the frame drawing is cancelled until
   * another `render` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart drawing.
   */
  /**
   * @method IPlugin#afterDraw
   * @desc Called after the `chart` has been drawn for the specific easing value. Note
   * that this hook will not be called if the drawing has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeDatasetsDraw
   * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
   * the datasets drawing is cancelled until another `render` is triggered.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart datasets drawing.
   */
  /**
   * @method IPlugin#afterDatasetsDraw
   * @desc Called after the `chart` datasets have been drawn. Note that this hook
   * will not be called if the datasets drawing has been previously cancelled.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeDatasetDraw
   * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
   * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
   * is cancelled until another `render` is triggered.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Number} args.index - The dataset index.
   * @param {Object} args.meta - The dataset metadata.
   * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart datasets drawing.
   */
  /**
   * @method IPlugin#afterDatasetDraw
   * @desc Called after the `chart` datasets at the given `args.index` have been drawn
   * (datasets are drawn in the reverse order). Note that this hook will not be called
   * if the datasets drawing has been previously cancelled.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Number} args.index - The dataset index.
   * @param {Object} args.meta - The dataset metadata.
   * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeTooltipDraw
   * @desc Called before drawing the `tooltip`. If any plugin returns `false`,
   * the tooltip drawing is cancelled until another `render` is triggered.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Object} args.tooltip - The tooltip.
   * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   * @returns {Boolean} `false` to cancel the chart tooltip drawing.
   */
  /**
   * @method IPlugin#afterTooltipDraw
   * @desc Called after drawing the `tooltip`. Note that this hook will not
   * be called if the tooltip drawing has been previously cancelled.
   * @param {Chart} chart - The chart instance.
   * @param {Object} args - The call arguments.
   * @param {Object} args.tooltip - The tooltip.
   * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#beforeEvent
   * @desc Called before processing the specified `event`. If any plugin returns `false`,
   * the event will be discarded.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {IEvent} event - The event object.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#afterEvent
   * @desc Called after the `event` has been consumed. Note that this hook
   * will not be called if the `event` has been previously discarded.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {IEvent} event - The event object.
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#resize
   * @desc Called after the chart as been resized.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
   * @param {Object} options - The plugin options.
   */
  /**
   * @method IPlugin#destroy
   * @desc Called after the chart as been destroyed.
   * @param {Chart.Controller} chart - The chart instance.
   * @param {Object} options - The plugin options.
   */
  
  },{"26":26,"46":46}],33:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  var Ticks = require(35);
  
  defaults._set('scale', {
  	display: true,
  	position: 'left',
  	offset: false,
  
  	// grid line settings
  	gridLines: {
  		display: true,
  		color: 'rgba(0, 0, 0, 0.1)',
  		lineWidth: 1,
  		drawBorder: true,
  		drawOnChartArea: true,
  		drawTicks: true,
  		tickMarkLength: 10,
  		zeroLineWidth: 1,
  		zeroLineColor: 'rgba(0,0,0,0.25)',
  		zeroLineBorderDash: [],
  		zeroLineBorderDashOffset: 0.0,
  		offsetGridLines: false,
  		borderDash: [],
  		borderDashOffset: 0.0
  	},
  
  	// scale label
  	scaleLabel: {
  		// display property
  		display: false,
  
  		// actual label
  		labelString: '',
  
  		// line height
  		lineHeight: 1.2,
  
  		// top/bottom padding
  		padding: {
  			top: 4,
  			bottom: 4
  		}
  	},
  
  	// label settings
  	ticks: {
  		beginAtZero: false,
  		minRotation: 0,
  		maxRotation: 50,
  		mirror: false,
  		padding: 0,
  		reverse: false,
  		display: true,
  		autoSkip: true,
  		autoSkipPadding: 0,
  		labelOffset: 0,
  		// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
  		callback: Ticks.formatters.values,
  		minor: {},
  		major: {}
  	}
  });
  
  function labelsFromTicks(ticks) {
  	var labels = [];
  	var i, ilen;
  
  	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
  		labels.push(ticks[i].label);
  	}
  
  	return labels;
  }
  
  function getLineValue(scale, index, offsetGridLines) {
  	var lineValue = scale.getPixelForTick(index);
  
  	if (offsetGridLines) {
  		if (index === 0) {
  			lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
  		} else {
  			lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
  		}
  	}
  	return lineValue;
  }
  
  function computeTextSize(context, tick, font) {
  	return helpers.isArray(tick) ?
  		helpers.longestText(context, font, tick) :
  		context.measureText(tick).width;
  }
  
  function parseFontOptions(options) {
  	var valueOrDefault = helpers.valueOrDefault;
  	var globalDefaults = defaults.global;
  	var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
  	var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
  	var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
  
  	return {
  		size: size,
  		style: style,
  		family: family,
  		font: helpers.fontString(size, style, family)
  	};
  }
  
  function parseLineHeight(options) {
  	return helpers.options.toLineHeight(
  		helpers.valueOrDefault(options.lineHeight, 1.2),
  		helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
  }
  
  module.exports = Element.extend({
  	/**
  	 * Get the padding needed for the scale
  	 * @method getPadding
  	 * @private
  	 * @returns {Padding} the necessary padding
  	 */
  	getPadding: function() {
  		var me = this;
  		return {
  			left: me.paddingLeft || 0,
  			top: me.paddingTop || 0,
  			right: me.paddingRight || 0,
  			bottom: me.paddingBottom || 0
  		};
  	},
  
  	/**
  	 * Returns the scale tick objects ({label, major})
  	 * @since 2.7
  	 */
  	getTicks: function() {
  		return this._ticks;
  	},
  
  	// These methods are ordered by lifecyle. Utilities then follow.
  	// Any function defined here is inherited by all scale types.
  	// Any function can be extended by the scale type
  
  	mergeTicksOptions: function() {
  		var ticks = this.options.ticks;
  		if (ticks.minor === false) {
  			ticks.minor = {
  				display: false
  			};
  		}
  		if (ticks.major === false) {
  			ticks.major = {
  				display: false
  			};
  		}
  		for (var key in ticks) {
  			if (key !== 'major' && key !== 'minor') {
  				if (typeof ticks.minor[key] === 'undefined') {
  					ticks.minor[key] = ticks[key];
  				}
  				if (typeof ticks.major[key] === 'undefined') {
  					ticks.major[key] = ticks[key];
  				}
  			}
  		}
  	},
  	beforeUpdate: function() {
  		helpers.callback(this.options.beforeUpdate, [this]);
  	},
  
  	update: function(maxWidth, maxHeight, margins) {
  		var me = this;
  		var i, ilen, labels, label, ticks, tick;
  
  		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  		me.beforeUpdate();
  
  		// Absorb the master measurements
  		me.maxWidth = maxWidth;
  		me.maxHeight = maxHeight;
  		me.margins = helpers.extend({
  			left: 0,
  			right: 0,
  			top: 0,
  			bottom: 0
  		}, margins);
  		me.longestTextCache = me.longestTextCache || {};
  
  		// Dimensions
  		me.beforeSetDimensions();
  		me.setDimensions();
  		me.afterSetDimensions();
  
  		// Data min/max
  		me.beforeDataLimits();
  		me.determineDataLimits();
  		me.afterDataLimits();
  
  		// Ticks - `this.ticks` is now DEPRECATED!
  		// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
  		// and must not be accessed directly from outside this class. `this.ticks` being
  		// around for long time and not marked as private, we can't change its structure
  		// without unexpected breaking changes. If you need to access the scale ticks,
  		// use scale.getTicks() instead.
  
  		me.beforeBuildTicks();
  
  		// New implementations should return an array of objects but for BACKWARD COMPAT,
  		// we still support no return (`this.ticks` internally set by calling this method).
  		ticks = me.buildTicks() || [];
  
  		me.afterBuildTicks();
  
  		me.beforeTickToLabelConversion();
  
  		// New implementations should return the formatted tick labels but for BACKWARD
  		// COMPAT, we still support no return (`this.ticks` internally changed by calling
  		// this method and supposed to contain only string values).
  		labels = me.convertTicksToLabels(ticks) || me.ticks;
  
  		me.afterTickToLabelConversion();
  
  		me.ticks = labels;   // BACKWARD COMPATIBILITY
  
  		// IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
  
  		// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
  		for (i = 0, ilen = labels.length; i < ilen; ++i) {
  			label = labels[i];
  			tick = ticks[i];
  			if (!tick) {
  				ticks.push(tick = {
  					label: label,
  					major: false
  				});
  			} else {
  				tick.label = label;
  			}
  		}
  
  		me._ticks = ticks;
  
  		// Tick Rotation
  		me.beforeCalculateTickRotation();
  		me.calculateTickRotation();
  		me.afterCalculateTickRotation();
  		// Fit
  		me.beforeFit();
  		me.fit();
  		me.afterFit();
  		//
  		me.afterUpdate();
  
  		return me.minSize;
  
  	},
  	afterUpdate: function() {
  		helpers.callback(this.options.afterUpdate, [this]);
  	},
  
  	//
  
  	beforeSetDimensions: function() {
  		helpers.callback(this.options.beforeSetDimensions, [this]);
  	},
  	setDimensions: function() {
  		var me = this;
  		// Set the unconstrained dimension before label rotation
  		if (me.isHorizontal()) {
  			// Reset position before calculating rotation
  			me.width = me.maxWidth;
  			me.left = 0;
  			me.right = me.width;
  		} else {
  			me.height = me.maxHeight;
  
  			// Reset position before calculating rotation
  			me.top = 0;
  			me.bottom = me.height;
  		}
  
  		// Reset padding
  		me.paddingLeft = 0;
  		me.paddingTop = 0;
  		me.paddingRight = 0;
  		me.paddingBottom = 0;
  	},
  	afterSetDimensions: function() {
  		helpers.callback(this.options.afterSetDimensions, [this]);
  	},
  
  	// Data limits
  	beforeDataLimits: function() {
  		helpers.callback(this.options.beforeDataLimits, [this]);
  	},
  	determineDataLimits: helpers.noop,
  	afterDataLimits: function() {
  		helpers.callback(this.options.afterDataLimits, [this]);
  	},
  
  	//
  	beforeBuildTicks: function() {
  		helpers.callback(this.options.beforeBuildTicks, [this]);
  	},
  	buildTicks: helpers.noop,
  	afterBuildTicks: function() {
  		helpers.callback(this.options.afterBuildTicks, [this]);
  	},
  
  	beforeTickToLabelConversion: function() {
  		helpers.callback(this.options.beforeTickToLabelConversion, [this]);
  	},
  	convertTicksToLabels: function() {
  		var me = this;
  		// Convert ticks to strings
  		var tickOpts = me.options.ticks;
  		me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
  	},
  	afterTickToLabelConversion: function() {
  		helpers.callback(this.options.afterTickToLabelConversion, [this]);
  	},
  
  	//
  
  	beforeCalculateTickRotation: function() {
  		helpers.callback(this.options.beforeCalculateTickRotation, [this]);
  	},
  	calculateTickRotation: function() {
  		var me = this;
  		var context = me.ctx;
  		var tickOpts = me.options.ticks;
  		var labels = labelsFromTicks(me._ticks);
  
  		// Get the width of each grid by calculating the difference
  		// between x offsets between 0 and 1.
  		var tickFont = parseFontOptions(tickOpts);
  		context.font = tickFont.font;
  
  		var labelRotation = tickOpts.minRotation || 0;
  
  		if (labels.length && me.options.display && me.isHorizontal()) {
  			var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
  			var labelWidth = originalLabelWidth;
  			var cosRotation, sinRotation;
  
  			// Allow 3 pixels x2 padding either side for label readability
  			var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
  
  			// Max label rotation can be set or default to 90 - also act as a loop counter
  			while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
  				var angleRadians = helpers.toRadians(labelRotation);
  				cosRotation = Math.cos(angleRadians);
  				sinRotation = Math.sin(angleRadians);
  
  				if (sinRotation * originalLabelWidth > me.maxHeight) {
  					// go back one step
  					labelRotation--;
  					break;
  				}
  
  				labelRotation++;
  				labelWidth = cosRotation * originalLabelWidth;
  			}
  		}
  
  		me.labelRotation = labelRotation;
  	},
  	afterCalculateTickRotation: function() {
  		helpers.callback(this.options.afterCalculateTickRotation, [this]);
  	},
  
  	//
  
  	beforeFit: function() {
  		helpers.callback(this.options.beforeFit, [this]);
  	},
  	fit: function() {
  		var me = this;
  		// Reset
  		var minSize = me.minSize = {
  			width: 0,
  			height: 0
  		};
  
  		var labels = labelsFromTicks(me._ticks);
  
  		var opts = me.options;
  		var tickOpts = opts.ticks;
  		var scaleLabelOpts = opts.scaleLabel;
  		var gridLineOpts = opts.gridLines;
  		var display = opts.display;
  		var isHorizontal = me.isHorizontal();
  
  		var tickFont = parseFontOptions(tickOpts);
  		var tickMarkLength = opts.gridLines.tickMarkLength;
  
  		// Width
  		if (isHorizontal) {
  			// subtract the margins to line up with the chartArea if we are a full width scale
  			minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
  		} else {
  			minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
  		}
  
  		// height
  		if (isHorizontal) {
  			minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
  		} else {
  			minSize.height = me.maxHeight; // fill all the height
  		}
  
  		// Are we showing a title for the scale?
  		if (scaleLabelOpts.display && display) {
  			var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
  			var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
  			var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
  
  			if (isHorizontal) {
  				minSize.height += deltaHeight;
  			} else {
  				minSize.width += deltaHeight;
  			}
  		}
  
  		// Don't bother fitting the ticks if we are not showing them
  		if (tickOpts.display && display) {
  			var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
  			var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
  			var lineSpace = tickFont.size * 0.5;
  			var tickPadding = me.options.ticks.padding;
  
  			if (isHorizontal) {
  				// A horizontal axis is more constrained by the height.
  				me.longestLabelWidth = largestTextWidth;
  
  				var angleRadians = helpers.toRadians(me.labelRotation);
  				var cosRotation = Math.cos(angleRadians);
  				var sinRotation = Math.sin(angleRadians);
  
  				// TODO - improve this calculation
  				var labelHeight = (sinRotation * largestTextWidth)
  					+ (tickFont.size * tallestLabelHeightInLines)
  					+ (lineSpace * (tallestLabelHeightInLines - 1))
  					+ lineSpace; // padding
  
  				minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
  
  				me.ctx.font = tickFont.font;
  				var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
  				var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
  
  				// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
  				// which means that the right padding is dominated by the font height
  				if (me.labelRotation !== 0) {
  					me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
  					me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
  				} else {
  					me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
  					me.paddingRight = lastLabelWidth / 2 + 3;
  				}
  			} else {
  				// A vertical axis is more constrained by the width. Labels are the
  				// dominant factor here, so get that length first and account for padding
  				if (tickOpts.mirror) {
  					largestTextWidth = 0;
  				} else {
  					// use lineSpace for consistency with horizontal axis
  					// tickPadding is not implemented for horizontal
  					largestTextWidth += tickPadding + lineSpace;
  				}
  
  				minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
  
  				me.paddingTop = tickFont.size / 2;
  				me.paddingBottom = tickFont.size / 2;
  			}
  		}
  
  		me.handleMargins();
  
  		me.width = minSize.width;
  		me.height = minSize.height;
  	},
  
  	/**
  	 * Handle margins and padding interactions
  	 * @private
  	 */
  	handleMargins: function() {
  		var me = this;
  		if (me.margins) {
  			me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
  			me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
  			me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
  			me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
  		}
  	},
  
  	afterFit: function() {
  		helpers.callback(this.options.afterFit, [this]);
  	},
  
  	// Shared Methods
  	isHorizontal: function() {
  		return this.options.position === 'top' || this.options.position === 'bottom';
  	},
  	isFullWidth: function() {
  		return (this.options.fullWidth);
  	},
  
  	// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
  	getRightValue: function(rawValue) {
  		// Null and undefined values first
  		if (helpers.isNullOrUndef(rawValue)) {
  			return NaN;
  		}
  		// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
  		if (typeof rawValue === 'number' && !isFinite(rawValue)) {
  			return NaN;
  		}
  		// If it is in fact an object, dive in one more level
  		if (rawValue) {
  			if (this.isHorizontal()) {
  				if (rawValue.x !== undefined) {
  					return this.getRightValue(rawValue.x);
  				}
  			} else if (rawValue.y !== undefined) {
  				return this.getRightValue(rawValue.y);
  			}
  		}
  
  		// Value is good, return it
  		return rawValue;
  	},
  
  	/**
  	 * Used to get the value to display in the tooltip for the data at the given index
  	 * @param index
  	 * @param datasetIndex
  	 */
  	getLabelForIndex: helpers.noop,
  
  	/**
  	 * Returns the location of the given data point. Value can either be an index or a numerical value
  	 * The coordinate (0, 0) is at the upper-left corner of the canvas
  	 * @param value
  	 * @param index
  	 * @param datasetIndex
  	 */
  	getPixelForValue: helpers.noop,
  
  	/**
  	 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
  	 * The coordinate (0, 0) is at the upper-left corner of the canvas
  	 * @param pixel
  	 */
  	getValueForPixel: helpers.noop,
  
  	/**
  	 * Returns the location of the tick at the given index
  	 * The coordinate (0, 0) is at the upper-left corner of the canvas
  	 */
  	getPixelForTick: function(index) {
  		var me = this;
  		var offset = me.options.offset;
  		if (me.isHorizontal()) {
  			var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
  			var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
  			var pixel = (tickWidth * index) + me.paddingLeft;
  
  			if (offset) {
  				pixel += tickWidth / 2;
  			}
  
  			var finalVal = me.left + Math.round(pixel);
  			finalVal += me.isFullWidth() ? me.margins.left : 0;
  			return finalVal;
  		}
  		var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
  		return me.top + (index * (innerHeight / (me._ticks.length - 1)));
  	},
  
  	/**
  	 * Utility for getting the pixel location of a percentage of scale
  	 * The coordinate (0, 0) is at the upper-left corner of the canvas
  	 */
  	getPixelForDecimal: function(decimal) {
  		var me = this;
  		if (me.isHorizontal()) {
  			var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
  			var valueOffset = (innerWidth * decimal) + me.paddingLeft;
  
  			var finalVal = me.left + Math.round(valueOffset);
  			finalVal += me.isFullWidth() ? me.margins.left : 0;
  			return finalVal;
  		}
  		return me.top + (decimal * me.height);
  	},
  
  	/**
  	 * Returns the pixel for the minimum chart value
  	 * The coordinate (0, 0) is at the upper-left corner of the canvas
  	 */
  	getBasePixel: function() {
  		return this.getPixelForValue(this.getBaseValue());
  	},
  
  	getBaseValue: function() {
  		var me = this;
  		var min = me.min;
  		var max = me.max;
  
  		return me.beginAtZero ? 0 :
  			min < 0 && max < 0 ? max :
  			min > 0 && max > 0 ? min :
  			0;
  	},
  
  	/**
  	 * Returns a subset of ticks to be plotted to avoid overlapping labels.
  	 * @private
  	 */
  	_autoSkip: function(ticks) {
  		var skipRatio;
  		var me = this;
  		var isHorizontal = me.isHorizontal();
  		var optionTicks = me.options.ticks.minor;
  		var tickCount = ticks.length;
  		var labelRotationRadians = helpers.toRadians(me.labelRotation);
  		var cosRotation = Math.cos(labelRotationRadians);
  		var longestRotatedLabel = me.longestLabelWidth * cosRotation;
  		var result = [];
  		var i, tick, shouldSkip;
  
  		// figure out the maximum number of gridlines to show
  		var maxTicks;
  		if (optionTicks.maxTicksLimit) {
  			maxTicks = optionTicks.maxTicksLimit;
  		}
  
  		if (isHorizontal) {
  			skipRatio = false;
  
  			if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
  				skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
  			}
  
  			// if they defined a max number of optionTicks,
  			// increase skipRatio until that number is met
  			if (maxTicks && tickCount > maxTicks) {
  				skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
  			}
  		}
  
  		for (i = 0; i < tickCount; i++) {
  			tick = ticks[i];
  
  			// Since we always show the last tick,we need may need to hide the last shown one before
  			shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
  			if (shouldSkip && i !== tickCount - 1) {
  				// leave tick in place but make sure it's not displayed (#4635)
  				delete tick.label;
  			}
  			result.push(tick);
  		}
  		return result;
  	},
  
  	// Actually draw the scale on the canvas
  	// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
  	draw: function(chartArea) {
  		var me = this;
  		var options = me.options;
  		if (!options.display) {
  			return;
  		}
  
  		var context = me.ctx;
  		var globalDefaults = defaults.global;
  		var optionTicks = options.ticks.minor;
  		var optionMajorTicks = options.ticks.major || optionTicks;
  		var gridLines = options.gridLines;
  		var scaleLabel = options.scaleLabel;
  
  		var isRotated = me.labelRotation !== 0;
  		var isHorizontal = me.isHorizontal();
  
  		var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
  		var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
  		var tickFont = parseFontOptions(optionTicks);
  		var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
  		var majorTickFont = parseFontOptions(optionMajorTicks);
  
  		var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
  
  		var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
  		var scaleLabelFont = parseFontOptions(scaleLabel);
  		var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
  		var labelRotationRadians = helpers.toRadians(me.labelRotation);
  
  		var itemsToDraw = [];
  
  		var axisWidth = me.options.gridLines.lineWidth;
  		var xTickStart = options.position === 'right' ? me.left : me.right - axisWidth - tl;
  		var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
  		var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
  		var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
  
  		helpers.each(ticks, function(tick, index) {
  			// autoskipper skipped this tick (#4635)
  			if (helpers.isNullOrUndef(tick.label)) {
  				return;
  			}
  
  			var label = tick.label;
  			var lineWidth, lineColor, borderDash, borderDashOffset;
  			if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
  				// Draw the first index specially
  				lineWidth = gridLines.zeroLineWidth;
  				lineColor = gridLines.zeroLineColor;
  				borderDash = gridLines.zeroLineBorderDash;
  				borderDashOffset = gridLines.zeroLineBorderDashOffset;
  			} else {
  				lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
  				lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
  				borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
  				borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
  			}
  
  			// Common properties
  			var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
  			var textAlign = 'middle';
  			var textBaseline = 'middle';
  			var tickPadding = optionTicks.padding;
  
  			if (isHorizontal) {
  				var labelYOffset = tl + tickPadding;
  
  				if (options.position === 'bottom') {
  					// bottom
  					textBaseline = !isRotated ? 'top' : 'middle';
  					textAlign = !isRotated ? 'center' : 'right';
  					labelY = me.top + labelYOffset;
  				} else {
  					// top
  					textBaseline = !isRotated ? 'bottom' : 'middle';
  					textAlign = !isRotated ? 'center' : 'left';
  					labelY = me.bottom - labelYOffset;
  				}
  
  				var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
  				if (xLineValue < me.left) {
  					lineColor = 'rgba(0,0,0,0)';
  				}
  				xLineValue += helpers.aliasPixel(lineWidth);
  
  				labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
  
  				tx1 = tx2 = x1 = x2 = xLineValue;
  				ty1 = yTickStart;
  				ty2 = yTickEnd;
  				y1 = chartArea.top;
  				y2 = chartArea.bottom + axisWidth;
  			} else {
  				var isLeft = options.position === 'left';
  				var labelXOffset;
  
  				if (optionTicks.mirror) {
  					textAlign = isLeft ? 'left' : 'right';
  					labelXOffset = tickPadding;
  				} else {
  					textAlign = isLeft ? 'right' : 'left';
  					labelXOffset = tl + tickPadding;
  				}
  
  				labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
  
  				var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
  				if (yLineValue < me.top) {
  					lineColor = 'rgba(0,0,0,0)';
  				}
  				yLineValue += helpers.aliasPixel(lineWidth);
  
  				labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
  
  				tx1 = xTickStart;
  				tx2 = xTickEnd;
  				x1 = chartArea.left;
  				x2 = chartArea.right + axisWidth;
  				ty1 = ty2 = y1 = y2 = yLineValue;
  			}
  
  			itemsToDraw.push({
  				tx1: tx1,
  				ty1: ty1,
  				tx2: tx2,
  				ty2: ty2,
  				x1: x1,
  				y1: y1,
  				x2: x2,
  				y2: y2,
  				labelX: labelX,
  				labelY: labelY,
  				glWidth: lineWidth,
  				glColor: lineColor,
  				glBorderDash: borderDash,
  				glBorderDashOffset: borderDashOffset,
  				rotation: -1 * labelRotationRadians,
  				label: label,
  				major: tick.major,
  				textBaseline: textBaseline,
  				textAlign: textAlign
  			});
  		});
  
  		// Draw all of the tick labels, tick marks, and grid lines at the correct places
  		helpers.each(itemsToDraw, function(itemToDraw) {
  			if (gridLines.display) {
  				context.save();
  				context.lineWidth = itemToDraw.glWidth;
  				context.strokeStyle = itemToDraw.glColor;
  				if (context.setLineDash) {
  					context.setLineDash(itemToDraw.glBorderDash);
  					context.lineDashOffset = itemToDraw.glBorderDashOffset;
  				}
  
  				context.beginPath();
  
  				if (gridLines.drawTicks) {
  					context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
  					context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
  				}
  
  				if (gridLines.drawOnChartArea) {
  					context.moveTo(itemToDraw.x1, itemToDraw.y1);
  					context.lineTo(itemToDraw.x2, itemToDraw.y2);
  				}
  
  				context.stroke();
  				context.restore();
  			}
  
  			if (optionTicks.display) {
  				// Make sure we draw text in the correct color and font
  				context.save();
  				context.translate(itemToDraw.labelX, itemToDraw.labelY);
  				context.rotate(itemToDraw.rotation);
  				context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
  				context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
  				context.textBaseline = itemToDraw.textBaseline;
  				context.textAlign = itemToDraw.textAlign;
  
  				var label = itemToDraw.label;
  				if (helpers.isArray(label)) {
  					var lineCount = label.length;
  					var lineHeight = tickFont.size * 1.5;
  					var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
  
  					for (var i = 0; i < lineCount; ++i) {
  						// We just make sure the multiline element is a string here..
  						context.fillText('' + label[i], 0, y);
  						// apply same lineSpacing as calculated @ L#320
  						y += lineHeight;
  					}
  				} else {
  					context.fillText(label, 0, 0);
  				}
  				context.restore();
  			}
  		});
  
  		if (scaleLabel.display) {
  			// Draw the scale label
  			var scaleLabelX;
  			var scaleLabelY;
  			var rotation = 0;
  			var halfLineHeight = parseLineHeight(scaleLabel) / 2;
  
  			if (isHorizontal) {
  				scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
  				scaleLabelY = options.position === 'bottom'
  					? me.bottom - halfLineHeight - scaleLabelPadding.bottom
  					: me.top + halfLineHeight + scaleLabelPadding.top;
  			} else {
  				var isLeft = options.position === 'left';
  				scaleLabelX = isLeft
  					? me.left + halfLineHeight + scaleLabelPadding.top
  					: me.right - halfLineHeight - scaleLabelPadding.top;
  				scaleLabelY = me.top + ((me.bottom - me.top) / 2);
  				rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
  			}
  
  			context.save();
  			context.translate(scaleLabelX, scaleLabelY);
  			context.rotate(rotation);
  			context.textAlign = 'center';
  			context.textBaseline = 'middle';
  			context.fillStyle = scaleLabelFontColor; // render in correct colour
  			context.font = scaleLabelFont.font;
  			context.fillText(scaleLabel.labelString, 0, 0);
  			context.restore();
  		}
  
  		if (gridLines.drawBorder) {
  			// Draw the line at the edge of the axis
  			context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
  			context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
  			var x1 = me.left;
  			var x2 = me.right + axisWidth;
  			var y1 = me.top;
  			var y2 = me.bottom + axisWidth;
  
  			var aliasPixel = helpers.aliasPixel(context.lineWidth);
  			if (isHorizontal) {
  				y1 = y2 = options.position === 'top' ? me.bottom : me.top;
  				y1 += aliasPixel;
  				y2 += aliasPixel;
  			} else {
  				x1 = x2 = options.position === 'left' ? me.right : me.left;
  				x1 += aliasPixel;
  				x2 += aliasPixel;
  			}
  
  			context.beginPath();
  			context.moveTo(x1, y1);
  			context.lineTo(x2, y2);
  			context.stroke();
  		}
  	}
  });
  
  },{"26":26,"27":27,"35":35,"46":46}],34:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var helpers = require(46);
  var layouts = require(31);
  
  module.exports = {
  	// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
  	// use the new chart options to grab the correct scale
  	constructors: {},
  	// Use a registration function so that we can move to an ES6 map when we no longer need to support
  	// old browsers
  
  	// Scale config defaults
  	defaults: {},
  	registerScaleType: function(type, scaleConstructor, scaleDefaults) {
  		this.constructors[type] = scaleConstructor;
  		this.defaults[type] = helpers.clone(scaleDefaults);
  	},
  	getScaleConstructor: function(type) {
  		return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
  	},
  	getScaleDefaults: function(type) {
  		// Return the scale defaults merged with the global settings so that we always use the latest ones
  		return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {};
  	},
  	updateScaleDefaults: function(type, additions) {
  		var me = this;
  		if (me.defaults.hasOwnProperty(type)) {
  			me.defaults[type] = helpers.extend(me.defaults[type], additions);
  		}
  	},
  	addScalesToLayout: function(chart) {
  		// Adds each scale to the chart.boxes array to be sized accordingly
  		helpers.each(chart.scales, function(scale) {
  			// Set ILayoutItem parameters for backwards compatibility
  			scale.fullWidth = scale.options.fullWidth;
  			scale.position = scale.options.position;
  			scale.weight = scale.options.weight;
  			layouts.addBox(chart, scale);
  		});
  	}
  };
  
  },{"26":26,"31":31,"46":46}],35:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  
  /**
   * Namespace to hold static tick generation functions
   * @namespace Chart.Ticks
   */
  module.exports = {
  	/**
  	 * Namespace to hold formatters for different types of ticks
  	 * @namespace Chart.Ticks.formatters
  	 */
  	formatters: {
  		/**
  		 * Formatter for value labels
  		 * @method Chart.Ticks.formatters.values
  		 * @param value the value to display
  		 * @return {String|Array} the label to display
  		 */
  		values: function(value) {
  			return helpers.isArray(value) ? value : '' + value;
  		},
  
  		/**
  		 * Formatter for linear numeric ticks
  		 * @method Chart.Ticks.formatters.linear
  		 * @param tickValue {Number} the value to be formatted
  		 * @param index {Number} the position of the tickValue parameter in the ticks array
  		 * @param ticks {Array<Number>} the list of ticks being converted
  		 * @return {String} string representation of the tickValue parameter
  		 */
  		linear: function(tickValue, index, ticks) {
  			// If we have lots of ticks, don't use the ones
  			var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
  
  			// If we have a number like 2.5 as the delta, figure out how many decimal places we need
  			if (Math.abs(delta) > 1) {
  				if (tickValue !== Math.floor(tickValue)) {
  					// not an integer
  					delta = tickValue - Math.floor(tickValue);
  				}
  			}
  
  			var logDelta = helpers.log10(Math.abs(delta));
  			var tickString = '';
  
  			if (tickValue !== 0) {
  				var maxTick = Math.max(Math.abs(ticks[0]), Math.abs(ticks[ticks.length - 1]));
  				if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation
  					var logTick = helpers.log10(Math.abs(tickValue));
  					tickString = tickValue.toExponential(Math.floor(logTick) - Math.floor(logDelta));
  				} else {
  					var numDecimal = -1 * Math.floor(logDelta);
  					numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
  					tickString = tickValue.toFixed(numDecimal);
  				}
  			} else {
  				tickString = '0'; // never show decimal places for 0
  			}
  
  			return tickString;
  		},
  
  		logarithmic: function(tickValue, index, ticks) {
  			var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
  
  			if (tickValue === 0) {
  				return '0';
  			} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
  				return tickValue.toExponential();
  			}
  			return '';
  		}
  	}
  };
  
  },{"46":46}],36:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  
  defaults._set('global', {
  	tooltips: {
  		enabled: true,
  		custom: null,
  		mode: 'nearest',
  		position: 'average',
  		intersect: true,
  		backgroundColor: 'rgba(0,0,0,0.8)',
  		titleFontStyle: 'bold',
  		titleSpacing: 2,
  		titleMarginBottom: 6,
  		titleFontColor: '#fff',
  		titleAlign: 'left',
  		bodySpacing: 2,
  		bodyFontColor: '#fff',
  		bodyAlign: 'left',
  		footerFontStyle: 'bold',
  		footerSpacing: 2,
  		footerMarginTop: 6,
  		footerFontColor: '#fff',
  		footerAlign: 'left',
  		yPadding: 6,
  		xPadding: 6,
  		caretPadding: 2,
  		caretSize: 5,
  		cornerRadius: 6,
  		multiKeyBackground: '#fff',
  		displayColors: true,
  		borderColor: 'rgba(0,0,0,0)',
  		borderWidth: 0,
  		callbacks: {
  			// Args are: (tooltipItems, data)
  			beforeTitle: helpers.noop,
  			title: function(tooltipItems, data) {
  				// Pick first xLabel for now
  				var title = '';
  				var labels = data.labels;
  				var labelCount = labels ? labels.length : 0;
  
  				if (tooltipItems.length > 0) {
  					var item = tooltipItems[0];
  
  					if (item.xLabel) {
  						title = item.xLabel;
  					} else if (labelCount > 0 && item.index < labelCount) {
  						title = labels[item.index];
  					}
  				}
  
  				return title;
  			},
  			afterTitle: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			beforeBody: helpers.noop,
  
  			// Args are: (tooltipItem, data)
  			beforeLabel: helpers.noop,
  			label: function(tooltipItem, data) {
  				var label = data.datasets[tooltipItem.datasetIndex].label || '';
  
  				if (label) {
  					label += ': ';
  				}
  				label += tooltipItem.yLabel;
  				return label;
  			},
  			labelColor: function(tooltipItem, chart) {
  				var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
  				var activeElement = meta.data[tooltipItem.index];
  				var view = activeElement._view;
  				return {
  					borderColor: view.borderColor,
  					backgroundColor: view.backgroundColor
  				};
  			},
  			labelTextColor: function() {
  				return this._options.bodyFontColor;
  			},
  			afterLabel: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			afterBody: helpers.noop,
  
  			// Args are: (tooltipItems, data)
  			beforeFooter: helpers.noop,
  			footer: helpers.noop,
  			afterFooter: helpers.noop
  		}
  	}
  });
  
  var positioners = {
  	/**
  	 * Average mode places the tooltip at the average position of the elements shown
  	 * @function Chart.Tooltip.positioners.average
  	 * @param elements {ChartElement[]} the elements being displayed in the tooltip
  	 * @returns {Point} tooltip position
  	 */
  	average: function(elements) {
  		if (!elements.length) {
  			return false;
  		}
  
  		var i, len;
  		var x = 0;
  		var y = 0;
  		var count = 0;
  
  		for (i = 0, len = elements.length; i < len; ++i) {
  			var el = elements[i];
  			if (el && el.hasValue()) {
  				var pos = el.tooltipPosition();
  				x += pos.x;
  				y += pos.y;
  				++count;
  			}
  		}
  
  		return {
  			x: Math.round(x / count),
  			y: Math.round(y / count)
  		};
  	},
  
  	/**
  	 * Gets the tooltip position nearest of the item nearest to the event position
  	 * @function Chart.Tooltip.positioners.nearest
  	 * @param elements {Chart.Element[]} the tooltip elements
  	 * @param eventPosition {Point} the position of the event in canvas coordinates
  	 * @returns {Point} the tooltip position
  	 */
  	nearest: function(elements, eventPosition) {
  		var x = eventPosition.x;
  		var y = eventPosition.y;
  		var minDistance = Number.POSITIVE_INFINITY;
  		var i, len, nearestElement;
  
  		for (i = 0, len = elements.length; i < len; ++i) {
  			var el = elements[i];
  			if (el && el.hasValue()) {
  				var center = el.getCenterPoint();
  				var d = helpers.distanceBetweenPoints(eventPosition, center);
  
  				if (d < minDistance) {
  					minDistance = d;
  					nearestElement = el;
  				}
  			}
  		}
  
  		if (nearestElement) {
  			var tp = nearestElement.tooltipPosition();
  			x = tp.x;
  			y = tp.y;
  		}
  
  		return {
  			x: x,
  			y: y
  		};
  	}
  };
  
  /**
   * Helper method to merge the opacity into a color
   */
  function mergeOpacity(colorString, opacity) {
  	var color = helpers.color(colorString);
  	return color.alpha(opacity * color.alpha()).rgbaString();
  }
  
  // Helper to push or concat based on if the 2nd parameter is an array or not
  function pushOrConcat(base, toPush) {
  	if (toPush) {
  		if (helpers.isArray(toPush)) {
  			// base = base.concat(toPush);
  			Array.prototype.push.apply(base, toPush);
  		} else {
  			base.push(toPush);
  		}
  	}
  
  	return base;
  }
  
  /**
   * Returns array of strings split by newline
   * @param {String} value - The value to split by newline.
   * @returns {Array} value if newline present - Returned from String split() method
   * @function
   */
  function splitNewlines(str) {
  	if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
  		return str.split('\n');
  	}
  	return str;
  }
  
  
  // Private helper to create a tooltip item model
  // @param element : the chart element (point, arc, bar) to create the tooltip item for
  // @return : new tooltip item
  function createTooltipItem(element) {
  	var xScale = element._xScale;
  	var yScale = element._yScale || element._scale; // handle radar || polarArea charts
  	var index = element._index;
  	var datasetIndex = element._datasetIndex;
  
  	return {
  		xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
  		yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
  		index: index,
  		datasetIndex: datasetIndex,
  		x: element._model.x,
  		y: element._model.y
  	};
  }
  
  /**
   * Helper to get the reset model for the tooltip
   * @param tooltipOpts {Object} the tooltip options
   */
  function getBaseModel(tooltipOpts) {
  	var globalDefaults = defaults.global;
  	var valueOrDefault = helpers.valueOrDefault;
  
  	return {
  		// Positioning
  		xPadding: tooltipOpts.xPadding,
  		yPadding: tooltipOpts.yPadding,
  		xAlign: tooltipOpts.xAlign,
  		yAlign: tooltipOpts.yAlign,
  
  		// Body
  		bodyFontColor: tooltipOpts.bodyFontColor,
  		_bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
  		_bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
  		_bodyAlign: tooltipOpts.bodyAlign,
  		bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
  		bodySpacing: tooltipOpts.bodySpacing,
  
  		// Title
  		titleFontColor: tooltipOpts.titleFontColor,
  		_titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
  		_titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
  		titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
  		_titleAlign: tooltipOpts.titleAlign,
  		titleSpacing: tooltipOpts.titleSpacing,
  		titleMarginBottom: tooltipOpts.titleMarginBottom,
  
  		// Footer
  		footerFontColor: tooltipOpts.footerFontColor,
  		_footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
  		_footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
  		footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
  		_footerAlign: tooltipOpts.footerAlign,
  		footerSpacing: tooltipOpts.footerSpacing,
  		footerMarginTop: tooltipOpts.footerMarginTop,
  
  		// Appearance
  		caretSize: tooltipOpts.caretSize,
  		cornerRadius: tooltipOpts.cornerRadius,
  		backgroundColor: tooltipOpts.backgroundColor,
  		opacity: 0,
  		legendColorBackground: tooltipOpts.multiKeyBackground,
  		displayColors: tooltipOpts.displayColors,
  		borderColor: tooltipOpts.borderColor,
  		borderWidth: tooltipOpts.borderWidth
  	};
  }
  
  /**
   * Get the size of the tooltip
   */
  function getTooltipSize(tooltip, model) {
  	var ctx = tooltip._chart.ctx;
  
  	var height = model.yPadding * 2; // Tooltip Padding
  	var width = 0;
  
  	// Count of all lines in the body
  	var body = model.body;
  	var combinedBodyLength = body.reduce(function(count, bodyItem) {
  		return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
  	}, 0);
  	combinedBodyLength += model.beforeBody.length + model.afterBody.length;
  
  	var titleLineCount = model.title.length;
  	var footerLineCount = model.footer.length;
  	var titleFontSize = model.titleFontSize;
  	var bodyFontSize = model.bodyFontSize;
  	var footerFontSize = model.footerFontSize;
  
  	height += titleLineCount * titleFontSize; // Title Lines
  	height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
  	height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
  	height += combinedBodyLength * bodyFontSize; // Body Lines
  	height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
  	height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
  	height += footerLineCount * (footerFontSize); // Footer Lines
  	height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
  
  	// Title width
  	var widthPadding = 0;
  	var maxLineWidth = function(line) {
  		width = Math.max(width, ctx.measureText(line).width + widthPadding);
  	};
  
  	ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
  	helpers.each(model.title, maxLineWidth);
  
  	// Body width
  	ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
  	helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
  
  	// Body lines may include some extra width due to the color box
  	widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
  	helpers.each(body, function(bodyItem) {
  		helpers.each(bodyItem.before, maxLineWidth);
  		helpers.each(bodyItem.lines, maxLineWidth);
  		helpers.each(bodyItem.after, maxLineWidth);
  	});
  
  	// Reset back to 0
  	widthPadding = 0;
  
  	// Footer width
  	ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
  	helpers.each(model.footer, maxLineWidth);
  
  	// Add padding
  	width += 2 * model.xPadding;
  
  	return {
  		width: width,
  		height: height
  	};
  }
  
  /**
   * Helper to get the alignment of a tooltip given the size
   */
  function determineAlignment(tooltip, size) {
  	var model = tooltip._model;
  	var chart = tooltip._chart;
  	var chartArea = tooltip._chart.chartArea;
  	var xAlign = 'center';
  	var yAlign = 'center';
  
  	if (model.y < size.height) {
  		yAlign = 'top';
  	} else if (model.y > (chart.height - size.height)) {
  		yAlign = 'bottom';
  	}
  
  	var lf, rf; // functions to determine left, right alignment
  	var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
  	var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
  	var midX = (chartArea.left + chartArea.right) / 2;
  	var midY = (chartArea.top + chartArea.bottom) / 2;
  
  	if (yAlign === 'center') {
  		lf = function(x) {
  			return x <= midX;
  		};
  		rf = function(x) {
  			return x > midX;
  		};
  	} else {
  		lf = function(x) {
  			return x <= (size.width / 2);
  		};
  		rf = function(x) {
  			return x >= (chart.width - (size.width / 2));
  		};
  	}
  
  	olf = function(x) {
  		return x + size.width + model.caretSize + model.caretPadding > chart.width;
  	};
  	orf = function(x) {
  		return x - size.width - model.caretSize - model.caretPadding < 0;
  	};
  	yf = function(y) {
  		return y <= midY ? 'top' : 'bottom';
  	};
  
  	if (lf(model.x)) {
  		xAlign = 'left';
  
  		// Is tooltip too wide and goes over the right side of the chart.?
  		if (olf(model.x)) {
  			xAlign = 'center';
  			yAlign = yf(model.y);
  		}
  	} else if (rf(model.x)) {
  		xAlign = 'right';
  
  		// Is tooltip too wide and goes outside left edge of canvas?
  		if (orf(model.x)) {
  			xAlign = 'center';
  			yAlign = yf(model.y);
  		}
  	}
  
  	var opts = tooltip._options;
  	return {
  		xAlign: opts.xAlign ? opts.xAlign : xAlign,
  		yAlign: opts.yAlign ? opts.yAlign : yAlign
  	};
  }
  
  /**
   * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
   */
  function getBackgroundPoint(vm, size, alignment, chart) {
  	// Background Position
  	var x = vm.x;
  	var y = vm.y;
  
  	var caretSize = vm.caretSize;
  	var caretPadding = vm.caretPadding;
  	var cornerRadius = vm.cornerRadius;
  	var xAlign = alignment.xAlign;
  	var yAlign = alignment.yAlign;
  	var paddingAndSize = caretSize + caretPadding;
  	var radiusAndPadding = cornerRadius + caretPadding;
  
  	if (xAlign === 'right') {
  		x -= size.width;
  	} else if (xAlign === 'center') {
  		x -= (size.width / 2);
  		if (x + size.width > chart.width) {
  			x = chart.width - size.width;
  		}
  		if (x < 0) {
  			x = 0;
  		}
  	}
  
  	if (yAlign === 'top') {
  		y += paddingAndSize;
  	} else if (yAlign === 'bottom') {
  		y -= size.height + paddingAndSize;
  	} else {
  		y -= (size.height / 2);
  	}
  
  	if (yAlign === 'center') {
  		if (xAlign === 'left') {
  			x += paddingAndSize;
  		} else if (xAlign === 'right') {
  			x -= paddingAndSize;
  		}
  	} else if (xAlign === 'left') {
  		x -= radiusAndPadding;
  	} else if (xAlign === 'right') {
  		x += radiusAndPadding;
  	}
  
  	return {
  		x: x,
  		y: y
  	};
  }
  
  /**
   * Helper to build before and after body lines
   */
  function getBeforeAfterBodyLines(callback) {
  	return pushOrConcat([], splitNewlines(callback));
  }
  
  var exports = module.exports = Element.extend({
  	initialize: function() {
  		this._model = getBaseModel(this._options);
  		this._lastActive = [];
  	},
  
  	// Get the title
  	// Args are: (tooltipItem, data)
  	getTitle: function() {
  		var me = this;
  		var opts = me._options;
  		var callbacks = opts.callbacks;
  
  		var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
  		var title = callbacks.title.apply(me, arguments);
  		var afterTitle = callbacks.afterTitle.apply(me, arguments);
  
  		var lines = [];
  		lines = pushOrConcat(lines, splitNewlines(beforeTitle));
  		lines = pushOrConcat(lines, splitNewlines(title));
  		lines = pushOrConcat(lines, splitNewlines(afterTitle));
  
  		return lines;
  	},
  
  	// Args are: (tooltipItem, data)
  	getBeforeBody: function() {
  		return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));
  	},
  
  	// Args are: (tooltipItem, data)
  	getBody: function(tooltipItems, data) {
  		var me = this;
  		var callbacks = me._options.callbacks;
  		var bodyItems = [];
  
  		helpers.each(tooltipItems, function(tooltipItem) {
  			var bodyItem = {
  				before: [],
  				lines: [],
  				after: []
  			};
  			pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));
  			pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
  			pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));
  
  			bodyItems.push(bodyItem);
  		});
  
  		return bodyItems;
  	},
  
  	// Args are: (tooltipItem, data)
  	getAfterBody: function() {
  		return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));
  	},
  
  	// Get the footer and beforeFooter and afterFooter lines
  	// Args are: (tooltipItem, data)
  	getFooter: function() {
  		var me = this;
  		var callbacks = me._options.callbacks;
  
  		var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
  		var footer = callbacks.footer.apply(me, arguments);
  		var afterFooter = callbacks.afterFooter.apply(me, arguments);
  
  		var lines = [];
  		lines = pushOrConcat(lines, splitNewlines(beforeFooter));
  		lines = pushOrConcat(lines, splitNewlines(footer));
  		lines = pushOrConcat(lines, splitNewlines(afterFooter));
  
  		return lines;
  	},
  
  	update: function(changed) {
  		var me = this;
  		var opts = me._options;
  
  		// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
  		// that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
  		// which breaks any animations.
  		var existingModel = me._model;
  		var model = me._model = getBaseModel(opts);
  		var active = me._active;
  
  		var data = me._data;
  
  		// In the case where active.length === 0 we need to keep these at existing values for good animations
  		var alignment = {
  			xAlign: existingModel.xAlign,
  			yAlign: existingModel.yAlign
  		};
  		var backgroundPoint = {
  			x: existingModel.x,
  			y: existingModel.y
  		};
  		var tooltipSize = {
  			width: existingModel.width,
  			height: existingModel.height
  		};
  		var tooltipPosition = {
  			x: existingModel.caretX,
  			y: existingModel.caretY
  		};
  
  		var i, len;
  
  		if (active.length) {
  			model.opacity = 1;
  
  			var labelColors = [];
  			var labelTextColors = [];
  			tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
  
  			var tooltipItems = [];
  			for (i = 0, len = active.length; i < len; ++i) {
  				tooltipItems.push(createTooltipItem(active[i]));
  			}
  
  			// If the user provided a filter function, use it to modify the tooltip items
  			if (opts.filter) {
  				tooltipItems = tooltipItems.filter(function(a) {
  					return opts.filter(a, data);
  				});
  			}
  
  			// If the user provided a sorting function, use it to modify the tooltip items
  			if (opts.itemSort) {
  				tooltipItems = tooltipItems.sort(function(a, b) {
  					return opts.itemSort(a, b, data);
  				});
  			}
  
  			// Determine colors for boxes
  			helpers.each(tooltipItems, function(tooltipItem) {
  				labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
  				labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
  			});
  
  
  			// Build the Text Lines
  			model.title = me.getTitle(tooltipItems, data);
  			model.beforeBody = me.getBeforeBody(tooltipItems, data);
  			model.body = me.getBody(tooltipItems, data);
  			model.afterBody = me.getAfterBody(tooltipItems, data);
  			model.footer = me.getFooter(tooltipItems, data);
  
  			// Initial positioning and colors
  			model.x = Math.round(tooltipPosition.x);
  			model.y = Math.round(tooltipPosition.y);
  			model.caretPadding = opts.caretPadding;
  			model.labelColors = labelColors;
  			model.labelTextColors = labelTextColors;
  
  			// data points
  			model.dataPoints = tooltipItems;
  
  			// We need to determine alignment of the tooltip
  			tooltipSize = getTooltipSize(this, model);
  			alignment = determineAlignment(this, tooltipSize);
  			// Final Size and Position
  			backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
  		} else {
  			model.opacity = 0;
  		}
  
  		model.xAlign = alignment.xAlign;
  		model.yAlign = alignment.yAlign;
  		model.x = backgroundPoint.x;
  		model.y = backgroundPoint.y;
  		model.width = tooltipSize.width;
  		model.height = tooltipSize.height;
  
  		// Point where the caret on the tooltip points to
  		model.caretX = tooltipPosition.x;
  		model.caretY = tooltipPosition.y;
  
  		me._model = model;
  
  		if (changed && opts.custom) {
  			opts.custom.call(me, model);
  		}
  
  		return me;
  	},
  
  	drawCaret: function(tooltipPoint, size) {
  		var ctx = this._chart.ctx;
  		var vm = this._view;
  		var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
  
  		ctx.lineTo(caretPosition.x1, caretPosition.y1);
  		ctx.lineTo(caretPosition.x2, caretPosition.y2);
  		ctx.lineTo(caretPosition.x3, caretPosition.y3);
  	},
  	getCaretPosition: function(tooltipPoint, size, vm) {
  		var x1, x2, x3, y1, y2, y3;
  		var caretSize = vm.caretSize;
  		var cornerRadius = vm.cornerRadius;
  		var xAlign = vm.xAlign;
  		var yAlign = vm.yAlign;
  		var ptX = tooltipPoint.x;
  		var ptY = tooltipPoint.y;
  		var width = size.width;
  		var height = size.height;
  
  		if (yAlign === 'center') {
  			y2 = ptY + (height / 2);
  
  			if (xAlign === 'left') {
  				x1 = ptX;
  				x2 = x1 - caretSize;
  				x3 = x1;
  
  				y1 = y2 + caretSize;
  				y3 = y2 - caretSize;
  			} else {
  				x1 = ptX + width;
  				x2 = x1 + caretSize;
  				x3 = x1;
  
  				y1 = y2 - caretSize;
  				y3 = y2 + caretSize;
  			}
  		} else {
  			if (xAlign === 'left') {
  				x2 = ptX + cornerRadius + (caretSize);
  				x1 = x2 - caretSize;
  				x3 = x2 + caretSize;
  			} else if (xAlign === 'right') {
  				x2 = ptX + width - cornerRadius - caretSize;
  				x1 = x2 - caretSize;
  				x3 = x2 + caretSize;
  			} else {
  				x2 = vm.caretX;
  				x1 = x2 - caretSize;
  				x3 = x2 + caretSize;
  			}
  			if (yAlign === 'top') {
  				y1 = ptY;
  				y2 = y1 - caretSize;
  				y3 = y1;
  			} else {
  				y1 = ptY + height;
  				y2 = y1 + caretSize;
  				y3 = y1;
  				// invert drawing order
  				var tmp = x3;
  				x3 = x1;
  				x1 = tmp;
  			}
  		}
  		return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
  	},
  
  	drawTitle: function(pt, vm, ctx, opacity) {
  		var title = vm.title;
  
  		if (title.length) {
  			ctx.textAlign = vm._titleAlign;
  			ctx.textBaseline = 'top';
  
  			var titleFontSize = vm.titleFontSize;
  			var titleSpacing = vm.titleSpacing;
  
  			ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
  			ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
  
  			var i, len;
  			for (i = 0, len = title.length; i < len; ++i) {
  				ctx.fillText(title[i], pt.x, pt.y);
  				pt.y += titleFontSize + titleSpacing; // Line Height and spacing
  
  				if (i + 1 === title.length) {
  					pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
  				}
  			}
  		}
  	},
  
  	drawBody: function(pt, vm, ctx, opacity) {
  		var bodyFontSize = vm.bodyFontSize;
  		var bodySpacing = vm.bodySpacing;
  		var body = vm.body;
  
  		ctx.textAlign = vm._bodyAlign;
  		ctx.textBaseline = 'top';
  		ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
  
  		// Before Body
  		var xLinePadding = 0;
  		var fillLineOfText = function(line) {
  			ctx.fillText(line, pt.x + xLinePadding, pt.y);
  			pt.y += bodyFontSize + bodySpacing;
  		};
  
  		// Before body lines
  		ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
  		helpers.each(vm.beforeBody, fillLineOfText);
  
  		var drawColorBoxes = vm.displayColors;
  		xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
  
  		// Draw body lines now
  		helpers.each(body, function(bodyItem, i) {
  			var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
  			ctx.fillStyle = textColor;
  			helpers.each(bodyItem.before, fillLineOfText);
  
  			helpers.each(bodyItem.lines, function(line) {
  				// Draw Legend-like boxes if needed
  				if (drawColorBoxes) {
  					// Fill a white rect so that colours merge nicely if the opacity is < 1
  					ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
  					ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
  
  					// Border
  					ctx.lineWidth = 1;
  					ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
  					ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
  
  					// Inner square
  					ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
  					ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
  					ctx.fillStyle = textColor;
  				}
  
  				fillLineOfText(line);
  			});
  
  			helpers.each(bodyItem.after, fillLineOfText);
  		});
  
  		// Reset back to 0 for after body
  		xLinePadding = 0;
  
  		// After body lines
  		helpers.each(vm.afterBody, fillLineOfText);
  		pt.y -= bodySpacing; // Remove last body spacing
  	},
  
  	drawFooter: function(pt, vm, ctx, opacity) {
  		var footer = vm.footer;
  
  		if (footer.length) {
  			pt.y += vm.footerMarginTop;
  
  			ctx.textAlign = vm._footerAlign;
  			ctx.textBaseline = 'top';
  
  			ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
  			ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
  
  			helpers.each(footer, function(line) {
  				ctx.fillText(line, pt.x, pt.y);
  				pt.y += vm.footerFontSize + vm.footerSpacing;
  			});
  		}
  	},
  
  	drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
  		ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
  		ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
  		ctx.lineWidth = vm.borderWidth;
  		var xAlign = vm.xAlign;
  		var yAlign = vm.yAlign;
  		var x = pt.x;
  		var y = pt.y;
  		var width = tooltipSize.width;
  		var height = tooltipSize.height;
  		var radius = vm.cornerRadius;
  
  		ctx.beginPath();
  		ctx.moveTo(x + radius, y);
  		if (yAlign === 'top') {
  			this.drawCaret(pt, tooltipSize);
  		}
  		ctx.lineTo(x + width - radius, y);
  		ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  		if (yAlign === 'center' && xAlign === 'right') {
  			this.drawCaret(pt, tooltipSize);
  		}
  		ctx.lineTo(x + width, y + height - radius);
  		ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  		if (yAlign === 'bottom') {
  			this.drawCaret(pt, tooltipSize);
  		}
  		ctx.lineTo(x + radius, y + height);
  		ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  		if (yAlign === 'center' && xAlign === 'left') {
  			this.drawCaret(pt, tooltipSize);
  		}
  		ctx.lineTo(x, y + radius);
  		ctx.quadraticCurveTo(x, y, x + radius, y);
  		ctx.closePath();
  
  		ctx.fill();
  
  		if (vm.borderWidth > 0) {
  			ctx.stroke();
  		}
  	},
  
  	draw: function() {
  		var ctx = this._chart.ctx;
  		var vm = this._view;
  
  		if (vm.opacity === 0) {
  			return;
  		}
  
  		var tooltipSize = {
  			width: vm.width,
  			height: vm.height
  		};
  		var pt = {
  			x: vm.x,
  			y: vm.y
  		};
  
  		// IE11/Edge does not like very small opacities, so snap to 0
  		var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
  
  		// Truthy/falsey value for empty tooltip
  		var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
  
  		if (this._options.enabled && hasTooltipContent) {
  			// Draw Background
  			this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
  
  			// Draw Title, Body, and Footer
  			pt.x += vm.xPadding;
  			pt.y += vm.yPadding;
  
  			// Titles
  			this.drawTitle(pt, vm, ctx, opacity);
  
  			// Body
  			this.drawBody(pt, vm, ctx, opacity);
  
  			// Footer
  			this.drawFooter(pt, vm, ctx, opacity);
  		}
  	},
  
  	/**
  	 * Handle an event
  	 * @private
  	 * @param {IEvent} event - The event to handle
  	 * @returns {Boolean} true if the tooltip changed
  	 */
  	handleEvent: function(e) {
  		var me = this;
  		var options = me._options;
  		var changed = false;
  
  		me._lastActive = me._lastActive || [];
  
  		// Find Active Elements for tooltips
  		if (e.type === 'mouseout') {
  			me._active = [];
  		} else {
  			me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
  		}
  
  		// Remember Last Actives
  		changed = !helpers.arrayEquals(me._active, me._lastActive);
  
  		// Only handle target event on tooltip change
  		if (changed) {
  			me._lastActive = me._active;
  
  			if (options.enabled || options.custom) {
  				me._eventPosition = {
  					x: e.x,
  					y: e.y
  				};
  
  				me.update(true);
  				me.pivot();
  			}
  		}
  
  		return changed;
  	}
  });
  
  /**
   * @namespace Chart.Tooltip.positioners
   */
  exports.positioners = positioners;
  
  
  },{"26":26,"27":27,"46":46}],37:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  
  defaults._set('global', {
  	elements: {
  		arc: {
  			backgroundColor: defaults.global.defaultColor,
  			borderColor: '#fff',
  			borderWidth: 2
  		}
  	}
  });
  
  module.exports = Element.extend({
  	inLabelRange: function(mouseX) {
  		var vm = this._view;
  
  		if (vm) {
  			return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
  		}
  		return false;
  	},
  
  	inRange: function(chartX, chartY) {
  		var vm = this._view;
  
  		if (vm) {
  			var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY});
  			var	angle = pointRelativePosition.angle;
  			var distance = pointRelativePosition.distance;
  
  			// Sanitise angle range
  			var startAngle = vm.startAngle;
  			var endAngle = vm.endAngle;
  			while (endAngle < startAngle) {
  				endAngle += 2.0 * Math.PI;
  			}
  			while (angle > endAngle) {
  				angle -= 2.0 * Math.PI;
  			}
  			while (angle < startAngle) {
  				angle += 2.0 * Math.PI;
  			}
  
  			// Check if within the range of the open/close angle
  			var betweenAngles = (angle >= startAngle && angle <= endAngle);
  			var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
  
  			return (betweenAngles && withinRadius);
  		}
  		return false;
  	},
  
  	getCenterPoint: function() {
  		var vm = this._view;
  		var halfAngle = (vm.startAngle + vm.endAngle) / 2;
  		var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
  		return {
  			x: vm.x + Math.cos(halfAngle) * halfRadius,
  			y: vm.y + Math.sin(halfAngle) * halfRadius
  		};
  	},
  
  	getArea: function() {
  		var vm = this._view;
  		return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
  	},
  
  	tooltipPosition: function() {
  		var vm = this._view;
  		var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
  		var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
  
  		return {
  			x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
  			y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
  		};
  	},
  
  	draw: function() {
  		var ctx = this._chart.ctx;
  		var vm = this._view;
  		var sA = vm.startAngle;
  		var eA = vm.endAngle;
  
  		ctx.beginPath();
  
  		ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
  		ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
  
  		ctx.closePath();
  		ctx.strokeStyle = vm.borderColor;
  		ctx.lineWidth = vm.borderWidth;
  
  		ctx.fillStyle = vm.backgroundColor;
  
  		ctx.fill();
  		ctx.lineJoin = 'bevel';
  
  		if (vm.borderWidth) {
  			ctx.stroke();
  		}
  	}
  });
  
  },{"26":26,"27":27,"46":46}],38:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  
  var globalDefaults = defaults.global;
  
  defaults._set('global', {
  	elements: {
  		line: {
  			tension: 0.4,
  			backgroundColor: globalDefaults.defaultColor,
  			borderWidth: 3,
  			borderColor: globalDefaults.defaultColor,
  			borderCapStyle: 'butt',
  			borderDash: [],
  			borderDashOffset: 0.0,
  			borderJoinStyle: 'miter',
  			capBezierPoints: true,
  			fill: true, // do we fill in the area between the line and its base axis
  		}
  	}
  });
  
  module.exports = Element.extend({
  	draw: function() {
  		var me = this;
  		var vm = me._view;
  		var ctx = me._chart.ctx;
  		var spanGaps = vm.spanGaps;
  		var points = me._children.slice(); // clone array
  		var globalOptionLineElements = globalDefaults.elements.line;
  		var lastDrawnIndex = -1;
  		var index, current, previous, currentVM;
  
  		// If we are looping, adding the first point again
  		if (me._loop && points.length) {
  			points.push(points[0]);
  		}
  
  		ctx.save();
  
  		// Stroke Line Options
  		ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
  
  		// IE 9 and 10 do not support line dash
  		if (ctx.setLineDash) {
  			ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
  		}
  
  		ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
  		ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
  		ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
  		ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
  
  		// Stroke Line
  		ctx.beginPath();
  		lastDrawnIndex = -1;
  
  		for (index = 0; index < points.length; ++index) {
  			current = points[index];
  			previous = helpers.previousItem(points, index);
  			currentVM = current._view;
  
  			// First point moves to it's starting position no matter what
  			if (index === 0) {
  				if (!currentVM.skip) {
  					ctx.moveTo(currentVM.x, currentVM.y);
  					lastDrawnIndex = index;
  				}
  			} else {
  				previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
  
  				if (!currentVM.skip) {
  					if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
  						// There was a gap and this is the first point after the gap
  						ctx.moveTo(currentVM.x, currentVM.y);
  					} else {
  						// Line to next point
  						helpers.canvas.lineTo(ctx, previous._view, current._view);
  					}
  					lastDrawnIndex = index;
  				}
  			}
  		}
  
  		ctx.stroke();
  		ctx.restore();
  	}
  });
  
  },{"26":26,"27":27,"46":46}],39:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  
  var defaultColor = defaults.global.defaultColor;
  
  defaults._set('global', {
  	elements: {
  		point: {
  			radius: 3,
  			pointStyle: 'circle',
  			backgroundColor: defaultColor,
  			borderColor: defaultColor,
  			borderWidth: 1,
  			// Hover
  			hitRadius: 1,
  			hoverRadius: 4,
  			hoverBorderWidth: 1
  		}
  	}
  });
  
  function xRange(mouseX) {
  	var vm = this._view;
  	return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
  }
  
  function yRange(mouseY) {
  	var vm = this._view;
  	return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
  }
  
  module.exports = Element.extend({
  	inRange: function(mouseX, mouseY) {
  		var vm = this._view;
  		return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
  	},
  
  	inLabelRange: xRange,
  	inXRange: xRange,
  	inYRange: yRange,
  
  	getCenterPoint: function() {
  		var vm = this._view;
  		return {
  			x: vm.x,
  			y: vm.y
  		};
  	},
  
  	getArea: function() {
  		return Math.PI * Math.pow(this._view.radius, 2);
  	},
  
  	tooltipPosition: function() {
  		var vm = this._view;
  		return {
  			x: vm.x,
  			y: vm.y,
  			padding: vm.radius + vm.borderWidth
  		};
  	},
  
  	draw: function(chartArea) {
  		var vm = this._view;
  		var model = this._model;
  		var ctx = this._chart.ctx;
  		var pointStyle = vm.pointStyle;
  		var rotation = vm.rotation;
  		var radius = vm.radius;
  		var x = vm.x;
  		var y = vm.y;
  		var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
  
  		if (vm.skip) {
  			return;
  		}
  
  		// Clipping for Points.
  		if (chartArea === undefined || (model.x >= chartArea.left && chartArea.right * errMargin >= model.x && model.y >= chartArea.top && chartArea.bottom * errMargin >= model.y)) {
  			ctx.strokeStyle = vm.borderColor || defaultColor;
  			ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth);
  			ctx.fillStyle = vm.backgroundColor || defaultColor;
  			helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
  		}
  	}
  });
  
  },{"26":26,"27":27,"46":46}],40:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  
  defaults._set('global', {
  	elements: {
  		rectangle: {
  			backgroundColor: defaults.global.defaultColor,
  			borderColor: defaults.global.defaultColor,
  			borderSkipped: 'bottom',
  			borderWidth: 0
  		}
  	}
  });
  
  function isVertical(bar) {
  	return bar._view.width !== undefined;
  }
  
  /**
   * Helper function to get the bounds of the bar regardless of the orientation
   * @param bar {Chart.Element.Rectangle} the bar
   * @return {Bounds} bounds of the bar
   * @private
   */
  function getBarBounds(bar) {
  	var vm = bar._view;
  	var x1, x2, y1, y2;
  
  	if (isVertical(bar)) {
  		// vertical
  		var halfWidth = vm.width / 2;
  		x1 = vm.x - halfWidth;
  		x2 = vm.x + halfWidth;
  		y1 = Math.min(vm.y, vm.base);
  		y2 = Math.max(vm.y, vm.base);
  	} else {
  		// horizontal bar
  		var halfHeight = vm.height / 2;
  		x1 = Math.min(vm.x, vm.base);
  		x2 = Math.max(vm.x, vm.base);
  		y1 = vm.y - halfHeight;
  		y2 = vm.y + halfHeight;
  	}
  
  	return {
  		left: x1,
  		top: y1,
  		right: x2,
  		bottom: y2
  	};
  }
  
  module.exports = Element.extend({
  	draw: function() {
  		var ctx = this._chart.ctx;
  		var vm = this._view;
  		var left, right, top, bottom, signX, signY, borderSkipped;
  		var borderWidth = vm.borderWidth;
  
  		if (!vm.horizontal) {
  			// bar
  			left = vm.x - vm.width / 2;
  			right = vm.x + vm.width / 2;
  			top = vm.y;
  			bottom = vm.base;
  			signX = 1;
  			signY = bottom > top ? 1 : -1;
  			borderSkipped = vm.borderSkipped || 'bottom';
  		} else {
  			// horizontal bar
  			left = vm.base;
  			right = vm.x;
  			top = vm.y - vm.height / 2;
  			bottom = vm.y + vm.height / 2;
  			signX = right > left ? 1 : -1;
  			signY = 1;
  			borderSkipped = vm.borderSkipped || 'left';
  		}
  
  		// Canvas doesn't allow us to stroke inside the width so we can
  		// adjust the sizes to fit if we're setting a stroke on the line
  		if (borderWidth) {
  			// borderWidth shold be less than bar width and bar height.
  			var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
  			borderWidth = borderWidth > barSize ? barSize : borderWidth;
  			var halfStroke = borderWidth / 2;
  			// Adjust borderWidth when bar top position is near vm.base(zero).
  			var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
  			var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
  			var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
  			var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
  			// not become a vertical line?
  			if (borderLeft !== borderRight) {
  				top = borderTop;
  				bottom = borderBottom;
  			}
  			// not become a horizontal line?
  			if (borderTop !== borderBottom) {
  				left = borderLeft;
  				right = borderRight;
  			}
  		}
  
  		ctx.beginPath();
  		ctx.fillStyle = vm.backgroundColor;
  		ctx.strokeStyle = vm.borderColor;
  		ctx.lineWidth = borderWidth;
  
  		// Corner points, from bottom-left to bottom-right clockwise
  		// | 1 2 |
  		// | 0 3 |
  		var corners = [
  			[left, bottom],
  			[left, top],
  			[right, top],
  			[right, bottom]
  		];
  
  		// Find first (starting) corner with fallback to 'bottom'
  		var borders = ['bottom', 'left', 'top', 'right'];
  		var startCorner = borders.indexOf(borderSkipped, 0);
  		if (startCorner === -1) {
  			startCorner = 0;
  		}
  
  		function cornerAt(index) {
  			return corners[(startCorner + index) % 4];
  		}
  
  		// Draw rectangle from 'startCorner'
  		var corner = cornerAt(0);
  		ctx.moveTo(corner[0], corner[1]);
  
  		for (var i = 1; i < 4; i++) {
  			corner = cornerAt(i);
  			ctx.lineTo(corner[0], corner[1]);
  		}
  
  		ctx.fill();
  		if (borderWidth) {
  			ctx.stroke();
  		}
  	},
  
  	height: function() {
  		var vm = this._view;
  		return vm.base - vm.y;
  	},
  
  	inRange: function(mouseX, mouseY) {
  		var inRange = false;
  
  		if (this._view) {
  			var bounds = getBarBounds(this);
  			inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
  		}
  
  		return inRange;
  	},
  
  	inLabelRange: function(mouseX, mouseY) {
  		var me = this;
  		if (!me._view) {
  			return false;
  		}
  
  		var inRange = false;
  		var bounds = getBarBounds(me);
  
  		if (isVertical(me)) {
  			inRange = mouseX >= bounds.left && mouseX <= bounds.right;
  		} else {
  			inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
  		}
  
  		return inRange;
  	},
  
  	inXRange: function(mouseX) {
  		var bounds = getBarBounds(this);
  		return mouseX >= bounds.left && mouseX <= bounds.right;
  	},
  
  	inYRange: function(mouseY) {
  		var bounds = getBarBounds(this);
  		return mouseY >= bounds.top && mouseY <= bounds.bottom;
  	},
  
  	getCenterPoint: function() {
  		var vm = this._view;
  		var x, y;
  		if (isVertical(this)) {
  			x = vm.x;
  			y = (vm.y + vm.base) / 2;
  		} else {
  			x = (vm.x + vm.base) / 2;
  			y = vm.y;
  		}
  
  		return {x: x, y: y};
  	},
  
  	getArea: function() {
  		var vm = this._view;
  		return vm.width * Math.abs(vm.y - vm.base);
  	},
  
  	tooltipPosition: function() {
  		var vm = this._view;
  		return {
  			x: vm.x,
  			y: vm.y
  		};
  	}
  });
  
  },{"26":26,"27":27}],41:[function(require,module,exports){
  'use strict';
  
  module.exports = {};
  module.exports.Arc = require(37);
  module.exports.Line = require(38);
  module.exports.Point = require(39);
  module.exports.Rectangle = require(40);
  
  },{"37":37,"38":38,"39":39,"40":40}],42:[function(require,module,exports){
  'use strict';
  
  var helpers = require(43);
  
  /**
   * @namespace Chart.helpers.canvas
   */
  var exports = module.exports = {
  	/**
  	 * Clears the entire canvas associated to the given `chart`.
  	 * @param {Chart} chart - The chart for which to clear the canvas.
  	 */
  	clear: function(chart) {
  		chart.ctx.clearRect(0, 0, chart.width, chart.height);
  	},
  
  	/**
  	 * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
  	 * given size (width, height) and the same `radius` for all corners.
  	 * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
  	 * @param {Number} x - The x axis of the coordinate for the rectangle starting point.
  	 * @param {Number} y - The y axis of the coordinate for the rectangle starting point.
  	 * @param {Number} width - The rectangle's width.
  	 * @param {Number} height - The rectangle's height.
  	 * @param {Number} radius - The rounded amount (in pixels) for the four corners.
  	 * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
  	 */
  	roundedRect: function(ctx, x, y, width, height, radius) {
  		if (radius) {
  			// NOTE(SB) `epsilon` helps to prevent minor artifacts appearing
  			// on Chrome when `r` is exactly half the height or the width.
  			var epsilon = 0.0000001;
  			var r = Math.min(radius, (height / 2) - epsilon, (width / 2) - epsilon);
  
  			ctx.moveTo(x + r, y);
  			ctx.lineTo(x + width - r, y);
  			ctx.arcTo(x + width, y, x + width, y + r, r);
  			ctx.lineTo(x + width, y + height - r);
  			ctx.arcTo(x + width, y + height, x + width - r, y + height, r);
  			ctx.lineTo(x + r, y + height);
  			ctx.arcTo(x, y + height, x, y + height - r, r);
  			ctx.lineTo(x, y + r);
  			ctx.arcTo(x, y, x + r, y, r);
  			ctx.closePath();
  			ctx.moveTo(x, y);
  		} else {
  			ctx.rect(x, y, width, height);
  		}
  	},
  
  	drawPoint: function(ctx, style, radius, x, y, rotation) {
  		var type, edgeLength, xOffset, yOffset, height, size;
  		rotation = rotation || 0;
  
  		if (style && typeof style === 'object') {
  			type = style.toString();
  			if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
  				ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
  				return;
  			}
  		}
  
  		if (isNaN(radius) || radius <= 0) {
  			return;
  		}
  
  		ctx.save();
  		ctx.translate(x, y);
  		ctx.rotate(rotation * Math.PI / 180);
  		ctx.beginPath();
  
  		switch (style) {
  		// Default includes circle
  		default:
  			ctx.arc(0, 0, radius, 0, Math.PI * 2);
  			ctx.closePath();
  			break;
  		case 'triangle':
  			edgeLength = 3 * radius / Math.sqrt(3);
  			height = edgeLength * Math.sqrt(3) / 2;
  			ctx.moveTo(-edgeLength / 2, height / 3);
  			ctx.lineTo(edgeLength / 2, height / 3);
  			ctx.lineTo(0, -2 * height / 3);
  			ctx.closePath();
  			break;
  		case 'rect':
  			size = 1 / Math.SQRT2 * radius;
  			ctx.rect(-size, -size, 2 * size, 2 * size);
  			break;
  		case 'rectRounded':
  			var offset = radius / Math.SQRT2;
  			var leftX = -offset;
  			var topY = -offset;
  			var sideSize = Math.SQRT2 * radius;
  
  			// NOTE(SB) the rounded rect implementation changed to use `arcTo`
  			// instead of `quadraticCurveTo` since it generates better results
  			// when rect is almost a circle. 0.425 (instead of 0.5) produces
  			// results visually closer to the previous impl.
  			this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius * 0.425);
  			break;
  		case 'rectRot':
  			size = 1 / Math.SQRT2 * radius;
  			ctx.moveTo(-size, 0);
  			ctx.lineTo(0, size);
  			ctx.lineTo(size, 0);
  			ctx.lineTo(0, -size);
  			ctx.closePath();
  			break;
  		case 'cross':
  			ctx.moveTo(0, radius);
  			ctx.lineTo(0, -radius);
  			ctx.moveTo(-radius, 0);
  			ctx.lineTo(radius, 0);
  			break;
  		case 'crossRot':
  			xOffset = Math.cos(Math.PI / 4) * radius;
  			yOffset = Math.sin(Math.PI / 4) * radius;
  			ctx.moveTo(-xOffset, -yOffset);
  			ctx.lineTo(xOffset, yOffset);
  			ctx.moveTo(-xOffset, yOffset);
  			ctx.lineTo(xOffset, -yOffset);
  			break;
  		case 'star':
  			ctx.moveTo(0, radius);
  			ctx.lineTo(0, -radius);
  			ctx.moveTo(-radius, 0);
  			ctx.lineTo(radius, 0);
  			xOffset = Math.cos(Math.PI / 4) * radius;
  			yOffset = Math.sin(Math.PI / 4) * radius;
  			ctx.moveTo(-xOffset, -yOffset);
  			ctx.lineTo(xOffset, yOffset);
  			ctx.moveTo(-xOffset, yOffset);
  			ctx.lineTo(xOffset, -yOffset);
  			break;
  		case 'line':
  			ctx.moveTo(-radius, 0);
  			ctx.lineTo(radius, 0);
  			break;
  		case 'dash':
  			ctx.moveTo(0, 0);
  			ctx.lineTo(radius, 0);
  			break;
  		}
  
  		ctx.fill();
  		ctx.stroke();
  		ctx.restore();
  	},
  
  	clipArea: function(ctx, area) {
  		ctx.save();
  		ctx.beginPath();
  		ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
  		ctx.clip();
  	},
  
  	unclipArea: function(ctx) {
  		ctx.restore();
  	},
  
  	lineTo: function(ctx, previous, target, flip) {
  		if (target.steppedLine) {
  			if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) {
  				ctx.lineTo(previous.x, target.y);
  			} else {
  				ctx.lineTo(target.x, previous.y);
  			}
  			ctx.lineTo(target.x, target.y);
  			return;
  		}
  
  		if (!target.tension) {
  			ctx.lineTo(target.x, target.y);
  			return;
  		}
  
  		ctx.bezierCurveTo(
  			flip ? previous.controlPointPreviousX : previous.controlPointNextX,
  			flip ? previous.controlPointPreviousY : previous.controlPointNextY,
  			flip ? target.controlPointNextX : target.controlPointPreviousX,
  			flip ? target.controlPointNextY : target.controlPointPreviousY,
  			target.x,
  			target.y);
  	}
  };
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
   * @namespace Chart.helpers.clear
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.clear = exports.clear;
  
  /**
   * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
   * @namespace Chart.helpers.drawRoundedRectangle
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.drawRoundedRectangle = function(ctx) {
  	ctx.beginPath();
  	exports.roundedRect.apply(exports, arguments);
  };
  
  },{"43":43}],43:[function(require,module,exports){
  'use strict';
  
  /**
   * @namespace Chart.helpers
   */
  var helpers = {
  	/**
  	 * An empty function that can be used, for example, for optional callback.
  	 */
  	noop: function() {},
  
  	/**
  	 * Returns a unique id, sequentially generated from a global variable.
  	 * @returns {Number}
  	 * @function
  	 */
  	uid: (function() {
  		var id = 0;
  		return function() {
  			return id++;
  		};
  	}()),
  
  	/**
  	 * Returns true if `value` is neither null nor undefined, else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @since 2.7.0
  	 */
  	isNullOrUndef: function(value) {
  		return value === null || typeof value === 'undefined';
  	},
  
  	/**
  	 * Returns true if `value` is an array, else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @function
  	 */
  	isArray: Array.isArray ? Array.isArray : function(value) {
  		return Object.prototype.toString.call(value) === '[object Array]';
  	},
  
  	/**
  	 * Returns true if `value` is an object (excluding null), else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @since 2.7.0
  	 */
  	isObject: function(value) {
  		return value !== null && Object.prototype.toString.call(value) === '[object Object]';
  	},
  
  	/**
  	 * Returns `value` if defined, else returns `defaultValue`.
  	 * @param {*} value - The value to return if defined.
  	 * @param {*} defaultValue - The value to return if `value` is undefined.
  	 * @returns {*}
  	 */
  	valueOrDefault: function(value, defaultValue) {
  		return typeof value === 'undefined' ? defaultValue : value;
  	},
  
  	/**
  	 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
  	 * @param {Array} value - The array to lookup for value at `index`.
  	 * @param {Number} index - The index in `value` to lookup for value.
  	 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
  	 * @returns {*}
  	 */
  	valueAtIndexOrDefault: function(value, index, defaultValue) {
  		return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
  	},
  
  	/**
  	 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
  	 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
  	 * @param {Function} fn - The function to call.
  	 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
  	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
  	 * @returns {*}
  	 */
  	callback: function(fn, args, thisArg) {
  		if (fn && typeof fn.call === 'function') {
  			return fn.apply(thisArg, args);
  		}
  	},
  
  	/**
  	 * Note(SB) for performance sake, this method should only be used when loopable type
  	 * is unknown or in none intensive code (not called often and small loopable). Else
  	 * it's preferable to use a regular for() loop and save extra function calls.
  	 * @param {Object|Array} loopable - The object or array to be iterated.
  	 * @param {Function} fn - The function to call for each item.
  	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
  	 * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
  	 */
  	each: function(loopable, fn, thisArg, reverse) {
  		var i, len, keys;
  		if (helpers.isArray(loopable)) {
  			len = loopable.length;
  			if (reverse) {
  				for (i = len - 1; i >= 0; i--) {
  					fn.call(thisArg, loopable[i], i);
  				}
  			} else {
  				for (i = 0; i < len; i++) {
  					fn.call(thisArg, loopable[i], i);
  				}
  			}
  		} else if (helpers.isObject(loopable)) {
  			keys = Object.keys(loopable);
  			len = keys.length;
  			for (i = 0; i < len; i++) {
  				fn.call(thisArg, loopable[keys[i]], keys[i]);
  			}
  		}
  	},
  
  	/**
  	 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
  	 * @see http://stackoverflow.com/a/14853974
  	 * @param {Array} a0 - The array to compare
  	 * @param {Array} a1 - The array to compare
  	 * @returns {Boolean}
  	 */
  	arrayEquals: function(a0, a1) {
  		var i, ilen, v0, v1;
  
  		if (!a0 || !a1 || a0.length !== a1.length) {
  			return false;
  		}
  
  		for (i = 0, ilen = a0.length; i < ilen; ++i) {
  			v0 = a0[i];
  			v1 = a1[i];
  
  			if (v0 instanceof Array && v1 instanceof Array) {
  				if (!helpers.arrayEquals(v0, v1)) {
  					return false;
  				}
  			} else if (v0 !== v1) {
  				// NOTE: two different object instances will never be equal: {x:20} != {x:20}
  				return false;
  			}
  		}
  
  		return true;
  	},
  
  	/**
  	 * Returns a deep copy of `source` without keeping references on objects and arrays.
  	 * @param {*} source - The value to clone.
  	 * @returns {*}
  	 */
  	clone: function(source) {
  		if (helpers.isArray(source)) {
  			return source.map(helpers.clone);
  		}
  
  		if (helpers.isObject(source)) {
  			var target = {};
  			var keys = Object.keys(source);
  			var klen = keys.length;
  			var k = 0;
  
  			for (; k < klen; ++k) {
  				target[keys[k]] = helpers.clone(source[keys[k]]);
  			}
  
  			return target;
  		}
  
  		return source;
  	},
  
  	/**
  	 * The default merger when Chart.helpers.merge is called without merger option.
  	 * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
  	 * @private
  	 */
  	_merger: function(key, target, source, options) {
  		var tval = target[key];
  		var sval = source[key];
  
  		if (helpers.isObject(tval) && helpers.isObject(sval)) {
  			helpers.merge(tval, sval, options);
  		} else {
  			target[key] = helpers.clone(sval);
  		}
  	},
  
  	/**
  	 * Merges source[key] in target[key] only if target[key] is undefined.
  	 * @private
  	 */
  	_mergerIf: function(key, target, source) {
  		var tval = target[key];
  		var sval = source[key];
  
  		if (helpers.isObject(tval) && helpers.isObject(sval)) {
  			helpers.mergeIf(tval, sval);
  		} else if (!target.hasOwnProperty(key)) {
  			target[key] = helpers.clone(sval);
  		}
  	},
  
  	/**
  	 * Recursively deep copies `source` properties into `target` with the given `options`.
  	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
  	 * @param {Object} target - The target object in which all sources are merged into.
  	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
  	 * @param {Object} [options] - Merging options:
  	 * @param {Function} [options.merger] - The merge method (key, target, source, options)
  	 * @returns {Object} The `target` object.
  	 */
  	merge: function(target, source, options) {
  		var sources = helpers.isArray(source) ? source : [source];
  		var ilen = sources.length;
  		var merge, i, keys, klen, k;
  
  		if (!helpers.isObject(target)) {
  			return target;
  		}
  
  		options = options || {};
  		merge = options.merger || helpers._merger;
  
  		for (i = 0; i < ilen; ++i) {
  			source = sources[i];
  			if (!helpers.isObject(source)) {
  				continue;
  			}
  
  			keys = Object.keys(source);
  			for (k = 0, klen = keys.length; k < klen; ++k) {
  				merge(keys[k], target, source, options);
  			}
  		}
  
  		return target;
  	},
  
  	/**
  	 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
  	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
  	 * @param {Object} target - The target object in which all sources are merged into.
  	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
  	 * @returns {Object} The `target` object.
  	 */
  	mergeIf: function(target, source) {
  		return helpers.merge(target, source, {merger: helpers._mergerIf});
  	},
  
  	/**
  	 * Applies the contents of two or more objects together into the first object.
  	 * @param {Object} target - The target object in which all objects are merged into.
  	 * @param {Object} arg1 - Object containing additional properties to merge in target.
  	 * @param {Object} argN - Additional objects containing properties to merge in target.
  	 * @returns {Object} The `target` object.
  	 */
  	extend: function(target) {
  		var setFn = function(value, key) {
  			target[key] = value;
  		};
  		for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
  			helpers.each(arguments[i], setFn);
  		}
  		return target;
  	},
  
  	/**
  	 * Basic javascript inheritance based on the model created in Backbone.js
  	 */
  	inherits: function(extensions) {
  		var me = this;
  		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
  			return me.apply(this, arguments);
  		};
  
  		var Surrogate = function() {
  			this.constructor = ChartElement;
  		};
  
  		Surrogate.prototype = me.prototype;
  		ChartElement.prototype = new Surrogate();
  		ChartElement.extend = helpers.inherits;
  
  		if (extensions) {
  			helpers.extend(ChartElement.prototype, extensions);
  		}
  
  		ChartElement.__super__ = me.prototype;
  		return ChartElement;
  	}
  };
  
  module.exports = helpers;
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use Chart.helpers.callback instead.
   * @function Chart.helpers.callCallback
   * @deprecated since version 2.6.0
   * @todo remove at version 3
   * @private
   */
  helpers.callCallback = helpers.callback;
  
  /**
   * Provided for backward compatibility, use Array.prototype.indexOf instead.
   * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
   * @function Chart.helpers.indexOf
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.indexOf = function(array, item, fromIndex) {
  	return Array.prototype.indexOf.call(array, item, fromIndex);
  };
  
  /**
   * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
   * @function Chart.helpers.getValueOrDefault
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.getValueOrDefault = helpers.valueOrDefault;
  
  /**
   * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
   * @function Chart.helpers.getValueAtIndexOrDefault
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
  
  },{}],44:[function(require,module,exports){
  'use strict';
  
  var helpers = require(43);
  
  /**
   * Easing functions adapted from Robert Penner's easing equations.
   * @namespace Chart.helpers.easingEffects
   * @see http://www.robertpenner.com/easing/
   */
  var effects = {
  	linear: function(t) {
  		return t;
  	},
  
  	easeInQuad: function(t) {
  		return t * t;
  	},
  
  	easeOutQuad: function(t) {
  		return -t * (t - 2);
  	},
  
  	easeInOutQuad: function(t) {
  		if ((t /= 0.5) < 1) {
  			return 0.5 * t * t;
  		}
  		return -0.5 * ((--t) * (t - 2) - 1);
  	},
  
  	easeInCubic: function(t) {
  		return t * t * t;
  	},
  
  	easeOutCubic: function(t) {
  		return (t = t - 1) * t * t + 1;
  	},
  
  	easeInOutCubic: function(t) {
  		if ((t /= 0.5) < 1) {
  			return 0.5 * t * t * t;
  		}
  		return 0.5 * ((t -= 2) * t * t + 2);
  	},
  
  	easeInQuart: function(t) {
  		return t * t * t * t;
  	},
  
  	easeOutQuart: function(t) {
  		return -((t = t - 1) * t * t * t - 1);
  	},
  
  	easeInOutQuart: function(t) {
  		if ((t /= 0.5) < 1) {
  			return 0.5 * t * t * t * t;
  		}
  		return -0.5 * ((t -= 2) * t * t * t - 2);
  	},
  
  	easeInQuint: function(t) {
  		return t * t * t * t * t;
  	},
  
  	easeOutQuint: function(t) {
  		return (t = t - 1) * t * t * t * t + 1;
  	},
  
  	easeInOutQuint: function(t) {
  		if ((t /= 0.5) < 1) {
  			return 0.5 * t * t * t * t * t;
  		}
  		return 0.5 * ((t -= 2) * t * t * t * t + 2);
  	},
  
  	easeInSine: function(t) {
  		return -Math.cos(t * (Math.PI / 2)) + 1;
  	},
  
  	easeOutSine: function(t) {
  		return Math.sin(t * (Math.PI / 2));
  	},
  
  	easeInOutSine: function(t) {
  		return -0.5 * (Math.cos(Math.PI * t) - 1);
  	},
  
  	easeInExpo: function(t) {
  		return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
  	},
  
  	easeOutExpo: function(t) {
  		return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
  	},
  
  	easeInOutExpo: function(t) {
  		if (t === 0) {
  			return 0;
  		}
  		if (t === 1) {
  			return 1;
  		}
  		if ((t /= 0.5) < 1) {
  			return 0.5 * Math.pow(2, 10 * (t - 1));
  		}
  		return 0.5 * (-Math.pow(2, -10 * --t) + 2);
  	},
  
  	easeInCirc: function(t) {
  		if (t >= 1) {
  			return t;
  		}
  		return -(Math.sqrt(1 - t * t) - 1);
  	},
  
  	easeOutCirc: function(t) {
  		return Math.sqrt(1 - (t = t - 1) * t);
  	},
  
  	easeInOutCirc: function(t) {
  		if ((t /= 0.5) < 1) {
  			return -0.5 * (Math.sqrt(1 - t * t) - 1);
  		}
  		return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
  	},
  
  	easeInElastic: function(t) {
  		var s = 1.70158;
  		var p = 0;
  		var a = 1;
  		if (t === 0) {
  			return 0;
  		}
  		if (t === 1) {
  			return 1;
  		}
  		if (!p) {
  			p = 0.3;
  		}
  		if (a < 1) {
  			a = 1;
  			s = p / 4;
  		} else {
  			s = p / (2 * Math.PI) * Math.asin(1 / a);
  		}
  		return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
  	},
  
  	easeOutElastic: function(t) {
  		var s = 1.70158;
  		var p = 0;
  		var a = 1;
  		if (t === 0) {
  			return 0;
  		}
  		if (t === 1) {
  			return 1;
  		}
  		if (!p) {
  			p = 0.3;
  		}
  		if (a < 1) {
  			a = 1;
  			s = p / 4;
  		} else {
  			s = p / (2 * Math.PI) * Math.asin(1 / a);
  		}
  		return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
  	},
  
  	easeInOutElastic: function(t) {
  		var s = 1.70158;
  		var p = 0;
  		var a = 1;
  		if (t === 0) {
  			return 0;
  		}
  		if ((t /= 0.5) === 2) {
  			return 1;
  		}
  		if (!p) {
  			p = 0.45;
  		}
  		if (a < 1) {
  			a = 1;
  			s = p / 4;
  		} else {
  			s = p / (2 * Math.PI) * Math.asin(1 / a);
  		}
  		if (t < 1) {
  			return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
  		}
  		return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
  	},
  	easeInBack: function(t) {
  		var s = 1.70158;
  		return t * t * ((s + 1) * t - s);
  	},
  
  	easeOutBack: function(t) {
  		var s = 1.70158;
  		return (t = t - 1) * t * ((s + 1) * t + s) + 1;
  	},
  
  	easeInOutBack: function(t) {
  		var s = 1.70158;
  		if ((t /= 0.5) < 1) {
  			return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
  		}
  		return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
  	},
  
  	easeInBounce: function(t) {
  		return 1 - effects.easeOutBounce(1 - t);
  	},
  
  	easeOutBounce: function(t) {
  		if (t < (1 / 2.75)) {
  			return 7.5625 * t * t;
  		}
  		if (t < (2 / 2.75)) {
  			return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
  		}
  		if (t < (2.5 / 2.75)) {
  			return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
  		}
  		return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
  	},
  
  	easeInOutBounce: function(t) {
  		if (t < 0.5) {
  			return effects.easeInBounce(t * 2) * 0.5;
  		}
  		return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
  	}
  };
  
  module.exports = {
  	effects: effects
  };
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
   * @function Chart.helpers.easingEffects
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.easingEffects = effects;
  
  },{"43":43}],45:[function(require,module,exports){
  'use strict';
  
  var helpers = require(43);
  
  /**
   * @alias Chart.helpers.options
   * @namespace
   */
  module.exports = {
  	/**
  	 * Converts the given line height `value` in pixels for a specific font `size`.
  	 * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
  	 * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
  	 * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
  	 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
  	 * @since 2.7.0
  	 */
  	toLineHeight: function(value, size) {
  		var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
  		if (!matches || matches[1] === 'normal') {
  			return size * 1.2;
  		}
  
  		value = +matches[2];
  
  		switch (matches[3]) {
  		case 'px':
  			return value;
  		case '%':
  			value /= 100;
  			break;
  		default:
  			break;
  		}
  
  		return size * value;
  	},
  
  	/**
  	 * Converts the given value into a padding object with pre-computed width/height.
  	 * @param {Number|Object} value - If a number, set the value to all TRBL component,
  	 *  else, if and object, use defined properties and sets undefined ones to 0.
  	 * @returns {Object} The padding values (top, right, bottom, left, width, height)
  	 * @since 2.7.0
  	 */
  	toPadding: function(value) {
  		var t, r, b, l;
  
  		if (helpers.isObject(value)) {
  			t = +value.top || 0;
  			r = +value.right || 0;
  			b = +value.bottom || 0;
  			l = +value.left || 0;
  		} else {
  			t = r = b = l = +value || 0;
  		}
  
  		return {
  			top: t,
  			right: r,
  			bottom: b,
  			left: l,
  			height: t + b,
  			width: l + r
  		};
  	},
  
  	/**
  	 * Evaluates the given `inputs` sequentially and returns the first defined value.
  	 * @param {Array[]} inputs - An array of values, falling back to the last value.
  	 * @param {Object} [context] - If defined and the current value is a function, the value
  	 * is called with `context` as first argument and the result becomes the new input.
  	 * @param {Number} [index] - If defined and the current value is an array, the value
  	 * at `index` become the new input.
  	 * @since 2.7.0
  	 */
  	resolve: function(inputs, context, index) {
  		var i, ilen, value;
  
  		for (i = 0, ilen = inputs.length; i < ilen; ++i) {
  			value = inputs[i];
  			if (value === undefined) {
  				continue;
  			}
  			if (context !== undefined && typeof value === 'function') {
  				value = value(context);
  			}
  			if (index !== undefined && helpers.isArray(value)) {
  				value = value[index];
  			}
  			if (value !== undefined) {
  				return value;
  			}
  		}
  	}
  };
  
  },{"43":43}],46:[function(require,module,exports){
  'use strict';
  
  module.exports = require(43);
  module.exports.easing = require(44);
  module.exports.canvas = require(42);
  module.exports.options = require(45);
  
  },{"42":42,"43":43,"44":44,"45":45}],47:[function(require,module,exports){
  /**
   * Platform fallback implementation (minimal).
   * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
   */
  
  module.exports = {
  	acquireContext: function(item) {
  		if (item && item.canvas) {
  			// Support for any object associated to a canvas (including a context2d)
  			item = item.canvas;
  		}
  
  		return item && item.getContext('2d') || null;
  	}
  };
  
  },{}],48:[function(require,module,exports){
  /**
   * Chart.Platform implementation for targeting a web browser
   */
  
  'use strict';
  
  var helpers = require(46);
  
  var EXPANDO_KEY = '$chartjs';
  var CSS_PREFIX = 'chartjs-';
  var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
  var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
  var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
  
  /**
   * DOM event types -> Chart.js event types.
   * Note: only events with different types are mapped.
   * @see https://developer.mozilla.org/en-US/docs/Web/Events
   */
  var EVENT_TYPES = {
  	touchstart: 'mousedown',
  	touchmove: 'mousemove',
  	touchend: 'mouseup',
  	pointerenter: 'mouseenter',
  	pointerdown: 'mousedown',
  	pointermove: 'mousemove',
  	pointerup: 'mouseup',
  	pointerleave: 'mouseout',
  	pointerout: 'mouseout'
  };
  
  /**
   * The "used" size is the final value of a dimension property after all calculations have
   * been performed. This method uses the computed style of `element` but returns undefined
   * if the computed style is not expressed in pixels. That can happen in some cases where
   * `element` has a size relative to its parent and this last one is not yet displayed,
   * for example because of `display: none` on a parent node.
   * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
   * @returns {Number} Size in pixels or undefined if unknown.
   */
  function readUsedSize(element, property) {
  	var value = helpers.getStyle(element, property);
  	var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
  	return matches ? Number(matches[1]) : undefined;
  }
  
  /**
   * Initializes the canvas style and render size without modifying the canvas display size,
   * since responsiveness is handled by the controller.resize() method. The config is used
   * to determine the aspect ratio to apply in case no explicit height has been specified.
   */
  function initCanvas(canvas, config) {
  	var style = canvas.style;
  
  	// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
  	// returns null or '' if no explicit value has been set to the canvas attribute.
  	var renderHeight = canvas.getAttribute('height');
  	var renderWidth = canvas.getAttribute('width');
  
  	// Chart.js modifies some canvas values that we want to restore on destroy
  	canvas[EXPANDO_KEY] = {
  		initial: {
  			height: renderHeight,
  			width: renderWidth,
  			style: {
  				display: style.display,
  				height: style.height,
  				width: style.width
  			}
  		}
  	};
  
  	// Force canvas to display as block to avoid extra space caused by inline
  	// elements, which would interfere with the responsive resize process.
  	// https://github.com/chartjs/Chart.js/issues/2538
  	style.display = style.display || 'block';
  
  	if (renderWidth === null || renderWidth === '') {
  		var displayWidth = readUsedSize(canvas, 'width');
  		if (displayWidth !== undefined) {
  			canvas.width = displayWidth;
  		}
  	}
  
  	if (renderHeight === null || renderHeight === '') {
  		if (canvas.style.height === '') {
  			// If no explicit render height and style height, let's apply the aspect ratio,
  			// which one can be specified by the user but also by charts as default option
  			// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
  			canvas.height = canvas.width / (config.options.aspectRatio || 2);
  		} else {
  			var displayHeight = readUsedSize(canvas, 'height');
  			if (displayWidth !== undefined) {
  				canvas.height = displayHeight;
  			}
  		}
  	}
  
  	return canvas;
  }
  
  /**
   * Detects support for options object argument in addEventListener.
   * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
   * @private
   */
  var supportsEventListenerOptions = (function() {
  	var supports = false;
  	try {
  		var options = Object.defineProperty({}, 'passive', {
  			get: function() {
  				supports = true;
  			}
  		});
  		window.addEventListener('e', null, options);
  	} catch (e) {
  		// continue regardless of error
  	}
  	return supports;
  }());
  
  // Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
  // https://github.com/chartjs/Chart.js/issues/4287
  var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
  
  function addEventListener(node, type, listener) {
  	node.addEventListener(type, listener, eventListenerOptions);
  }
  
  function removeEventListener(node, type, listener) {
  	node.removeEventListener(type, listener, eventListenerOptions);
  }
  
  function createEvent(type, chart, x, y, nativeEvent) {
  	return {
  		type: type,
  		chart: chart,
  		native: nativeEvent || null,
  		x: x !== undefined ? x : null,
  		y: y !== undefined ? y : null,
  	};
  }
  
  function fromNativeEvent(event, chart) {
  	var type = EVENT_TYPES[event.type] || event.type;
  	var pos = helpers.getRelativePosition(event, chart);
  	return createEvent(type, chart, pos.x, pos.y, event);
  }
  
  function throttled(fn, thisArg) {
  	var ticking = false;
  	var args = [];
  
  	return function() {
  		args = Array.prototype.slice.call(arguments);
  		thisArg = thisArg || this;
  
  		if (!ticking) {
  			ticking = true;
  			helpers.requestAnimFrame.call(window, function() {
  				ticking = false;
  				fn.apply(thisArg, args);
  			});
  		}
  	};
  }
  
  // Implementation based on https://github.com/marcj/css-element-queries
  function createResizer(handler) {
  	var resizer = document.createElement('div');
  	var cls = CSS_PREFIX + 'size-monitor';
  	var maxSize = 1000000;
  	var style =
  		'position:absolute;' +
  		'left:0;' +
  		'top:0;' +
  		'right:0;' +
  		'bottom:0;' +
  		'overflow:hidden;' +
  		'pointer-events:none;' +
  		'visibility:hidden;' +
  		'z-index:-1;';
  
  	resizer.style.cssText = style;
  	resizer.className = cls;
  	resizer.innerHTML =
  		'<div class="' + cls + '-expand" style="' + style + '">' +
  			'<div style="' +
  				'position:absolute;' +
  				'width:' + maxSize + 'px;' +
  				'height:' + maxSize + 'px;' +
  				'left:0;' +
  				'top:0">' +
  			'</div>' +
  		'</div>' +
  		'<div class="' + cls + '-shrink" style="' + style + '">' +
  			'<div style="' +
  				'position:absolute;' +
  				'width:200%;' +
  				'height:200%;' +
  				'left:0; ' +
  				'top:0">' +
  			'</div>' +
  		'</div>';
  
  	var expand = resizer.childNodes[0];
  	var shrink = resizer.childNodes[1];
  
  	resizer._reset = function() {
  		expand.scrollLeft = maxSize;
  		expand.scrollTop = maxSize;
  		shrink.scrollLeft = maxSize;
  		shrink.scrollTop = maxSize;
  	};
  	var onScroll = function() {
  		resizer._reset();
  		handler();
  	};
  
  	addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
  	addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
  
  	return resizer;
  }
  
  // https://davidwalsh.name/detect-node-insertion
  function watchForRender(node, handler) {
  	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
  	var proxy = expando.renderProxy = function(e) {
  		if (e.animationName === CSS_RENDER_ANIMATION) {
  			handler();
  		}
  	};
  
  	helpers.each(ANIMATION_START_EVENTS, function(type) {
  		addEventListener(node, type, proxy);
  	});
  
  	// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
  	// is removed then added back immediately (same animation frame?). Accessing the
  	// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
  	// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
  	// https://github.com/chartjs/Chart.js/issues/4737
  	expando.reflow = !!node.offsetParent;
  
  	node.classList.add(CSS_RENDER_MONITOR);
  }
  
  function unwatchForRender(node) {
  	var expando = node[EXPANDO_KEY] || {};
  	var proxy = expando.renderProxy;
  
  	if (proxy) {
  		helpers.each(ANIMATION_START_EVENTS, function(type) {
  			removeEventListener(node, type, proxy);
  		});
  
  		delete expando.renderProxy;
  	}
  
  	node.classList.remove(CSS_RENDER_MONITOR);
  }
  
  function addResizeListener(node, listener, chart) {
  	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
  
  	// Let's keep track of this added resizer and thus avoid DOM query when removing it.
  	var resizer = expando.resizer = createResizer(throttled(function() {
  		if (expando.resizer) {
  			return listener(createEvent('resize', chart));
  		}
  	}));
  
  	// The resizer needs to be attached to the node parent, so we first need to be
  	// sure that `node` is attached to the DOM before injecting the resizer element.
  	watchForRender(node, function() {
  		if (expando.resizer) {
  			var container = node.parentNode;
  			if (container && container !== resizer.parentNode) {
  				container.insertBefore(resizer, container.firstChild);
  			}
  
  			// The container size might have changed, let's reset the resizer state.
  			resizer._reset();
  		}
  	});
  }
  
  function removeResizeListener(node) {
  	var expando = node[EXPANDO_KEY] || {};
  	var resizer = expando.resizer;
  
  	delete expando.resizer;
  	unwatchForRender(node);
  
  	if (resizer && resizer.parentNode) {
  		resizer.parentNode.removeChild(resizer);
  	}
  }
  
  function injectCSS(platform, css) {
  	// http://stackoverflow.com/q/3922139
  	var style = platform._style || document.createElement('style');
  	if (!platform._style) {
  		platform._style = style;
  		css = '/* Chart.js */\n' + css;
  		style.setAttribute('type', 'text/css');
  		document.getElementsByTagName('head')[0].appendChild(style);
  	}
  
  	style.appendChild(document.createTextNode(css));
  }
  
  module.exports = {
  	/**
  	 * This property holds whether this platform is enabled for the current environment.
  	 * Currently used by platform.js to select the proper implementation.
  	 * @private
  	 */
  	_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
  
  	initialize: function() {
  		var keyframes = 'from{opacity:0.99}to{opacity:1}';
  
  		injectCSS(this,
  			// DOM rendering detection
  			// https://davidwalsh.name/detect-node-insertion
  			'@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
  			'@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
  			'.' + CSS_RENDER_MONITOR + '{' +
  				'-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
  				'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
  			'}'
  		);
  	},
  
  	acquireContext: function(item, config) {
  		if (typeof item === 'string') {
  			item = document.getElementById(item);
  		} else if (item.length) {
  			// Support for array based queries (such as jQuery)
  			item = item[0];
  		}
  
  		if (item && item.canvas) {
  			// Support for any object associated to a canvas (including a context2d)
  			item = item.canvas;
  		}
  
  		// To prevent canvas fingerprinting, some add-ons undefine the getContext
  		// method, for example: https://github.com/kkapsner/CanvasBlocker
  		// https://github.com/chartjs/Chart.js/issues/2807
  		var context = item && item.getContext && item.getContext('2d');
  
  		// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
  		// inside an iframe or when running in a protected environment. We could guess the
  		// types from their toString() value but let's keep things flexible and assume it's
  		// a sufficient condition if the item has a context2D which has item as `canvas`.
  		// https://github.com/chartjs/Chart.js/issues/3887
  		// https://github.com/chartjs/Chart.js/issues/4102
  		// https://github.com/chartjs/Chart.js/issues/4152
  		if (context && context.canvas === item) {
  			initCanvas(item, config);
  			return context;
  		}
  
  		return null;
  	},
  
  	releaseContext: function(context) {
  		var canvas = context.canvas;
  		if (!canvas[EXPANDO_KEY]) {
  			return;
  		}
  
  		var initial = canvas[EXPANDO_KEY].initial;
  		['height', 'width'].forEach(function(prop) {
  			var value = initial[prop];
  			if (helpers.isNullOrUndef(value)) {
  				canvas.removeAttribute(prop);
  			} else {
  				canvas.setAttribute(prop, value);
  			}
  		});
  
  		helpers.each(initial.style || {}, function(value, key) {
  			canvas.style[key] = value;
  		});
  
  		// The canvas render size might have been changed (and thus the state stack discarded),
  		// we can't use save() and restore() to restore the initial state. So make sure that at
  		// least the canvas context is reset to the default state by setting the canvas width.
  		// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
  		canvas.width = canvas.width;
  
  		delete canvas[EXPANDO_KEY];
  	},
  
  	addEventListener: function(chart, type, listener) {
  		var canvas = chart.canvas;
  		if (type === 'resize') {
  			// Note: the resize event is not supported on all browsers.
  			addResizeListener(canvas, listener, chart);
  			return;
  		}
  
  		var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
  		var proxies = expando.proxies || (expando.proxies = {});
  		var proxy = proxies[chart.id + '_' + type] = function(event) {
  			listener(fromNativeEvent(event, chart));
  		};
  
  		addEventListener(canvas, type, proxy);
  	},
  
  	removeEventListener: function(chart, type, listener) {
  		var canvas = chart.canvas;
  		if (type === 'resize') {
  			// Note: the resize event is not supported on all browsers.
  			removeResizeListener(canvas, listener);
  			return;
  		}
  
  		var expando = listener[EXPANDO_KEY] || {};
  		var proxies = expando.proxies || {};
  		var proxy = proxies[chart.id + '_' + type];
  		if (!proxy) {
  			return;
  		}
  
  		removeEventListener(canvas, type, proxy);
  	}
  };
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use EventTarget.addEventListener instead.
   * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
   * @function Chart.helpers.addEvent
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.addEvent = addEventListener;
  
  /**
   * Provided for backward compatibility, use EventTarget.removeEventListener instead.
   * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
   * @function Chart.helpers.removeEvent
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.removeEvent = removeEventListener;
  
  },{"46":46}],49:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  var basic = require(47);
  var dom = require(48);
  
  // @TODO Make possible to select another platform at build time.
  var implementation = dom._enabled ? dom : basic;
  
  /**
   * @namespace Chart.platform
   * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
   * @since 2.4.0
   */
  module.exports = helpers.extend({
  	/**
  	 * @since 2.7.0
  	 */
  	initialize: function() {},
  
  	/**
  	 * Called at chart construction time, returns a context2d instance implementing
  	 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
  	 * @param {*} item - The native item from which to acquire context (platform specific)
  	 * @param {Object} options - The chart options
  	 * @returns {CanvasRenderingContext2D} context2d instance
  	 */
  	acquireContext: function() {},
  
  	/**
  	 * Called at chart destruction time, releases any resources associated to the context
  	 * previously returned by the acquireContext() method.
  	 * @param {CanvasRenderingContext2D} context - The context2d instance
  	 * @returns {Boolean} true if the method succeeded, else false
  	 */
  	releaseContext: function() {},
  
  	/**
  	 * Registers the specified listener on the given chart.
  	 * @param {Chart} chart - Chart from which to listen for event
  	 * @param {String} type - The ({@link IEvent}) type to listen for
  	 * @param {Function} listener - Receives a notification (an object that implements
  	 * the {@link IEvent} interface) when an event of the specified type occurs.
  	 */
  	addEventListener: function() {},
  
  	/**
  	 * Removes the specified listener previously registered with addEventListener.
  	 * @param {Chart} chart -Chart from which to remove the listener
  	 * @param {String} type - The ({@link IEvent}) type to remove
  	 * @param {Function} listener - The listener function to remove from the event target.
  	 */
  	removeEventListener: function() {}
  
  }, implementation);
  
  /**
   * @interface IPlatform
   * Allows abstracting platform dependencies away from the chart
   * @borrows Chart.platform.acquireContext as acquireContext
   * @borrows Chart.platform.releaseContext as releaseContext
   * @borrows Chart.platform.addEventListener as addEventListener
   * @borrows Chart.platform.removeEventListener as removeEventListener
   */
  
  /**
   * @interface IEvent
   * @prop {String} type - The event type name, possible values are:
   * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
   * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
   * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
   * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
   * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
   */
  
  },{"46":46,"47":47,"48":48}],50:[function(require,module,exports){
  'use strict';
  
  module.exports = {};
  module.exports.filler = require(51);
  module.exports.legend = require(52);
  module.exports.title = require(53);
  
  },{"51":51,"52":52,"53":53}],51:[function(require,module,exports){
  /**
   * Plugin based on discussion from the following Chart.js issues:
   * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
   * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
   */
  
  'use strict';
  
  var defaults = require(26);
  var elements = require(41);
  var helpers = require(46);
  
  defaults._set('global', {
  	plugins: {
  		filler: {
  			propagate: true
  		}
  	}
  });
  
  var mappers = {
  	dataset: function(source) {
  		var index = source.fill;
  		var chart = source.chart;
  		var meta = chart.getDatasetMeta(index);
  		var visible = meta && chart.isDatasetVisible(index);
  		var points = (visible && meta.dataset._children) || [];
  		var length = points.length || 0;
  
  		return !length ? null : function(point, i) {
  			return (i < length && points[i]._view) || null;
  		};
  	},
  
  	boundary: function(source) {
  		var boundary = source.boundary;
  		var x = boundary ? boundary.x : null;
  		var y = boundary ? boundary.y : null;
  
  		return function(point) {
  			return {
  				x: x === null ? point.x : x,
  				y: y === null ? point.y : y,
  			};
  		};
  	}
  };
  
  // @todo if (fill[0] === '#')
  function decodeFill(el, index, count) {
  	var model = el._model || {};
  	var fill = model.fill;
  	var target;
  
  	if (fill === undefined) {
  		fill = !!model.backgroundColor;
  	}
  
  	if (fill === false || fill === null) {
  		return false;
  	}
  
  	if (fill === true) {
  		return 'origin';
  	}
  
  	target = parseFloat(fill, 10);
  	if (isFinite(target) && Math.floor(target) === target) {
  		if (fill[0] === '-' || fill[0] === '+') {
  			target = index + target;
  		}
  
  		if (target === index || target < 0 || target >= count) {
  			return false;
  		}
  
  		return target;
  	}
  
  	switch (fill) {
  	// compatibility
  	case 'bottom':
  		return 'start';
  	case 'top':
  		return 'end';
  	case 'zero':
  		return 'origin';
  	// supported boundaries
  	case 'origin':
  	case 'start':
  	case 'end':
  		return fill;
  	// invalid fill values
  	default:
  		return false;
  	}
  }
  
  function computeBoundary(source) {
  	var model = source.el._model || {};
  	var scale = source.el._scale || {};
  	var fill = source.fill;
  	var target = null;
  	var horizontal;
  
  	if (isFinite(fill)) {
  		return null;
  	}
  
  	// Backward compatibility: until v3, we still need to support boundary values set on
  	// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
  	// controllers might still use it (e.g. the Smith chart).
  
  	if (fill === 'start') {
  		target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
  	} else if (fill === 'end') {
  		target = model.scaleTop === undefined ? scale.top : model.scaleTop;
  	} else if (model.scaleZero !== undefined) {
  		target = model.scaleZero;
  	} else if (scale.getBasePosition) {
  		target = scale.getBasePosition();
  	} else if (scale.getBasePixel) {
  		target = scale.getBasePixel();
  	}
  
  	if (target !== undefined && target !== null) {
  		if (target.x !== undefined && target.y !== undefined) {
  			return target;
  		}
  
  		if (typeof target === 'number' && isFinite(target)) {
  			horizontal = scale.isHorizontal();
  			return {
  				x: horizontal ? target : null,
  				y: horizontal ? null : target
  			};
  		}
  	}
  
  	return null;
  }
  
  function resolveTarget(sources, index, propagate) {
  	var source = sources[index];
  	var fill = source.fill;
  	var visited = [index];
  	var target;
  
  	if (!propagate) {
  		return fill;
  	}
  
  	while (fill !== false && visited.indexOf(fill) === -1) {
  		if (!isFinite(fill)) {
  			return fill;
  		}
  
  		target = sources[fill];
  		if (!target) {
  			return false;
  		}
  
  		if (target.visible) {
  			return fill;
  		}
  
  		visited.push(fill);
  		fill = target.fill;
  	}
  
  	return false;
  }
  
  function createMapper(source) {
  	var fill = source.fill;
  	var type = 'dataset';
  
  	if (fill === false) {
  		return null;
  	}
  
  	if (!isFinite(fill)) {
  		type = 'boundary';
  	}
  
  	return mappers[type](source);
  }
  
  function isDrawable(point) {
  	return point && !point.skip;
  }
  
  function drawArea(ctx, curve0, curve1, len0, len1) {
  	var i;
  
  	if (!len0 || !len1) {
  		return;
  	}
  
  	// building first area curve (normal)
  	ctx.moveTo(curve0[0].x, curve0[0].y);
  	for (i = 1; i < len0; ++i) {
  		helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
  	}
  
  	// joining the two area curves
  	ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
  
  	// building opposite area curve (reverse)
  	for (i = len1 - 1; i > 0; --i) {
  		helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
  	}
  }
  
  function doFill(ctx, points, mapper, view, color, loop) {
  	var count = points.length;
  	var span = view.spanGaps;
  	var curve0 = [];
  	var curve1 = [];
  	var len0 = 0;
  	var len1 = 0;
  	var i, ilen, index, p0, p1, d0, d1;
  
  	ctx.beginPath();
  
  	for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
  		index = i % count;
  		p0 = points[index]._view;
  		p1 = mapper(p0, index, view);
  		d0 = isDrawable(p0);
  		d1 = isDrawable(p1);
  
  		if (d0 && d1) {
  			len0 = curve0.push(p0);
  			len1 = curve1.push(p1);
  		} else if (len0 && len1) {
  			if (!span) {
  				drawArea(ctx, curve0, curve1, len0, len1);
  				len0 = len1 = 0;
  				curve0 = [];
  				curve1 = [];
  			} else {
  				if (d0) {
  					curve0.push(p0);
  				}
  				if (d1) {
  					curve1.push(p1);
  				}
  			}
  		}
  	}
  
  	drawArea(ctx, curve0, curve1, len0, len1);
  
  	ctx.closePath();
  	ctx.fillStyle = color;
  	ctx.fill();
  }
  
  module.exports = {
  	id: 'filler',
  
  	afterDatasetsUpdate: function(chart, options) {
  		var count = (chart.data.datasets || []).length;
  		var propagate = options.propagate;
  		var sources = [];
  		var meta, i, el, source;
  
  		for (i = 0; i < count; ++i) {
  			meta = chart.getDatasetMeta(i);
  			el = meta.dataset;
  			source = null;
  
  			if (el && el._model && el instanceof elements.Line) {
  				source = {
  					visible: chart.isDatasetVisible(i),
  					fill: decodeFill(el, i, count),
  					chart: chart,
  					el: el
  				};
  			}
  
  			meta.$filler = source;
  			sources.push(source);
  		}
  
  		for (i = 0; i < count; ++i) {
  			source = sources[i];
  			if (!source) {
  				continue;
  			}
  
  			source.fill = resolveTarget(sources, i, propagate);
  			source.boundary = computeBoundary(source);
  			source.mapper = createMapper(source);
  		}
  	},
  
  	beforeDatasetDraw: function(chart, args) {
  		var meta = args.meta.$filler;
  		if (!meta) {
  			return;
  		}
  
  		var ctx = chart.ctx;
  		var el = meta.el;
  		var view = el._view;
  		var points = el._children || [];
  		var mapper = meta.mapper;
  		var color = view.backgroundColor || defaults.global.defaultColor;
  
  		if (mapper && color && points.length) {
  			helpers.canvas.clipArea(ctx, chart.chartArea);
  			doFill(ctx, points, mapper, view, color, el._loop);
  			helpers.canvas.unclipArea(ctx);
  		}
  	}
  };
  
  },{"26":26,"41":41,"46":46}],52:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  var layouts = require(31);
  
  var noop = helpers.noop;
  
  defaults._set('global', {
  	legend: {
  		display: true,
  		position: 'top',
  		fullWidth: true,
  		reverse: false,
  		weight: 1000,
  
  		// a callback that will handle
  		onClick: function(e, legendItem) {
  			var index = legendItem.datasetIndex;
  			var ci = this.chart;
  			var meta = ci.getDatasetMeta(index);
  
  			// See controller.isDatasetVisible comment
  			meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
  
  			// We hid a dataset ... rerender the chart
  			ci.update();
  		},
  
  		onHover: null,
  
  		labels: {
  			boxWidth: 40,
  			padding: 10,
  			// Generates labels shown in the legend
  			// Valid properties to return:
  			// text : text to display
  			// fillStyle : fill of coloured box
  			// strokeStyle: stroke of coloured box
  			// hidden : if this legend item refers to a hidden item
  			// lineCap : cap style for line
  			// lineDash
  			// lineDashOffset :
  			// lineJoin :
  			// lineWidth :
  			generateLabels: function(chart) {
  				var data = chart.data;
  				return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
  					return {
  						text: dataset.label,
  						fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
  						hidden: !chart.isDatasetVisible(i),
  						lineCap: dataset.borderCapStyle,
  						lineDash: dataset.borderDash,
  						lineDashOffset: dataset.borderDashOffset,
  						lineJoin: dataset.borderJoinStyle,
  						lineWidth: dataset.borderWidth,
  						strokeStyle: dataset.borderColor,
  						pointStyle: dataset.pointStyle,
  
  						// Below is extra data used for toggling the datasets
  						datasetIndex: i
  					};
  				}, this) : [];
  			}
  		}
  	},
  
  	legendCallback: function(chart) {
  		var text = [];
  		text.push('<ul class="' + chart.id + '-legend">');
  		for (var i = 0; i < chart.data.datasets.length; i++) {
  			text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
  			if (chart.data.datasets[i].label) {
  				text.push(chart.data.datasets[i].label);
  			}
  			text.push('</li>');
  		}
  		text.push('</ul>');
  		return text.join('');
  	}
  });
  
  /**
   * Helper function to get the box width based on the usePointStyle option
   * @param labelopts {Object} the label options on the legend
   * @param fontSize {Number} the label font size
   * @return {Number} width of the color box area
   */
  function getBoxWidth(labelOpts, fontSize) {
  	return labelOpts.usePointStyle ?
  		fontSize * Math.SQRT2 :
  		labelOpts.boxWidth;
  }
  
  /**
   * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
   */
  var Legend = Element.extend({
  
  	initialize: function(config) {
  		helpers.extend(this, config);
  
  		// Contains hit boxes for each dataset (in dataset order)
  		this.legendHitBoxes = [];
  
  		// Are we in doughnut mode which has a different data type
  		this.doughnutMode = false;
  	},
  
  	// These methods are ordered by lifecycle. Utilities then follow.
  	// Any function defined here is inherited by all legend types.
  	// Any function can be extended by the legend type
  
  	beforeUpdate: noop,
  	update: function(maxWidth, maxHeight, margins) {
  		var me = this;
  
  		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  		me.beforeUpdate();
  
  		// Absorb the master measurements
  		me.maxWidth = maxWidth;
  		me.maxHeight = maxHeight;
  		me.margins = margins;
  
  		// Dimensions
  		me.beforeSetDimensions();
  		me.setDimensions();
  		me.afterSetDimensions();
  		// Labels
  		me.beforeBuildLabels();
  		me.buildLabels();
  		me.afterBuildLabels();
  
  		// Fit
  		me.beforeFit();
  		me.fit();
  		me.afterFit();
  		//
  		me.afterUpdate();
  
  		return me.minSize;
  	},
  	afterUpdate: noop,
  
  	//
  
  	beforeSetDimensions: noop,
  	setDimensions: function() {
  		var me = this;
  		// Set the unconstrained dimension before label rotation
  		if (me.isHorizontal()) {
  			// Reset position before calculating rotation
  			me.width = me.maxWidth;
  			me.left = 0;
  			me.right = me.width;
  		} else {
  			me.height = me.maxHeight;
  
  			// Reset position before calculating rotation
  			me.top = 0;
  			me.bottom = me.height;
  		}
  
  		// Reset padding
  		me.paddingLeft = 0;
  		me.paddingTop = 0;
  		me.paddingRight = 0;
  		me.paddingBottom = 0;
  
  		// Reset minSize
  		me.minSize = {
  			width: 0,
  			height: 0
  		};
  	},
  	afterSetDimensions: noop,
  
  	//
  
  	beforeBuildLabels: noop,
  	buildLabels: function() {
  		var me = this;
  		var labelOpts = me.options.labels || {};
  		var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || [];
  
  		if (labelOpts.filter) {
  			legendItems = legendItems.filter(function(item) {
  				return labelOpts.filter(item, me.chart.data);
  			});
  		}
  
  		if (me.options.reverse) {
  			legendItems.reverse();
  		}
  
  		me.legendItems = legendItems;
  	},
  	afterBuildLabels: noop,
  
  	//
  
  	beforeFit: noop,
  	fit: function() {
  		var me = this;
  		var opts = me.options;
  		var labelOpts = opts.labels;
  		var display = opts.display;
  
  		var ctx = me.ctx;
  
  		var globalDefault = defaults.global;
  		var valueOrDefault = helpers.valueOrDefault;
  		var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
  		var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
  		var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
  		var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
  
  		// Reset hit boxes
  		var hitboxes = me.legendHitBoxes = [];
  
  		var minSize = me.minSize;
  		var isHorizontal = me.isHorizontal();
  
  		if (isHorizontal) {
  			minSize.width = me.maxWidth; // fill all the width
  			minSize.height = display ? 10 : 0;
  		} else {
  			minSize.width = display ? 10 : 0;
  			minSize.height = me.maxHeight; // fill all the height
  		}
  
  		// Increase sizes here
  		if (display) {
  			ctx.font = labelFont;
  
  			if (isHorizontal) {
  				// Labels
  
  				// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
  				var lineWidths = me.lineWidths = [0];
  				var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
  
  				ctx.textAlign = 'left';
  				ctx.textBaseline = 'top';
  
  				helpers.each(me.legendItems, function(legendItem, i) {
  					var boxWidth = getBoxWidth(labelOpts, fontSize);
  					var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
  
  					if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
  						totalHeight += fontSize + (labelOpts.padding);
  						lineWidths[lineWidths.length] = me.left;
  					}
  
  					// Store the hitbox width and height here. Final position will be updated in `draw`
  					hitboxes[i] = {
  						left: 0,
  						top: 0,
  						width: width,
  						height: fontSize
  					};
  
  					lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
  				});
  
  				minSize.height += totalHeight;
  
  			} else {
  				var vPadding = labelOpts.padding;
  				var columnWidths = me.columnWidths = [];
  				var totalWidth = labelOpts.padding;
  				var currentColWidth = 0;
  				var currentColHeight = 0;
  				var itemHeight = fontSize + vPadding;
  
  				helpers.each(me.legendItems, function(legendItem, i) {
  					var boxWidth = getBoxWidth(labelOpts, fontSize);
  					var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
  
  					// If too tall, go to new column
  					if (currentColHeight + itemHeight > minSize.height) {
  						totalWidth += currentColWidth + labelOpts.padding;
  						columnWidths.push(currentColWidth); // previous column width
  
  						currentColWidth = 0;
  						currentColHeight = 0;
  					}
  
  					// Get max width
  					currentColWidth = Math.max(currentColWidth, itemWidth);
  					currentColHeight += itemHeight;
  
  					// Store the hitbox width and height here. Final position will be updated in `draw`
  					hitboxes[i] = {
  						left: 0,
  						top: 0,
  						width: itemWidth,
  						height: fontSize
  					};
  				});
  
  				totalWidth += currentColWidth;
  				columnWidths.push(currentColWidth);
  				minSize.width += totalWidth;
  			}
  		}
  
  		me.width = minSize.width;
  		me.height = minSize.height;
  	},
  	afterFit: noop,
  
  	// Shared Methods
  	isHorizontal: function() {
  		return this.options.position === 'top' || this.options.position === 'bottom';
  	},
  
  	// Actually draw the legend on the canvas
  	draw: function() {
  		var me = this;
  		var opts = me.options;
  		var labelOpts = opts.labels;
  		var globalDefault = defaults.global;
  		var lineDefault = globalDefault.elements.line;
  		var legendWidth = me.width;
  		var lineWidths = me.lineWidths;
  
  		if (opts.display) {
  			var ctx = me.ctx;
  			var valueOrDefault = helpers.valueOrDefault;
  			var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
  			var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
  			var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
  			var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
  			var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
  			var cursor;
  
  			// Canvas setup
  			ctx.textAlign = 'left';
  			ctx.textBaseline = 'middle';
  			ctx.lineWidth = 0.5;
  			ctx.strokeStyle = fontColor; // for strikethrough effect
  			ctx.fillStyle = fontColor; // render in correct colour
  			ctx.font = labelFont;
  
  			var boxWidth = getBoxWidth(labelOpts, fontSize);
  			var hitboxes = me.legendHitBoxes;
  
  			// current position
  			var drawLegendBox = function(x, y, legendItem) {
  				if (isNaN(boxWidth) || boxWidth <= 0) {
  					return;
  				}
  
  				// Set the ctx for the box
  				ctx.save();
  
  				ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
  				ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
  				ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
  				ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
  				ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
  				ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
  				var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
  
  				if (ctx.setLineDash) {
  					// IE 9 and 10 do not support line dash
  					ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
  				}
  
  				if (opts.labels && opts.labels.usePointStyle) {
  					// Recalculate x and y for drawPoint() because its expecting
  					// x and y to be center of figure (instead of top left)
  					var radius = fontSize * Math.SQRT2 / 2;
  					var offSet = radius / Math.SQRT2;
  					var centerX = x + offSet;
  					var centerY = y + offSet;
  
  					// Draw pointStyle as legend symbol
  					helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
  				} else {
  					// Draw box as legend symbol
  					if (!isLineWidthZero) {
  						ctx.strokeRect(x, y, boxWidth, fontSize);
  					}
  					ctx.fillRect(x, y, boxWidth, fontSize);
  				}
  
  				ctx.restore();
  			};
  			var fillText = function(x, y, legendItem, textWidth) {
  				var halfFontSize = fontSize / 2;
  				var xLeft = boxWidth + halfFontSize + x;
  				var yMiddle = y + halfFontSize;
  
  				ctx.fillText(legendItem.text, xLeft, yMiddle);
  
  				if (legendItem.hidden) {
  					// Strikethrough the text if hidden
  					ctx.beginPath();
  					ctx.lineWidth = 2;
  					ctx.moveTo(xLeft, yMiddle);
  					ctx.lineTo(xLeft + textWidth, yMiddle);
  					ctx.stroke();
  				}
  			};
  
  			// Horizontal
  			var isHorizontal = me.isHorizontal();
  			if (isHorizontal) {
  				cursor = {
  					x: me.left + ((legendWidth - lineWidths[0]) / 2),
  					y: me.top + labelOpts.padding,
  					line: 0
  				};
  			} else {
  				cursor = {
  					x: me.left + labelOpts.padding,
  					y: me.top + labelOpts.padding,
  					line: 0
  				};
  			}
  
  			var itemHeight = fontSize + labelOpts.padding;
  			helpers.each(me.legendItems, function(legendItem, i) {
  				var textWidth = ctx.measureText(legendItem.text).width;
  				var width = boxWidth + (fontSize / 2) + textWidth;
  				var x = cursor.x;
  				var y = cursor.y;
  
  				if (isHorizontal) {
  					if (x + width >= legendWidth) {
  						y = cursor.y += itemHeight;
  						cursor.line++;
  						x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
  					}
  				} else if (y + itemHeight > me.bottom) {
  					x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
  					y = cursor.y = me.top + labelOpts.padding;
  					cursor.line++;
  				}
  
  				drawLegendBox(x, y, legendItem);
  
  				hitboxes[i].left = x;
  				hitboxes[i].top = y;
  
  				// Fill the actual label
  				fillText(x, y, legendItem, textWidth);
  
  				if (isHorizontal) {
  					cursor.x += width + (labelOpts.padding);
  				} else {
  					cursor.y += itemHeight;
  				}
  
  			});
  		}
  	},
  
  	/**
  	 * Handle an event
  	 * @private
  	 * @param {IEvent} event - The event to handle
  	 * @return {Boolean} true if a change occured
  	 */
  	handleEvent: function(e) {
  		var me = this;
  		var opts = me.options;
  		var type = e.type === 'mouseup' ? 'click' : e.type;
  		var changed = false;
  
  		if (type === 'mousemove') {
  			if (!opts.onHover) {
  				return;
  			}
  		} else if (type === 'click') {
  			if (!opts.onClick) {
  				return;
  			}
  		} else {
  			return;
  		}
  
  		// Chart event already has relative position in it
  		var x = e.x;
  		var y = e.y;
  
  		if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
  			// See if we are touching one of the dataset boxes
  			var lh = me.legendHitBoxes;
  			for (var i = 0; i < lh.length; ++i) {
  				var hitBox = lh[i];
  
  				if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
  					// Touching an element
  					if (type === 'click') {
  						// use e.native for backwards compatibility
  						opts.onClick.call(me, e.native, me.legendItems[i]);
  						changed = true;
  						break;
  					} else if (type === 'mousemove') {
  						// use e.native for backwards compatibility
  						opts.onHover.call(me, e.native, me.legendItems[i]);
  						changed = true;
  						break;
  					}
  				}
  			}
  		}
  
  		return changed;
  	}
  });
  
  function createNewLegendAndAttach(chart, legendOpts) {
  	var legend = new Legend({
  		ctx: chart.ctx,
  		options: legendOpts,
  		chart: chart
  	});
  
  	layouts.configure(chart, legend, legendOpts);
  	layouts.addBox(chart, legend);
  	chart.legend = legend;
  }
  
  module.exports = {
  	id: 'legend',
  
  	/**
  	 * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
  	 * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
  	 * the plugin, which one will be re-exposed in the chart.js file.
  	 * https://github.com/chartjs/Chart.js/pull/2640
  	 * @private
  	 */
  	_element: Legend,
  
  	beforeInit: function(chart) {
  		var legendOpts = chart.options.legend;
  
  		if (legendOpts) {
  			createNewLegendAndAttach(chart, legendOpts);
  		}
  	},
  
  	beforeUpdate: function(chart) {
  		var legendOpts = chart.options.legend;
  		var legend = chart.legend;
  
  		if (legendOpts) {
  			helpers.mergeIf(legendOpts, defaults.global.legend);
  
  			if (legend) {
  				layouts.configure(chart, legend, legendOpts);
  				legend.options = legendOpts;
  			} else {
  				createNewLegendAndAttach(chart, legendOpts);
  			}
  		} else if (legend) {
  			layouts.removeBox(chart, legend);
  			delete chart.legend;
  		}
  	},
  
  	afterEvent: function(chart, e) {
  		var legend = chart.legend;
  		if (legend) {
  			legend.handleEvent(e);
  		}
  	}
  };
  
  },{"26":26,"27":27,"31":31,"46":46}],53:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var Element = require(27);
  var helpers = require(46);
  var layouts = require(31);
  
  var noop = helpers.noop;
  
  defaults._set('global', {
  	title: {
  		display: false,
  		fontStyle: 'bold',
  		fullWidth: true,
  		lineHeight: 1.2,
  		padding: 10,
  		position: 'top',
  		text: '',
  		weight: 2000         // by default greater than legend (1000) to be above
  	}
  });
  
  /**
   * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
   */
  var Title = Element.extend({
  	initialize: function(config) {
  		var me = this;
  		helpers.extend(me, config);
  
  		// Contains hit boxes for each dataset (in dataset order)
  		me.legendHitBoxes = [];
  	},
  
  	// These methods are ordered by lifecycle. Utilities then follow.
  
  	beforeUpdate: noop,
  	update: function(maxWidth, maxHeight, margins) {
  		var me = this;
  
  		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  		me.beforeUpdate();
  
  		// Absorb the master measurements
  		me.maxWidth = maxWidth;
  		me.maxHeight = maxHeight;
  		me.margins = margins;
  
  		// Dimensions
  		me.beforeSetDimensions();
  		me.setDimensions();
  		me.afterSetDimensions();
  		// Labels
  		me.beforeBuildLabels();
  		me.buildLabels();
  		me.afterBuildLabels();
  
  		// Fit
  		me.beforeFit();
  		me.fit();
  		me.afterFit();
  		//
  		me.afterUpdate();
  
  		return me.minSize;
  
  	},
  	afterUpdate: noop,
  
  	//
  
  	beforeSetDimensions: noop,
  	setDimensions: function() {
  		var me = this;
  		// Set the unconstrained dimension before label rotation
  		if (me.isHorizontal()) {
  			// Reset position before calculating rotation
  			me.width = me.maxWidth;
  			me.left = 0;
  			me.right = me.width;
  		} else {
  			me.height = me.maxHeight;
  
  			// Reset position before calculating rotation
  			me.top = 0;
  			me.bottom = me.height;
  		}
  
  		// Reset padding
  		me.paddingLeft = 0;
  		me.paddingTop = 0;
  		me.paddingRight = 0;
  		me.paddingBottom = 0;
  
  		// Reset minSize
  		me.minSize = {
  			width: 0,
  			height: 0
  		};
  	},
  	afterSetDimensions: noop,
  
  	//
  
  	beforeBuildLabels: noop,
  	buildLabels: noop,
  	afterBuildLabels: noop,
  
  	//
  
  	beforeFit: noop,
  	fit: function() {
  		var me = this;
  		var valueOrDefault = helpers.valueOrDefault;
  		var opts = me.options;
  		var display = opts.display;
  		var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize);
  		var minSize = me.minSize;
  		var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1;
  		var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
  		var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
  
  		if (me.isHorizontal()) {
  			minSize.width = me.maxWidth; // fill all the width
  			minSize.height = textSize;
  		} else {
  			minSize.width = textSize;
  			minSize.height = me.maxHeight; // fill all the height
  		}
  
  		me.width = minSize.width;
  		me.height = minSize.height;
  
  	},
  	afterFit: noop,
  
  	// Shared Methods
  	isHorizontal: function() {
  		var pos = this.options.position;
  		return pos === 'top' || pos === 'bottom';
  	},
  
  	// Actually draw the title block on the canvas
  	draw: function() {
  		var me = this;
  		var ctx = me.ctx;
  		var valueOrDefault = helpers.valueOrDefault;
  		var opts = me.options;
  		var globalDefaults = defaults.global;
  
  		if (opts.display) {
  			var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
  			var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
  			var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
  			var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
  			var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
  			var offset = lineHeight / 2 + opts.padding;
  			var rotation = 0;
  			var top = me.top;
  			var left = me.left;
  			var bottom = me.bottom;
  			var right = me.right;
  			var maxWidth, titleX, titleY;
  
  			ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
  			ctx.font = titleFont;
  
  			// Horizontal
  			if (me.isHorizontal()) {
  				titleX = left + ((right - left) / 2); // midpoint of the width
  				titleY = top + offset;
  				maxWidth = right - left;
  			} else {
  				titleX = opts.position === 'left' ? left + offset : right - offset;
  				titleY = top + ((bottom - top) / 2);
  				maxWidth = bottom - top;
  				rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
  			}
  
  			ctx.save();
  			ctx.translate(titleX, titleY);
  			ctx.rotate(rotation);
  			ctx.textAlign = 'center';
  			ctx.textBaseline = 'middle';
  
  			var text = opts.text;
  			if (helpers.isArray(text)) {
  				var y = 0;
  				for (var i = 0; i < text.length; ++i) {
  					ctx.fillText(text[i], 0, y, maxWidth);
  					y += lineHeight;
  				}
  			} else {
  				ctx.fillText(text, 0, 0, maxWidth);
  			}
  
  			ctx.restore();
  		}
  	}
  });
  
  function createNewTitleBlockAndAttach(chart, titleOpts) {
  	var title = new Title({
  		ctx: chart.ctx,
  		options: titleOpts,
  		chart: chart
  	});
  
  	layouts.configure(chart, title, titleOpts);
  	layouts.addBox(chart, title);
  	chart.titleBlock = title;
  }
  
  module.exports = {
  	id: 'title',
  
  	/**
  	 * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
  	 * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
  	 * the plugin, which one will be re-exposed in the chart.js file.
  	 * https://github.com/chartjs/Chart.js/pull/2640
  	 * @private
  	 */
  	_element: Title,
  
  	beforeInit: function(chart) {
  		var titleOpts = chart.options.title;
  
  		if (titleOpts) {
  			createNewTitleBlockAndAttach(chart, titleOpts);
  		}
  	},
  
  	beforeUpdate: function(chart) {
  		var titleOpts = chart.options.title;
  		var titleBlock = chart.titleBlock;
  
  		if (titleOpts) {
  			helpers.mergeIf(titleOpts, defaults.global.title);
  
  			if (titleBlock) {
  				layouts.configure(chart, titleBlock, titleOpts);
  				titleBlock.options = titleOpts;
  			} else {
  				createNewTitleBlockAndAttach(chart, titleOpts);
  			}
  		} else if (titleBlock) {
  			layouts.removeBox(chart, titleBlock);
  			delete chart.titleBlock;
  		}
  	}
  };
  
  },{"26":26,"27":27,"31":31,"46":46}],54:[function(require,module,exports){
  'use strict';
  
  var Scale = require(33);
  var scaleService = require(34);
  
  module.exports = function() {
  
  	// Default config for a category scale
  	var defaultConfig = {
  		position: 'bottom'
  	};
  
  	var DatasetScale = Scale.extend({
  		/**
  		* Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
  		* else fall back to data.labels
  		* @private
  		*/
  		getLabels: function() {
  			var data = this.chart.data;
  			return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
  		},
  
  		determineDataLimits: function() {
  			var me = this;
  			var labels = me.getLabels();
  			me.minIndex = 0;
  			me.maxIndex = labels.length - 1;
  			var findIndex;
  
  			if (me.options.ticks.min !== undefined) {
  				// user specified min value
  				findIndex = labels.indexOf(me.options.ticks.min);
  				me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
  			}
  
  			if (me.options.ticks.max !== undefined) {
  				// user specified max value
  				findIndex = labels.indexOf(me.options.ticks.max);
  				me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
  			}
  
  			me.min = labels[me.minIndex];
  			me.max = labels[me.maxIndex];
  		},
  
  		buildTicks: function() {
  			var me = this;
  			var labels = me.getLabels();
  			// If we are viewing some subset of labels, slice the original array
  			me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
  		},
  
  		getLabelForIndex: function(index, datasetIndex) {
  			var me = this;
  			var data = me.chart.data;
  			var isHorizontal = me.isHorizontal();
  
  			if (data.yLabels && !isHorizontal) {
  				return me.getRightValue(data.datasets[datasetIndex].data[index]);
  			}
  			return me.ticks[index - me.minIndex];
  		},
  
  		// Used to get data value locations.  Value can either be an index or a numerical value
  		getPixelForValue: function(value, index) {
  			var me = this;
  			var offset = me.options.offset;
  			// 1 is added because we need the length but we have the indexes
  			var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
  
  			// If value is a data object, then index is the index in the data array,
  			// not the index of the scale. We need to change that.
  			var valueCategory;
  			if (value !== undefined && value !== null) {
  				valueCategory = me.isHorizontal() ? value.x : value.y;
  			}
  			if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
  				var labels = me.getLabels();
  				value = valueCategory || value;
  				var idx = labels.indexOf(value);
  				index = idx !== -1 ? idx : index;
  			}
  
  			if (me.isHorizontal()) {
  				var valueWidth = me.width / offsetAmt;
  				var widthOffset = (valueWidth * (index - me.minIndex));
  
  				if (offset) {
  					widthOffset += (valueWidth / 2);
  				}
  
  				return me.left + Math.round(widthOffset);
  			}
  			var valueHeight = me.height / offsetAmt;
  			var heightOffset = (valueHeight * (index - me.minIndex));
  
  			if (offset) {
  				heightOffset += (valueHeight / 2);
  			}
  
  			return me.top + Math.round(heightOffset);
  		},
  		getPixelForTick: function(index) {
  			return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
  		},
  		getValueForPixel: function(pixel) {
  			var me = this;
  			var offset = me.options.offset;
  			var value;
  			var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
  			var horz = me.isHorizontal();
  			var valueDimension = (horz ? me.width : me.height) / offsetAmt;
  
  			pixel -= horz ? me.left : me.top;
  
  			if (offset) {
  				pixel -= (valueDimension / 2);
  			}
  
  			if (pixel <= 0) {
  				value = 0;
  			} else {
  				value = Math.round(pixel / valueDimension);
  			}
  
  			return value + me.minIndex;
  		},
  		getBasePixel: function() {
  			return this.bottom;
  		}
  	});
  
  	scaleService.registerScaleType('category', DatasetScale, defaultConfig);
  };
  
  },{"33":33,"34":34}],55:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var helpers = require(46);
  var scaleService = require(34);
  var Ticks = require(35);
  
  module.exports = function(Chart) {
  
  	var defaultConfig = {
  		position: 'left',
  		ticks: {
  			callback: Ticks.formatters.linear
  		}
  	};
  
  	var LinearScale = Chart.LinearScaleBase.extend({
  
  		determineDataLimits: function() {
  			var me = this;
  			var opts = me.options;
  			var chart = me.chart;
  			var data = chart.data;
  			var datasets = data.datasets;
  			var isHorizontal = me.isHorizontal();
  			var DEFAULT_MIN = 0;
  			var DEFAULT_MAX = 1;
  
  			function IDMatches(meta) {
  				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
  			}
  
  			// First Calculate the range
  			me.min = null;
  			me.max = null;
  
  			var hasStacks = opts.stacked;
  			if (hasStacks === undefined) {
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					if (hasStacks) {
  						return;
  					}
  
  					var meta = chart.getDatasetMeta(datasetIndex);
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
  						meta.stack !== undefined) {
  						hasStacks = true;
  					}
  				});
  			}
  
  			if (opts.stacked || hasStacks) {
  				var valuesPerStack = {};
  
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					var meta = chart.getDatasetMeta(datasetIndex);
  					var key = [
  						meta.type,
  						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
  						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
  						meta.stack
  					].join('.');
  
  					if (valuesPerStack[key] === undefined) {
  						valuesPerStack[key] = {
  							positiveValues: [],
  							negativeValues: []
  						};
  					}
  
  					// Store these per type
  					var positiveValues = valuesPerStack[key].positiveValues;
  					var negativeValues = valuesPerStack[key].negativeValues;
  
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  						helpers.each(dataset.data, function(rawValue, index) {
  							var value = +me.getRightValue(rawValue);
  							if (isNaN(value) || meta.data[index].hidden) {
  								return;
  							}
  
  							positiveValues[index] = positiveValues[index] || 0;
  							negativeValues[index] = negativeValues[index] || 0;
  
  							if (opts.relativePoints) {
  								positiveValues[index] = 100;
  							} else if (value < 0) {
  								negativeValues[index] += value;
  							} else {
  								positiveValues[index] += value;
  							}
  						});
  					}
  				});
  
  				helpers.each(valuesPerStack, function(valuesForType) {
  					var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
  					var minVal = helpers.min(values);
  					var maxVal = helpers.max(values);
  					me.min = me.min === null ? minVal : Math.min(me.min, minVal);
  					me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
  				});
  
  			} else {
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					var meta = chart.getDatasetMeta(datasetIndex);
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  						helpers.each(dataset.data, function(rawValue, index) {
  							var value = +me.getRightValue(rawValue);
  							if (isNaN(value) || meta.data[index].hidden) {
  								return;
  							}
  
  							if (me.min === null) {
  								me.min = value;
  							} else if (value < me.min) {
  								me.min = value;
  							}
  
  							if (me.max === null) {
  								me.max = value;
  							} else if (value > me.max) {
  								me.max = value;
  							}
  						});
  					}
  				});
  			}
  
  			me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
  			me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
  
  			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
  			this.handleTickRangeOptions();
  		},
  		getTickLimit: function() {
  			var maxTicks;
  			var me = this;
  			var tickOpts = me.options.ticks;
  
  			if (me.isHorizontal()) {
  				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
  			} else {
  				// The factor of 2 used to scale the font size has been experimentally determined.
  				var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
  				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
  			}
  
  			return maxTicks;
  		},
  		// Called after the ticks are built. We need
  		handleDirectionalChanges: function() {
  			if (!this.isHorizontal()) {
  				// We are in a vertical orientation. The top value is the highest. So reverse the array
  				this.ticks.reverse();
  			}
  		},
  		getLabelForIndex: function(index, datasetIndex) {
  			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  		},
  		// Utils
  		getPixelForValue: function(value) {
  			// This must be called after fit has been run so that
  			// this.left, this.top, this.right, and this.bottom have been defined
  			var me = this;
  			var start = me.start;
  
  			var rightValue = +me.getRightValue(value);
  			var pixel;
  			var range = me.end - start;
  
  			if (me.isHorizontal()) {
  				pixel = me.left + (me.width / range * (rightValue - start));
  			} else {
  				pixel = me.bottom - (me.height / range * (rightValue - start));
  			}
  			return pixel;
  		},
  		getValueForPixel: function(pixel) {
  			var me = this;
  			var isHorizontal = me.isHorizontal();
  			var innerDimension = isHorizontal ? me.width : me.height;
  			var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
  			return me.start + ((me.end - me.start) * offset);
  		},
  		getPixelForTick: function(index) {
  			return this.getPixelForValue(this.ticksAsNumbers[index]);
  		}
  	});
  
  	scaleService.registerScaleType('linear', LinearScale, defaultConfig);
  };
  
  },{"26":26,"34":34,"35":35,"46":46}],56:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  var Scale = require(33);
  
  /**
   * Generate a set of linear ticks
   * @param generationOptions the options used to generate the ticks
   * @param dataRange the range of the data
   * @returns {Array<Number>} array of tick values
   */
  function generateTicks(generationOptions, dataRange) {
  	var ticks = [];
  	// To get a "nice" value for the tick spacing, we will use the appropriately named
  	// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
  	// for details.
  
  	var factor;
  	var precision;
  	var spacing;
  
  	if (generationOptions.stepSize && generationOptions.stepSize > 0) {
  		spacing = generationOptions.stepSize;
  	} else {
  		var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
  		spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
  
  		precision = generationOptions.precision;
  		if (precision !== undefined) {
  			// If the user specified a precision, round to that number of decimal places
  			factor = Math.pow(10, precision);
  			spacing = Math.ceil(spacing * factor) / factor;
  		}
  	}
  	var niceMin = Math.floor(dataRange.min / spacing) * spacing;
  	var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
  
  	// If min, max and stepSize is set and they make an evenly spaced scale use it.
  	if (!helpers.isNullOrUndef(generationOptions.min) && !helpers.isNullOrUndef(generationOptions.max) && generationOptions.stepSize) {
  		// If very close to our whole number, use it.
  		if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
  			niceMin = generationOptions.min;
  			niceMax = generationOptions.max;
  		}
  	}
  
  	var numSpaces = (niceMax - niceMin) / spacing;
  	// If very close to our rounded value, use it.
  	if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
  		numSpaces = Math.round(numSpaces);
  	} else {
  		numSpaces = Math.ceil(numSpaces);
  	}
  
  	precision = 1;
  	if (spacing < 1) {
  		precision = Math.pow(10, 1 - Math.floor(helpers.log10(spacing)));
  		niceMin = Math.round(niceMin * precision) / precision;
  		niceMax = Math.round(niceMax * precision) / precision;
  	}
  	ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
  	for (var j = 1; j < numSpaces; ++j) {
  		ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
  	}
  	ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
  
  	return ticks;
  }
  
  module.exports = function(Chart) {
  
  	var noop = helpers.noop;
  
  	Chart.LinearScaleBase = Scale.extend({
  		getRightValue: function(value) {
  			if (typeof value === 'string') {
  				return +value;
  			}
  			return Scale.prototype.getRightValue.call(this, value);
  		},
  
  		handleTickRangeOptions: function() {
  			var me = this;
  			var opts = me.options;
  			var tickOpts = opts.ticks;
  
  			// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
  			// do nothing since that would make the chart weird. If the user really wants a weird chart
  			// axis, they can manually override it
  			if (tickOpts.beginAtZero) {
  				var minSign = helpers.sign(me.min);
  				var maxSign = helpers.sign(me.max);
  
  				if (minSign < 0 && maxSign < 0) {
  					// move the top up to 0
  					me.max = 0;
  				} else if (minSign > 0 && maxSign > 0) {
  					// move the bottom down to 0
  					me.min = 0;
  				}
  			}
  
  			var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
  			var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
  
  			if (tickOpts.min !== undefined) {
  				me.min = tickOpts.min;
  			} else if (tickOpts.suggestedMin !== undefined) {
  				if (me.min === null) {
  					me.min = tickOpts.suggestedMin;
  				} else {
  					me.min = Math.min(me.min, tickOpts.suggestedMin);
  				}
  			}
  
  			if (tickOpts.max !== undefined) {
  				me.max = tickOpts.max;
  			} else if (tickOpts.suggestedMax !== undefined) {
  				if (me.max === null) {
  					me.max = tickOpts.suggestedMax;
  				} else {
  					me.max = Math.max(me.max, tickOpts.suggestedMax);
  				}
  			}
  
  			if (setMin !== setMax) {
  				// We set the min or the max but not both.
  				// So ensure that our range is good
  				// Inverted or 0 length range can happen when
  				// ticks.min is set, and no datasets are visible
  				if (me.min >= me.max) {
  					if (setMin) {
  						me.max = me.min + 1;
  					} else {
  						me.min = me.max - 1;
  					}
  				}
  			}
  
  			if (me.min === me.max) {
  				me.max++;
  
  				if (!tickOpts.beginAtZero) {
  					me.min--;
  				}
  			}
  		},
  		getTickLimit: noop,
  		handleDirectionalChanges: noop,
  
  		buildTicks: function() {
  			var me = this;
  			var opts = me.options;
  			var tickOpts = opts.ticks;
  
  			// Figure out what the max number of ticks we can support it is based on the size of
  			// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
  			// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
  			// the graph. Make sure we always have at least 2 ticks
  			var maxTicks = me.getTickLimit();
  			maxTicks = Math.max(2, maxTicks);
  
  			var numericGeneratorOptions = {
  				maxTicks: maxTicks,
  				min: tickOpts.min,
  				max: tickOpts.max,
  				precision: tickOpts.precision,
  				stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
  			};
  			var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
  
  			me.handleDirectionalChanges();
  
  			// At this point, we need to update our max and min given the tick values since we have expanded the
  			// range of the scale
  			me.max = helpers.max(ticks);
  			me.min = helpers.min(ticks);
  
  			if (tickOpts.reverse) {
  				ticks.reverse();
  
  				me.start = me.max;
  				me.end = me.min;
  			} else {
  				me.start = me.min;
  				me.end = me.max;
  			}
  		},
  		convertTicksToLabels: function() {
  			var me = this;
  			me.ticksAsNumbers = me.ticks.slice();
  			me.zeroLineIndex = me.ticks.indexOf(0);
  
  			Scale.prototype.convertTicksToLabels.call(me);
  		}
  	});
  };
  
  },{"33":33,"46":46}],57:[function(require,module,exports){
  'use strict';
  
  var helpers = require(46);
  var Scale = require(33);
  var scaleService = require(34);
  var Ticks = require(35);
  
  /**
   * Generate a set of logarithmic ticks
   * @param generationOptions the options used to generate the ticks
   * @param dataRange the range of the data
   * @returns {Array<Number>} array of tick values
   */
  function generateTicks(generationOptions, dataRange) {
  	var ticks = [];
  	var valueOrDefault = helpers.valueOrDefault;
  
  	// Figure out what the max number of ticks we can support it is based on the size of
  	// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
  	// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
  	// the graph
  	var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
  
  	var endExp = Math.floor(helpers.log10(dataRange.max));
  	var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
  	var exp, significand;
  
  	if (tickVal === 0) {
  		exp = Math.floor(helpers.log10(dataRange.minNotZero));
  		significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
  
  		ticks.push(tickVal);
  		tickVal = significand * Math.pow(10, exp);
  	} else {
  		exp = Math.floor(helpers.log10(tickVal));
  		significand = Math.floor(tickVal / Math.pow(10, exp));
  	}
  	var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
  
  	do {
  		ticks.push(tickVal);
  
  		++significand;
  		if (significand === 10) {
  			significand = 1;
  			++exp;
  			precision = exp >= 0 ? 1 : precision;
  		}
  
  		tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
  	} while (exp < endExp || (exp === endExp && significand < endSignificand));
  
  	var lastTick = valueOrDefault(generationOptions.max, tickVal);
  	ticks.push(lastTick);
  
  	return ticks;
  }
  
  
  module.exports = function(Chart) {
  
  	var defaultConfig = {
  		position: 'left',
  
  		// label settings
  		ticks: {
  			callback: Ticks.formatters.logarithmic
  		}
  	};
  
  	var LogarithmicScale = Scale.extend({
  		determineDataLimits: function() {
  			var me = this;
  			var opts = me.options;
  			var chart = me.chart;
  			var data = chart.data;
  			var datasets = data.datasets;
  			var isHorizontal = me.isHorizontal();
  			function IDMatches(meta) {
  				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
  			}
  
  			// Calculate Range
  			me.min = null;
  			me.max = null;
  			me.minNotZero = null;
  
  			var hasStacks = opts.stacked;
  			if (hasStacks === undefined) {
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					if (hasStacks) {
  						return;
  					}
  
  					var meta = chart.getDatasetMeta(datasetIndex);
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
  						meta.stack !== undefined) {
  						hasStacks = true;
  					}
  				});
  			}
  
  			if (opts.stacked || hasStacks) {
  				var valuesPerStack = {};
  
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					var meta = chart.getDatasetMeta(datasetIndex);
  					var key = [
  						meta.type,
  						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
  						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
  						meta.stack
  					].join('.');
  
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  						if (valuesPerStack[key] === undefined) {
  							valuesPerStack[key] = [];
  						}
  
  						helpers.each(dataset.data, function(rawValue, index) {
  							var values = valuesPerStack[key];
  							var value = +me.getRightValue(rawValue);
  							// invalid, hidden and negative values are ignored
  							if (isNaN(value) || meta.data[index].hidden || value < 0) {
  								return;
  							}
  							values[index] = values[index] || 0;
  							values[index] += value;
  						});
  					}
  				});
  
  				helpers.each(valuesPerStack, function(valuesForType) {
  					if (valuesForType.length > 0) {
  						var minVal = helpers.min(valuesForType);
  						var maxVal = helpers.max(valuesForType);
  						me.min = me.min === null ? minVal : Math.min(me.min, minVal);
  						me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
  					}
  				});
  
  			} else {
  				helpers.each(datasets, function(dataset, datasetIndex) {
  					var meta = chart.getDatasetMeta(datasetIndex);
  					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  						helpers.each(dataset.data, function(rawValue, index) {
  							var value = +me.getRightValue(rawValue);
  							// invalid, hidden and negative values are ignored
  							if (isNaN(value) || meta.data[index].hidden || value < 0) {
  								return;
  							}
  
  							if (me.min === null) {
  								me.min = value;
  							} else if (value < me.min) {
  								me.min = value;
  							}
  
  							if (me.max === null) {
  								me.max = value;
  							} else if (value > me.max) {
  								me.max = value;
  							}
  
  							if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
  								me.minNotZero = value;
  							}
  						});
  					}
  				});
  			}
  
  			// Common base implementation to handle ticks.min, ticks.max
  			this.handleTickRangeOptions();
  		},
  		handleTickRangeOptions: function() {
  			var me = this;
  			var opts = me.options;
  			var tickOpts = opts.ticks;
  			var valueOrDefault = helpers.valueOrDefault;
  			var DEFAULT_MIN = 1;
  			var DEFAULT_MAX = 10;
  
  			me.min = valueOrDefault(tickOpts.min, me.min);
  			me.max = valueOrDefault(tickOpts.max, me.max);
  
  			if (me.min === me.max) {
  				if (me.min !== 0 && me.min !== null) {
  					me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
  					me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
  				} else {
  					me.min = DEFAULT_MIN;
  					me.max = DEFAULT_MAX;
  				}
  			}
  			if (me.min === null) {
  				me.min = Math.pow(10, Math.floor(helpers.log10(me.max)) - 1);
  			}
  			if (me.max === null) {
  				me.max = me.min !== 0
  					? Math.pow(10, Math.floor(helpers.log10(me.min)) + 1)
  					: DEFAULT_MAX;
  			}
  			if (me.minNotZero === null) {
  				if (me.min > 0) {
  					me.minNotZero = me.min;
  				} else if (me.max < 1) {
  					me.minNotZero = Math.pow(10, Math.floor(helpers.log10(me.max)));
  				} else {
  					me.minNotZero = DEFAULT_MIN;
  				}
  			}
  		},
  		buildTicks: function() {
  			var me = this;
  			var opts = me.options;
  			var tickOpts = opts.ticks;
  			var reverse = !me.isHorizontal();
  
  			var generationOptions = {
  				min: tickOpts.min,
  				max: tickOpts.max
  			};
  			var ticks = me.ticks = generateTicks(generationOptions, me);
  
  			// At this point, we need to update our max and min given the tick values since we have expanded the
  			// range of the scale
  			me.max = helpers.max(ticks);
  			me.min = helpers.min(ticks);
  
  			if (tickOpts.reverse) {
  				reverse = !reverse;
  				me.start = me.max;
  				me.end = me.min;
  			} else {
  				me.start = me.min;
  				me.end = me.max;
  			}
  			if (reverse) {
  				ticks.reverse();
  			}
  		},
  		convertTicksToLabels: function() {
  			this.tickValues = this.ticks.slice();
  
  			Scale.prototype.convertTicksToLabels.call(this);
  		},
  		// Get the correct tooltip label
  		getLabelForIndex: function(index, datasetIndex) {
  			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  		},
  		getPixelForTick: function(index) {
  			return this.getPixelForValue(this.tickValues[index]);
  		},
  		/**
  		 * Returns the value of the first tick.
  		 * @param {Number} value - The minimum not zero value.
  		 * @return {Number} The first tick value.
  		 * @private
  		 */
  		_getFirstTickValue: function(value) {
  			var exp = Math.floor(helpers.log10(value));
  			var significand = Math.floor(value / Math.pow(10, exp));
  
  			return significand * Math.pow(10, exp);
  		},
  		getPixelForValue: function(value) {
  			var me = this;
  			var reverse = me.options.ticks.reverse;
  			var log10 = helpers.log10;
  			var firstTickValue = me._getFirstTickValue(me.minNotZero);
  			var offset = 0;
  			var innerDimension, pixel, start, end, sign;
  
  			value = +me.getRightValue(value);
  			if (reverse) {
  				start = me.end;
  				end = me.start;
  				sign = -1;
  			} else {
  				start = me.start;
  				end = me.end;
  				sign = 1;
  			}
  			if (me.isHorizontal()) {
  				innerDimension = me.width;
  				pixel = reverse ? me.right : me.left;
  			} else {
  				innerDimension = me.height;
  				sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
  				pixel = reverse ? me.top : me.bottom;
  			}
  			if (value !== start) {
  				if (start === 0) { // include zero tick
  					offset = helpers.getValueOrDefault(
  						me.options.ticks.fontSize,
  						Chart.defaults.global.defaultFontSize
  					);
  					innerDimension -= offset;
  					start = firstTickValue;
  				}
  				if (value !== 0) {
  					offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
  				}
  				pixel += sign * offset;
  			}
  			return pixel;
  		},
  		getValueForPixel: function(pixel) {
  			var me = this;
  			var reverse = me.options.ticks.reverse;
  			var log10 = helpers.log10;
  			var firstTickValue = me._getFirstTickValue(me.minNotZero);
  			var innerDimension, start, end, value;
  
  			if (reverse) {
  				start = me.end;
  				end = me.start;
  			} else {
  				start = me.start;
  				end = me.end;
  			}
  			if (me.isHorizontal()) {
  				innerDimension = me.width;
  				value = reverse ? me.right - pixel : pixel - me.left;
  			} else {
  				innerDimension = me.height;
  				value = reverse ? pixel - me.top : me.bottom - pixel;
  			}
  			if (value !== start) {
  				if (start === 0) { // include zero tick
  					var offset = helpers.getValueOrDefault(
  						me.options.ticks.fontSize,
  						Chart.defaults.global.defaultFontSize
  					);
  					value -= offset;
  					innerDimension -= offset;
  					start = firstTickValue;
  				}
  				value *= log10(end) - log10(start);
  				value /= innerDimension;
  				value = Math.pow(10, log10(start) + value);
  			}
  			return value;
  		}
  	});
  
  	scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
  };
  
  },{"33":33,"34":34,"35":35,"46":46}],58:[function(require,module,exports){
  'use strict';
  
  var defaults = require(26);
  var helpers = require(46);
  var scaleService = require(34);
  var Ticks = require(35);
  
  module.exports = function(Chart) {
  
  	var globalDefaults = defaults.global;
  
  	var defaultConfig = {
  		display: true,
  
  		// Boolean - Whether to animate scaling the chart from the centre
  		animate: true,
  		position: 'chartArea',
  
  		angleLines: {
  			display: true,
  			color: 'rgba(0, 0, 0, 0.1)',
  			lineWidth: 1
  		},
  
  		gridLines: {
  			circular: false
  		},
  
  		// label settings
  		ticks: {
  			// Boolean - Show a backdrop to the scale label
  			showLabelBackdrop: true,
  
  			// String - The colour of the label backdrop
  			backdropColor: 'rgba(255,255,255,0.75)',
  
  			// Number - The backdrop padding above & below the label in pixels
  			backdropPaddingY: 2,
  
  			// Number - The backdrop padding to the side of the label in pixels
  			backdropPaddingX: 2,
  
  			callback: Ticks.formatters.linear
  		},
  
  		pointLabels: {
  			// Boolean - if true, show point labels
  			display: true,
  
  			// Number - Point label font size in pixels
  			fontSize: 10,
  
  			// Function - Used to convert point labels
  			callback: function(label) {
  				return label;
  			}
  		}
  	};
  
  	function getValueCount(scale) {
  		var opts = scale.options;
  		return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
  	}
  
  	function getPointLabelFontOptions(scale) {
  		var pointLabelOptions = scale.options.pointLabels;
  		var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
  		var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
  		var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
  		var font = helpers.fontString(fontSize, fontStyle, fontFamily);
  
  		return {
  			size: fontSize,
  			style: fontStyle,
  			family: fontFamily,
  			font: font
  		};
  	}
  
  	function measureLabelSize(ctx, fontSize, label) {
  		if (helpers.isArray(label)) {
  			return {
  				w: helpers.longestText(ctx, ctx.font, label),
  				h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
  			};
  		}
  
  		return {
  			w: ctx.measureText(label).width,
  			h: fontSize
  		};
  	}
  
  	function determineLimits(angle, pos, size, min, max) {
  		if (angle === min || angle === max) {
  			return {
  				start: pos - (size / 2),
  				end: pos + (size / 2)
  			};
  		} else if (angle < min || angle > max) {
  			return {
  				start: pos - size - 5,
  				end: pos
  			};
  		}
  
  		return {
  			start: pos,
  			end: pos + size + 5
  		};
  	}
  
  	/**
  	 * Helper function to fit a radial linear scale with point labels
  	 */
  	function fitWithPointLabels(scale) {
  		/*
  		 * Right, this is really confusing and there is a lot of maths going on here
  		 * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
  		 *
  		 * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
  		 *
  		 * Solution:
  		 *
  		 * We assume the radius of the polygon is half the size of the canvas at first
  		 * at each index we check if the text overlaps.
  		 *
  		 * Where it does, we store that angle and that index.
  		 *
  		 * After finding the largest index and angle we calculate how much we need to remove
  		 * from the shape radius to move the point inwards by that x.
  		 *
  		 * We average the left and right distances to get the maximum shape radius that can fit in the box
  		 * along with labels.
  		 *
  		 * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
  		 * on each side, removing that from the size, halving it and adding the left x protrusion width.
  		 *
  		 * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
  		 * and position it in the most space efficient manner
  		 *
  		 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
  		 */
  
  		var plFont = getPointLabelFontOptions(scale);
  
  		// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
  		// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
  		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
  		var furthestLimits = {
  			r: scale.width,
  			l: 0,
  			t: scale.height,
  			b: 0
  		};
  		var furthestAngles = {};
  		var i, textSize, pointPosition;
  
  		scale.ctx.font = plFont.font;
  		scale._pointLabelSizes = [];
  
  		var valueCount = getValueCount(scale);
  		for (i = 0; i < valueCount; i++) {
  			pointPosition = scale.getPointPosition(i, largestPossibleRadius);
  			textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
  			scale._pointLabelSizes[i] = textSize;
  
  			// Add quarter circle to make degree 0 mean top of circle
  			var angleRadians = scale.getIndexAngle(i);
  			var angle = helpers.toDegrees(angleRadians) % 360;
  			var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
  			var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
  
  			if (hLimits.start < furthestLimits.l) {
  				furthestLimits.l = hLimits.start;
  				furthestAngles.l = angleRadians;
  			}
  
  			if (hLimits.end > furthestLimits.r) {
  				furthestLimits.r = hLimits.end;
  				furthestAngles.r = angleRadians;
  			}
  
  			if (vLimits.start < furthestLimits.t) {
  				furthestLimits.t = vLimits.start;
  				furthestAngles.t = angleRadians;
  			}
  
  			if (vLimits.end > furthestLimits.b) {
  				furthestLimits.b = vLimits.end;
  				furthestAngles.b = angleRadians;
  			}
  		}
  
  		scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
  	}
  
  	/**
  	 * Helper function to fit a radial linear scale with no point labels
  	 */
  	function fit(scale) {
  		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
  		scale.drawingArea = Math.round(largestPossibleRadius);
  		scale.setCenterPoint(0, 0, 0, 0);
  	}
  
  	function getTextAlignForAngle(angle) {
  		if (angle === 0 || angle === 180) {
  			return 'center';
  		} else if (angle < 180) {
  			return 'left';
  		}
  
  		return 'right';
  	}
  
  	function fillText(ctx, text, position, fontSize) {
  		if (helpers.isArray(text)) {
  			var y = position.y;
  			var spacing = 1.5 * fontSize;
  
  			for (var i = 0; i < text.length; ++i) {
  				ctx.fillText(text[i], position.x, y);
  				y += spacing;
  			}
  		} else {
  			ctx.fillText(text, position.x, position.y);
  		}
  	}
  
  	function adjustPointPositionForLabelHeight(angle, textSize, position) {
  		if (angle === 90 || angle === 270) {
  			position.y -= (textSize.h / 2);
  		} else if (angle > 270 || angle < 90) {
  			position.y -= textSize.h;
  		}
  	}
  
  	function drawPointLabels(scale) {
  		var ctx = scale.ctx;
  		var opts = scale.options;
  		var angleLineOpts = opts.angleLines;
  		var pointLabelOpts = opts.pointLabels;
  
  		ctx.lineWidth = angleLineOpts.lineWidth;
  		ctx.strokeStyle = angleLineOpts.color;
  
  		var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
  
  		// Point Label Font
  		var plFont = getPointLabelFontOptions(scale);
  
  		ctx.textBaseline = 'top';
  
  		for (var i = getValueCount(scale) - 1; i >= 0; i--) {
  			if (angleLineOpts.display) {
  				var outerPosition = scale.getPointPosition(i, outerDistance);
  				ctx.beginPath();
  				ctx.moveTo(scale.xCenter, scale.yCenter);
  				ctx.lineTo(outerPosition.x, outerPosition.y);
  				ctx.stroke();
  				ctx.closePath();
  			}
  
  			if (pointLabelOpts.display) {
  				// Extra 3px out for some label spacing
  				var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
  
  				// Keep this in loop since we may support array properties here
  				var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor);
  				ctx.font = plFont.font;
  				ctx.fillStyle = pointLabelFontColor;
  
  				var angleRadians = scale.getIndexAngle(i);
  				var angle = helpers.toDegrees(angleRadians);
  				ctx.textAlign = getTextAlignForAngle(angle);
  				adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
  				fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
  			}
  		}
  	}
  
  	function drawRadiusLine(scale, gridLineOpts, radius, index) {
  		var ctx = scale.ctx;
  		ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1);
  		ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
  
  		if (scale.options.gridLines.circular) {
  			// Draw circular arcs between the points
  			ctx.beginPath();
  			ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
  			ctx.closePath();
  			ctx.stroke();
  		} else {
  			// Draw straight lines connecting each index
  			var valueCount = getValueCount(scale);
  
  			if (valueCount === 0) {
  				return;
  			}
  
  			ctx.beginPath();
  			var pointPosition = scale.getPointPosition(0, radius);
  			ctx.moveTo(pointPosition.x, pointPosition.y);
  
  			for (var i = 1; i < valueCount; i++) {
  				pointPosition = scale.getPointPosition(i, radius);
  				ctx.lineTo(pointPosition.x, pointPosition.y);
  			}
  
  			ctx.closePath();
  			ctx.stroke();
  		}
  	}
  
  	function numberOrZero(param) {
  		return helpers.isNumber(param) ? param : 0;
  	}
  
  	var LinearRadialScale = Chart.LinearScaleBase.extend({
  		setDimensions: function() {
  			var me = this;
  			var opts = me.options;
  			var tickOpts = opts.ticks;
  			// Set the unconstrained dimension before label rotation
  			me.width = me.maxWidth;
  			me.height = me.maxHeight;
  			me.xCenter = Math.round(me.width / 2);
  			me.yCenter = Math.round(me.height / 2);
  
  			var minSize = helpers.min([me.height, me.width]);
  			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
  			me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
  		},
  		determineDataLimits: function() {
  			var me = this;
  			var chart = me.chart;
  			var min = Number.POSITIVE_INFINITY;
  			var max = Number.NEGATIVE_INFINITY;
  
  			helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
  				if (chart.isDatasetVisible(datasetIndex)) {
  					var meta = chart.getDatasetMeta(datasetIndex);
  
  					helpers.each(dataset.data, function(rawValue, index) {
  						var value = +me.getRightValue(rawValue);
  						if (isNaN(value) || meta.data[index].hidden) {
  							return;
  						}
  
  						min = Math.min(value, min);
  						max = Math.max(value, max);
  					});
  				}
  			});
  
  			me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
  			me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
  
  			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
  			me.handleTickRangeOptions();
  		},
  		getTickLimit: function() {
  			var tickOpts = this.options.ticks;
  			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
  			return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
  		},
  		convertTicksToLabels: function() {
  			var me = this;
  
  			Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
  
  			// Point labels
  			me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
  		},
  		getLabelForIndex: function(index, datasetIndex) {
  			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  		},
  		fit: function() {
  			if (this.options.pointLabels.display) {
  				fitWithPointLabels(this);
  			} else {
  				fit(this);
  			}
  		},
  		/**
  		 * Set radius reductions and determine new radius and center point
  		 * @private
  		 */
  		setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
  			var me = this;
  			var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
  			var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
  			var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
  			var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
  
  			radiusReductionLeft = numberOrZero(radiusReductionLeft);
  			radiusReductionRight = numberOrZero(radiusReductionRight);
  			radiusReductionTop = numberOrZero(radiusReductionTop);
  			radiusReductionBottom = numberOrZero(radiusReductionBottom);
  
  			me.drawingArea = Math.min(
  				Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
  				Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
  			me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
  		},
  		setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
  			var me = this;
  			var maxRight = me.width - rightMovement - me.drawingArea;
  			var maxLeft = leftMovement + me.drawingArea;
  			var maxTop = topMovement + me.drawingArea;
  			var maxBottom = me.height - bottomMovement - me.drawingArea;
  
  			me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
  			me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
  		},
  
  		getIndexAngle: function(index) {
  			var angleMultiplier = (Math.PI * 2) / getValueCount(this);
  			var startAngle = this.chart.options && this.chart.options.startAngle ?
  				this.chart.options.startAngle :
  				0;
  
  			var startAngleRadians = startAngle * Math.PI * 2 / 360;
  
  			// Start from the top instead of right, so remove a quarter of the circle
  			return index * angleMultiplier + startAngleRadians;
  		},
  		getDistanceFromCenterForValue: function(value) {
  			var me = this;
  
  			if (value === null) {
  				return 0; // null always in center
  			}
  
  			// Take into account half font size + the yPadding of the top value
  			var scalingFactor = me.drawingArea / (me.max - me.min);
  			if (me.options.ticks.reverse) {
  				return (me.max - value) * scalingFactor;
  			}
  			return (value - me.min) * scalingFactor;
  		},
  		getPointPosition: function(index, distanceFromCenter) {
  			var me = this;
  			var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
  			return {
  				x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
  				y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
  			};
  		},
  		getPointPositionForValue: function(index, value) {
  			return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
  		},
  
  		getBasePosition: function() {
  			var me = this;
  			var min = me.min;
  			var max = me.max;
  
  			return me.getPointPositionForValue(0,
  				me.beginAtZero ? 0 :
  				min < 0 && max < 0 ? max :
  				min > 0 && max > 0 ? min :
  				0);
  		},
  
  		draw: function() {
  			var me = this;
  			var opts = me.options;
  			var gridLineOpts = opts.gridLines;
  			var tickOpts = opts.ticks;
  			var valueOrDefault = helpers.valueOrDefault;
  
  			if (opts.display) {
  				var ctx = me.ctx;
  				var startAngle = this.getIndexAngle(0);
  
  				// Tick Font
  				var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
  				var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
  				var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
  				var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  
  				helpers.each(me.ticks, function(label, index) {
  					// Don't draw a centre value (if it is minimum)
  					if (index > 0 || tickOpts.reverse) {
  						var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
  
  						// Draw circular lines around the scale
  						if (gridLineOpts.display && index !== 0) {
  							drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
  						}
  
  						if (tickOpts.display) {
  							var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
  							ctx.font = tickLabelFont;
  
  							ctx.save();
  							ctx.translate(me.xCenter, me.yCenter);
  							ctx.rotate(startAngle);
  
  							if (tickOpts.showLabelBackdrop) {
  								var labelWidth = ctx.measureText(label).width;
  								ctx.fillStyle = tickOpts.backdropColor;
  								ctx.fillRect(
  									-labelWidth / 2 - tickOpts.backdropPaddingX,
  									-yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
  									labelWidth + tickOpts.backdropPaddingX * 2,
  									tickFontSize + tickOpts.backdropPaddingY * 2
  								);
  							}
  
  							ctx.textAlign = 'center';
  							ctx.textBaseline = 'middle';
  							ctx.fillStyle = tickFontColor;
  							ctx.fillText(label, 0, -yCenterOffset);
  							ctx.restore();
  						}
  					}
  				});
  
  				if (opts.angleLines.display || opts.pointLabels.display) {
  					drawPointLabels(me);
  				}
  			}
  		}
  	});
  
  	scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
  };
  
  },{"26":26,"34":34,"35":35,"46":46}],59:[function(require,module,exports){
  /* global window: false */
  'use strict';
  
  var moment = require(1);
  moment = typeof moment === 'function' ? moment : window.moment;
  
  var defaults = require(26);
  var helpers = require(46);
  var Scale = require(33);
  var scaleService = require(34);
  
  // Integer constants are from the ES6 spec.
  var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
  var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
  
  var INTERVALS = {
  	millisecond: {
  		common: true,
  		size: 1,
  		steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
  	},
  	second: {
  		common: true,
  		size: 1000,
  		steps: [1, 2, 5, 10, 15, 30]
  	},
  	minute: {
  		common: true,
  		size: 60000,
  		steps: [1, 2, 5, 10, 15, 30]
  	},
  	hour: {
  		common: true,
  		size: 3600000,
  		steps: [1, 2, 3, 6, 12]
  	},
  	day: {
  		common: true,
  		size: 86400000,
  		steps: [1, 2, 5]
  	},
  	week: {
  		common: false,
  		size: 604800000,
  		steps: [1, 2, 3, 4]
  	},
  	month: {
  		common: true,
  		size: 2.628e9,
  		steps: [1, 2, 3]
  	},
  	quarter: {
  		common: false,
  		size: 7.884e9,
  		steps: [1, 2, 3, 4]
  	},
  	year: {
  		common: true,
  		size: 3.154e10
  	}
  };
  
  var UNITS = Object.keys(INTERVALS);
  
  function sorter(a, b) {
  	return a - b;
  }
  
  function arrayUnique(items) {
  	var hash = {};
  	var out = [];
  	var i, ilen, item;
  
  	for (i = 0, ilen = items.length; i < ilen; ++i) {
  		item = items[i];
  		if (!hash[item]) {
  			hash[item] = true;
  			out.push(item);
  		}
  	}
  
  	return out;
  }
  
  /**
   * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
   * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
   * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
   * extremity (left + width or top + height). Note that it would be more optimized to directly
   * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
   * to create the lookup table. The table ALWAYS contains at least two items: min and max.
   *
   * @param {Number[]} timestamps - timestamps sorted from lowest to highest.
   * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min
   * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
   * If 'series', timestamps will be positioned at the same distance from each other. In this
   * case, only timestamps that break the time linearity are registered, meaning that in the
   * best case, all timestamps are linear, the table contains only min and max.
   */
  function buildLookupTable(timestamps, min, max, distribution) {
  	if (distribution === 'linear' || !timestamps.length) {
  		return [
  			{time: min, pos: 0},
  			{time: max, pos: 1}
  		];
  	}
  
  	var table = [];
  	var items = [min];
  	var i, ilen, prev, curr, next;
  
  	for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
  		curr = timestamps[i];
  		if (curr > min && curr < max) {
  			items.push(curr);
  		}
  	}
  
  	items.push(max);
  
  	for (i = 0, ilen = items.length; i < ilen; ++i) {
  		next = items[i + 1];
  		prev = items[i - 1];
  		curr = items[i];
  
  		// only add points that breaks the scale linearity
  		if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
  			table.push({time: curr, pos: i / (ilen - 1)});
  		}
  	}
  
  	return table;
  }
  
  // @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
  function lookup(table, key, value) {
  	var lo = 0;
  	var hi = table.length - 1;
  	var mid, i0, i1;
  
  	while (lo >= 0 && lo <= hi) {
  		mid = (lo + hi) >> 1;
  		i0 = table[mid - 1] || null;
  		i1 = table[mid];
  
  		if (!i0) {
  			// given value is outside table (before first item)
  			return {lo: null, hi: i1};
  		} else if (i1[key] < value) {
  			lo = mid + 1;
  		} else if (i0[key] > value) {
  			hi = mid - 1;
  		} else {
  			return {lo: i0, hi: i1};
  		}
  	}
  
  	// given value is outside table (after last item)
  	return {lo: i1, hi: null};
  }
  
  /**
   * Linearly interpolates the given source `value` using the table items `skey` values and
   * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
   * returns the position for a timestamp equal to 42. If value is out of bounds, values at
   * index [0, 1] or [n - 1, n] are used for the interpolation.
   */
  function interpolate(table, skey, sval, tkey) {
  	var range = lookup(table, skey, sval);
  
  	// Note: the lookup table ALWAYS contains at least 2 items (min and max)
  	var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
  	var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
  
  	var span = next[skey] - prev[skey];
  	var ratio = span ? (sval - prev[skey]) / span : 0;
  	var offset = (next[tkey] - prev[tkey]) * ratio;
  
  	return prev[tkey] + offset;
  }
  
  /**
   * Convert the given value to a moment object using the given time options.
   * @see http://momentjs.com/docs/#/parsing/
   */
  function momentify(value, options) {
  	var parser = options.parser;
  	var format = options.parser || options.format;
  
  	if (typeof parser === 'function') {
  		return parser(value);
  	}
  
  	if (typeof value === 'string' && typeof format === 'string') {
  		return moment(value, format);
  	}
  
  	if (!(value instanceof moment)) {
  		value = moment(value);
  	}
  
  	if (value.isValid()) {
  		return value;
  	}
  
  	// Labels are in an incompatible moment format and no `parser` has been provided.
  	// The user might still use the deprecated `format` option to convert his inputs.
  	if (typeof format === 'function') {
  		return format(value);
  	}
  
  	return value;
  }
  
  function parse(input, scale) {
  	if (helpers.isNullOrUndef(input)) {
  		return null;
  	}
  
  	var options = scale.options.time;
  	var value = momentify(scale.getRightValue(input), options);
  	if (!value.isValid()) {
  		return null;
  	}
  
  	if (options.round) {
  		value.startOf(options.round);
  	}
  
  	return value.valueOf();
  }
  
  /**
   * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
   * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
   */
  function determineStepSize(min, max, unit, capacity) {
  	var range = max - min;
  	var interval = INTERVALS[unit];
  	var milliseconds = interval.size;
  	var steps = interval.steps;
  	var i, ilen, factor;
  
  	if (!steps) {
  		return Math.ceil(range / (capacity * milliseconds));
  	}
  
  	for (i = 0, ilen = steps.length; i < ilen; ++i) {
  		factor = steps[i];
  		if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
  			break;
  		}
  	}
  
  	return factor;
  }
  
  /**
   * Figures out what unit results in an appropriate number of auto-generated ticks
   */
  function determineUnitForAutoTicks(minUnit, min, max, capacity) {
  	var ilen = UNITS.length;
  	var i, interval, factor;
  
  	for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
  		interval = INTERVALS[UNITS[i]];
  		factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
  
  		if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
  			return UNITS[i];
  		}
  	}
  
  	return UNITS[ilen - 1];
  }
  
  /**
   * Figures out what unit to format a set of ticks with
   */
  function determineUnitForFormatting(ticks, minUnit, min, max) {
  	var duration = moment.duration(moment(max).diff(moment(min)));
  	var ilen = UNITS.length;
  	var i, unit;
  
  	for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
  		unit = UNITS[i];
  		if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
  			return unit;
  		}
  	}
  
  	return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
  }
  
  function determineMajorUnit(unit) {
  	for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
  		if (INTERVALS[UNITS[i]].common) {
  			return UNITS[i];
  		}
  	}
  }
  
  /**
   * Generates a maximum of `capacity` timestamps between min and max, rounded to the
   * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
   * Important: this method can return ticks outside the min and max range, it's the
   * responsibility of the calling code to clamp values if needed.
   */
  function generate(min, max, capacity, options) {
  	var timeOpts = options.time;
  	var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
  	var major = determineMajorUnit(minor);
  	var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
  	var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
  	var majorTicksEnabled = options.ticks.major.enabled;
  	var interval = INTERVALS[minor];
  	var first = moment(min);
  	var last = moment(max);
  	var ticks = [];
  	var time;
  
  	if (!stepSize) {
  		stepSize = determineStepSize(min, max, minor, capacity);
  	}
  
  	// For 'week' unit, handle the first day of week option
  	if (weekday) {
  		first = first.isoWeekday(weekday);
  		last = last.isoWeekday(weekday);
  	}
  
  	// Align first/last ticks on unit
  	first = first.startOf(weekday ? 'day' : minor);
  	last = last.startOf(weekday ? 'day' : minor);
  
  	// Make sure that the last tick include max
  	if (last < max) {
  		last.add(1, minor);
  	}
  
  	time = moment(first);
  
  	if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
  		// Align the first tick on the previous `minor` unit aligned on the `major` unit:
  		// we first aligned time on the previous `major` unit then add the number of full
  		// stepSize there is between first and the previous major time.
  		time.startOf(major);
  		time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
  	}
  
  	for (; time < last; time.add(stepSize, minor)) {
  		ticks.push(+time);
  	}
  
  	ticks.push(+time);
  
  	return ticks;
  }
  
  /**
   * Returns the right and left offsets from edges in the form of {left, right}.
   * Offsets are added when the `offset` option is true.
   */
  function computeOffsets(table, ticks, min, max, options) {
  	var left = 0;
  	var right = 0;
  	var upper, lower;
  
  	if (options.offset && ticks.length) {
  		if (!options.time.min) {
  			upper = ticks.length > 1 ? ticks[1] : max;
  			lower = ticks[0];
  			left = (
  				interpolate(table, 'time', upper, 'pos') -
  				interpolate(table, 'time', lower, 'pos')
  			) / 2;
  		}
  		if (!options.time.max) {
  			upper = ticks[ticks.length - 1];
  			lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
  			right = (
  				interpolate(table, 'time', upper, 'pos') -
  				interpolate(table, 'time', lower, 'pos')
  			) / 2;
  		}
  	}
  
  	return {left: left, right: right};
  }
  
  function ticksFromTimestamps(values, majorUnit) {
  	var ticks = [];
  	var i, ilen, value, major;
  
  	for (i = 0, ilen = values.length; i < ilen; ++i) {
  		value = values[i];
  		major = majorUnit ? value === +moment(value).startOf(majorUnit) : false;
  
  		ticks.push({
  			value: value,
  			major: major
  		});
  	}
  
  	return ticks;
  }
  
  function determineLabelFormat(data, timeOpts) {
  	var i, momentDate, hasTime;
  	var ilen = data.length;
  
  	// find the label with the most parts (milliseconds, minutes, etc.)
  	// format all labels with the same level of detail as the most specific label
  	for (i = 0; i < ilen; i++) {
  		momentDate = momentify(data[i], timeOpts);
  		if (momentDate.millisecond() !== 0) {
  			return 'MMM D, YYYY h:mm:ss.SSS a';
  		}
  		if (momentDate.second() !== 0 || momentDate.minute() !== 0 || momentDate.hour() !== 0) {
  			hasTime = true;
  		}
  	}
  	if (hasTime) {
  		return 'MMM D, YYYY h:mm:ss a';
  	}
  	return 'MMM D, YYYY';
  }
  
  module.exports = function() {
  
  	var defaultConfig = {
  		position: 'bottom',
  
  		/**
  		 * Data distribution along the scale:
  		 * - 'linear': data are spread according to their time (distances can vary),
  		 * - 'series': data are spread at the same distance from each other.
  		 * @see https://github.com/chartjs/Chart.js/pull/4507
  		 * @since 2.7.0
  		 */
  		distribution: 'linear',
  
  		/**
  		 * Scale boundary strategy (bypassed by min/max time options)
  		 * - `data`: make sure data are fully visible, ticks outside are removed
  		 * - `ticks`: make sure ticks are fully visible, data outside are truncated
  		 * @see https://github.com/chartjs/Chart.js/pull/4556
  		 * @since 2.7.0
  		 */
  		bounds: 'data',
  
  		time: {
  			parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
  			format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
  			unit: false, // false == automatic or override with week, month, year, etc.
  			round: false, // none, or override with week, month, year, etc.
  			displayFormat: false, // DEPRECATED
  			isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
  			minUnit: 'millisecond',
  
  			// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
  			displayFormats: {
  				millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
  				second: 'h:mm:ss a', // 11:20:01 AM
  				minute: 'h:mm a', // 11:20 AM
  				hour: 'hA', // 5PM
  				day: 'MMM D', // Sep 4
  				week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
  				month: 'MMM YYYY', // Sept 2015
  				quarter: '[Q]Q - YYYY', // Q3
  				year: 'YYYY' // 2015
  			},
  		},
  		ticks: {
  			autoSkip: false,
  
  			/**
  			 * Ticks generation input values:
  			 * - 'auto': generates "optimal" ticks based on scale size and time options.
  			 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
  			 * - 'labels': generates ticks from user given `data.labels` values ONLY.
  			 * @see https://github.com/chartjs/Chart.js/pull/4507
  			 * @since 2.7.0
  			 */
  			source: 'auto',
  
  			major: {
  				enabled: false
  			}
  		}
  	};
  
  	var TimeScale = Scale.extend({
  		initialize: function() {
  			if (!moment) {
  				throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
  			}
  
  			this.mergeTicksOptions();
  
  			Scale.prototype.initialize.call(this);
  		},
  
  		update: function() {
  			var me = this;
  			var options = me.options;
  
  			// DEPRECATIONS: output a message only one time per update
  			if (options.time && options.time.format) {
  				console.warn('options.time.format is deprecated and replaced by options.time.parser.');
  			}
  
  			return Scale.prototype.update.apply(me, arguments);
  		},
  
  		/**
  		 * Allows data to be referenced via 't' attribute
  		 */
  		getRightValue: function(rawValue) {
  			if (rawValue && rawValue.t !== undefined) {
  				rawValue = rawValue.t;
  			}
  			return Scale.prototype.getRightValue.call(this, rawValue);
  		},
  
  		determineDataLimits: function() {
  			var me = this;
  			var chart = me.chart;
  			var timeOpts = me.options.time;
  			var unit = timeOpts.unit || 'day';
  			var min = MAX_INTEGER;
  			var max = MIN_INTEGER;
  			var timestamps = [];
  			var datasets = [];
  			var labels = [];
  			var i, j, ilen, jlen, data, timestamp;
  
  			// Convert labels to timestamps
  			for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) {
  				labels.push(parse(chart.data.labels[i], me));
  			}
  
  			// Convert data to timestamps
  			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  				if (chart.isDatasetVisible(i)) {
  					data = chart.data.datasets[i].data;
  
  					// Let's consider that all data have the same format.
  					if (helpers.isObject(data[0])) {
  						datasets[i] = [];
  
  						for (j = 0, jlen = data.length; j < jlen; ++j) {
  							timestamp = parse(data[j], me);
  							timestamps.push(timestamp);
  							datasets[i][j] = timestamp;
  						}
  					} else {
  						timestamps.push.apply(timestamps, labels);
  						datasets[i] = labels.slice(0);
  					}
  				} else {
  					datasets[i] = [];
  				}
  			}
  
  			if (labels.length) {
  				// Sort labels **after** data have been converted
  				labels = arrayUnique(labels).sort(sorter);
  				min = Math.min(min, labels[0]);
  				max = Math.max(max, labels[labels.length - 1]);
  			}
  
  			if (timestamps.length) {
  				timestamps = arrayUnique(timestamps).sort(sorter);
  				min = Math.min(min, timestamps[0]);
  				max = Math.max(max, timestamps[timestamps.length - 1]);
  			}
  
  			min = parse(timeOpts.min, me) || min;
  			max = parse(timeOpts.max, me) || max;
  
  			// In case there is no valid min/max, set limits based on unit time option
  			min = min === MAX_INTEGER ? +moment().startOf(unit) : min;
  			max = max === MIN_INTEGER ? +moment().endOf(unit) + 1 : max;
  
  			// Make sure that max is strictly higher than min (required by the lookup table)
  			me.min = Math.min(min, max);
  			me.max = Math.max(min + 1, max);
  
  			// PRIVATE
  			me._horizontal = me.isHorizontal();
  			me._table = [];
  			me._timestamps = {
  				data: timestamps,
  				datasets: datasets,
  				labels: labels
  			};
  		},
  
  		buildTicks: function() {
  			var me = this;
  			var min = me.min;
  			var max = me.max;
  			var options = me.options;
  			var timeOpts = options.time;
  			var timestamps = [];
  			var ticks = [];
  			var i, ilen, timestamp;
  
  			switch (options.ticks.source) {
  			case 'data':
  				timestamps = me._timestamps.data;
  				break;
  			case 'labels':
  				timestamps = me._timestamps.labels;
  				break;
  			case 'auto':
  			default:
  				timestamps = generate(min, max, me.getLabelCapacity(min), options);
  			}
  
  			if (options.bounds === 'ticks' && timestamps.length) {
  				min = timestamps[0];
  				max = timestamps[timestamps.length - 1];
  			}
  
  			// Enforce limits with user min/max options
  			min = parse(timeOpts.min, me) || min;
  			max = parse(timeOpts.max, me) || max;
  
  			// Remove ticks outside the min/max range
  			for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
  				timestamp = timestamps[i];
  				if (timestamp >= min && timestamp <= max) {
  					ticks.push(timestamp);
  				}
  			}
  
  			me.min = min;
  			me.max = max;
  
  			// PRIVATE
  			me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
  			me._majorUnit = determineMajorUnit(me._unit);
  			me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
  			me._offsets = computeOffsets(me._table, ticks, min, max, options);
  			me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts);
  
  			return ticksFromTimestamps(ticks, me._majorUnit);
  		},
  
  		getLabelForIndex: function(index, datasetIndex) {
  			var me = this;
  			var data = me.chart.data;
  			var timeOpts = me.options.time;
  			var label = data.labels && index < data.labels.length ? data.labels[index] : '';
  			var value = data.datasets[datasetIndex].data[index];
  
  			if (helpers.isObject(value)) {
  				label = me.getRightValue(value);
  			}
  			if (timeOpts.tooltipFormat) {
  				return momentify(label, timeOpts).format(timeOpts.tooltipFormat);
  			}
  			if (typeof label === 'string') {
  				return label;
  			}
  
  			return momentify(label, timeOpts).format(me._labelFormat);
  		},
  
  		/**
  		 * Function to format an individual tick mark
  		 * @private
  		 */
  		tickFormatFunction: function(tick, index, ticks, formatOverride) {
  			var me = this;
  			var options = me.options;
  			var time = tick.valueOf();
  			var formats = options.time.displayFormats;
  			var minorFormat = formats[me._unit];
  			var majorUnit = me._majorUnit;
  			var majorFormat = formats[majorUnit];
  			var majorTime = tick.clone().startOf(majorUnit).valueOf();
  			var majorTickOpts = options.ticks.major;
  			var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
  			var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
  			var tickOpts = major ? majorTickOpts : options.ticks.minor;
  			var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
  
  			return formatter ? formatter(label, index, ticks) : label;
  		},
  
  		convertTicksToLabels: function(ticks) {
  			var labels = [];
  			var i, ilen;
  
  			for (i = 0, ilen = ticks.length; i < ilen; ++i) {
  				labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks));
  			}
  
  			return labels;
  		},
  
  		/**
  		 * @private
  		 */
  		getPixelForOffset: function(time) {
  			var me = this;
  			var size = me._horizontal ? me.width : me.height;
  			var start = me._horizontal ? me.left : me.top;
  			var pos = interpolate(me._table, 'time', time, 'pos');
  
  			return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
  		},
  
  		getPixelForValue: function(value, index, datasetIndex) {
  			var me = this;
  			var time = null;
  
  			if (index !== undefined && datasetIndex !== undefined) {
  				time = me._timestamps.datasets[datasetIndex][index];
  			}
  
  			if (time === null) {
  				time = parse(value, me);
  			}
  
  			if (time !== null) {
  				return me.getPixelForOffset(time);
  			}
  		},
  
  		getPixelForTick: function(index) {
  			var ticks = this.getTicks();
  			return index >= 0 && index < ticks.length ?
  				this.getPixelForOffset(ticks[index].value) :
  				null;
  		},
  
  		getValueForPixel: function(pixel) {
  			var me = this;
  			var size = me._horizontal ? me.width : me.height;
  			var start = me._horizontal ? me.left : me.top;
  			var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
  			var time = interpolate(me._table, 'pos', pos, 'time');
  
  			return moment(time);
  		},
  
  		/**
  		 * Crude approximation of what the label width might be
  		 * @private
  		 */
  		getLabelWidth: function(label) {
  			var me = this;
  			var ticksOpts = me.options.ticks;
  			var tickLabelWidth = me.ctx.measureText(label).width;
  			var angle = helpers.toRadians(ticksOpts.maxRotation);
  			var cosRotation = Math.cos(angle);
  			var sinRotation = Math.sin(angle);
  			var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize);
  
  			return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
  		},
  
  		/**
  		 * @private
  		 */
  		getLabelCapacity: function(exampleTime) {
  			var me = this;
  
  			var formatOverride = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
  
  			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride);
  			var tickLabelWidth = me.getLabelWidth(exampleLabel);
  			var innerWidth = me.isHorizontal() ? me.width : me.height;
  
  			var capacity = Math.floor(innerWidth / tickLabelWidth);
  			return capacity > 0 ? capacity : 1;
  		}
  	});
  
  	scaleService.registerScaleType('time', TimeScale, defaultConfig);
  };
  
  },{"1":1,"26":26,"33":33,"34":34,"46":46}]},{},[7])(7)
  });
  
  'use strict';
  
  var WOW;
  
  (function ($) {
  
    WOW = function WOW() {
  
      return {
  
        init: function init() {
  
          var animationName = [];
  
          var once = 1;
  
          function mdbWow() {
  
            var windowHeight = window.innerHeight;
            var scroll = window.scrollY;
  
            $('.wow').each(function () {
  
              if ($(this).css('visibility') == 'visible') {
                return;
              }
  
              if (windowHeight + scroll - 100 > getOffset(this) && scroll < getOffset(this) || windowHeight + scroll - 100 > getOffset(this) + $(this).height() && scroll < getOffset(this) + $(this).height() || windowHeight + scroll == $(document).height() && getOffset(this) + 100 > $(document).height()) {
  
                var index = $(this).index('.wow');
  
                var delay = $(this).attr('data-wow-delay');
  
                if (delay) {
  
                  delay = $(this).attr('data-wow-delay').slice(0, -1
  
                  );
                  var self = this;
  
                  var timeout = parseFloat(delay) * 1000;
  
                  $(self).addClass('animated');
                  $(self).css({
                    'visibility': 'visible'
                  });
                  $(self).css({
                    'animation-delay': delay
                  });
                  $(self).css({
                    'animation-name': animationName[index]
                  });
  
                  var removeTime = $(this).css('animation-duration').slice(0, -1) * 1000;
  
                  if ($(this).attr('data-wow-delay')) {
  
                    removeTime += $(this).attr('data-wow-delay').slice(0, -1) * 1000;
                  }
  
                  var self = this;
  
                  setTimeout(function () {
  
                    $(self).removeClass('animated');
                  }, removeTime);
                } else {
  
                  $(this).addClass('animated');
                  $(this).css({
                    'visibility': 'visible'
                  });
                  $(this).css({
                    'animation-name': animationName[index]
                  });
  
                  var removeTime = $(this).css('animation-duration').slice(0, -1) * 1000;
  
                  var self = this;
  
                  setTimeout(function () {
  
                    $(self).removeClass('animated');
                  }, removeTime);
                }
              }
            });
          }
  
          function appear() {
  
            $('.wow').each(function () {
  
              var index = $(this).index('.wow');
  
              var delay = $(this).attr('data-wow-delay');
  
              if (delay) {
  
                delay = $(this).attr('data-wow-delay').slice(0, -1);
  
                var timeout = parseFloat(delay) * 1000;
  
                $(this).addClass('animated');
                $(this).css({
                  'visibility': 'visible'
                });
                $(this).css({
                  'animation-delay': delay + 's'
                });
                $(this).css({
                  'animation-name': animationName[index]
                });
              } else {
  
                $(this).addClass('animated');
                $(this).css({
                  'visibility': 'visible'
                });
                $(this).css({
                  'animation-name': animationName[index]
                });
              }
            });
          }
  
          function hide() {
  
            var windowHeight = window.innerHeight;
            var scroll = window.scrollY;
  
            $('.wow.animated').each(function () {
  
              if (windowHeight + scroll - 100 > getOffset(this) && scroll > getOffset(this) + 100 || windowHeight + scroll - 100 < getOffset(this) && scroll < getOffset(this) + 100 || getOffset(this) + $(this).height > $(document).height() - 100) {
  
                $(this).removeClass('animated');
                $(this).css({
                  'animation-name': 'none'
                });
                $(this).css({
                  'visibility': 'hidden'
                });
              } else {
  
                var removeTime = $(this).css('animation-duration').slice(0, -1) * 1000;
  
                if ($(this).attr('data-wow-delay')) {
  
                  removeTime += $(this).attr('data-wow-delay').slice(0, -1) * 1000;
                }
  
                var self = this;
  
                setTimeout(function () {
  
                  $(self).removeClass('animated');
                }, removeTime);
              }
            });
  
            mdbWow();
  
            once--;
          }
  
          function getOffset(elem) {
  
            var box = elem.getBoundingClientRect();
  
            var body = document.body;
            var docEl = document.documentElement;
  
            var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
  
            var clientTop = docEl.clientTop || body.clientTop || 0;
  
            var top = box.top + scrollTop - clientTop;
  
            return Math.round(top);
          }
  
          $('.wow').each(function () {
  
            $(this).css({
              'visibility': 'hidden'
            });
            animationName[$(this).index('.wow')] = $(this).css('animation-name');
            $(this).css({
              'animation-name': 'none'
            });
          });
  
          $(window).scroll(function () {
  
            if (once) {
  
              hide();
            } else {
  
              mdbWow();
            }
          });
  
          appear();
        }
      };
    };
  })(jQuery);
  
  "use strict";
  
  (function ($) {
    var SCROLLING_NAVBAR_OFFSET_TOP = 50;
    $(window).on('scroll', function () {
      var $navbar = $('.navbar');
  
      if ($navbar.length) {
        if ($navbar.offset().top > SCROLLING_NAVBAR_OFFSET_TOP) {
          $('.scrolling-navbar').addClass('top-nav-collapse');
        } else {
          $('.scrolling-navbar').removeClass('top-nav-collapse');
        }
      }
    });
  })(jQuery);
  "use strict";
  
  (function ($) {
    $.fn.characterCounter = function () {
      return this.each(function () {
        var itHasLengthAttribute = $(this).attr('length') !== undefined;
  
        if (itHasLengthAttribute) {
          $(this).on('input', updateCounter);
          $(this).on('focus', updateCounter);
          $(this).on('blur', removeCounterElement);
          addCounterElement($(this));
        }
      });
    };
  
    function updateCounter() {
      var maxLength = Number($(this).attr('length'));
      var actualLength = Number($(this).val().length);
      var isValidLength = actualLength <= maxLength;
      $(this).parent().find('span[class="character-counter"]').html("".concat(actualLength, "/").concat(maxLength));
      addInputStyle(isValidLength, $(this));
    }
  
    function addCounterElement($input) {
      var $counterElement = $('<span/>').addClass('character-counter').css('float', 'right').css('font-size', '12px').css('height', 1);
      $input.parent().append($counterElement);
    }
  
    function removeCounterElement() {
      $(this).parent().find('span[class="character-counter"]').html('');
    }
  
    function addInputStyle(isValidLength, $input) {
      var inputHasInvalidClass = $input.hasClass('invalid');
  
      if (isValidLength && inputHasInvalidClass) {
        $input.removeClass('invalid');
      } else if (!isValidLength && !inputHasInvalidClass) {
        $input.removeClass('valid');
        $input.addClass('invalid');
      }
    }
  
    $(document).ready(function () {
      $('input, textarea').characterCounter();
    });
  })(jQuery);
  
  /*!
   * Waves v0.7.6
   * http://fian.my.id/Waves
   *
   * Copyright 2014-2018 Alfiana E. Sibuea and other contributors
   * Released under the MIT license
   * https://github.com/fians/Waves/blob/master/LICENSE
   */
  
  ;(function(window, factory) {
      'use strict';
  
      // AMD. Register as an anonymous module.  Wrap in function so we have access
      // to root via `this`.
      if (typeof define === 'function' && define.amd) {
          define([], function() {
              window.Waves = factory.call(window);
              return window.Waves;
          });
      }
  
      // Node. Does not work with strict CommonJS, but only CommonJS-like
      // environments that support module.exports, like Node.
      else if (typeof exports === 'object') {
          module.exports = factory.call(window);
      }
  
      // Browser globals.
      else {
          window.Waves = factory.call(window);
      }
  })(typeof global === 'object' ? global : this, function() {
      'use strict';
  
      var Waves            = Waves || {};
      var $$               = document.querySelectorAll.bind(document);
      var toString         = Object.prototype.toString;
      var isTouchAvailable = 'ontouchstart' in window;
  
  
      // Find exact position of element
      function isWindow(obj) {
          return obj !== null && obj === obj.window;
      }
  
      function getWindow(elem) {
          return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
      }
  
      function isObject(value) {
          var type = typeof value;
          return type === 'function' || type === 'object' && !!value;
      }
  
      function isDOMNode(obj) {
          return isObject(obj) && obj.nodeType > 0;
      }
  
      function getWavesElements(nodes) {
          var stringRepr = toString.call(nodes);
  
          if (stringRepr === '[object String]') {
              return $$(nodes);
          } else if (isObject(nodes) && /^\[object (Array|HTMLCollection|NodeList|Object)\]$/.test(stringRepr) && nodes.hasOwnProperty('length')) {
              return nodes;
          } else if (isDOMNode(nodes)) {
              return [nodes];
          }
  
          return [];
      }
  
      function offset(elem) {
          var docElem, win,
              box = { top: 0, left: 0 },
              doc = elem && elem.ownerDocument;
  
          docElem = doc.documentElement;
  
          if (typeof elem.getBoundingClientRect !== typeof undefined) {
              box = elem.getBoundingClientRect();
          }
          win = getWindow(doc);
          return {
              top: box.top + win.pageYOffset - docElem.clientTop,
              left: box.left + win.pageXOffset - docElem.clientLeft
          };
      }
  
      function convertStyle(styleObj) {
          var style = '';
  
          for (var prop in styleObj) {
              if (styleObj.hasOwnProperty(prop)) {
                  style += (prop + ':' + styleObj[prop] + ';');
              }
          }
  
          return style;
      }
  
      var Effect = {
  
          // Effect duration
          duration: 750,
  
          // Effect delay (check for scroll before showing effect)
          delay: 200,
  
          show: function(e, element, velocity) {
  
              // Disable right click
              if (e.button === 2) {
                  return false;
              }
  
              element = element || this;
  
              // Create ripple
              var ripple = document.createElement('div');
              ripple.className = 'waves-ripple waves-rippling';
              element.appendChild(ripple);
  
              // Get click coordinate and element width
              var pos       = offset(element);
              var relativeY = 0;
              var relativeX = 0;
              // Support for touch devices
              if('touches' in e && e.touches.length) {
                  relativeY   = (e.touches[0].pageY - pos.top);
                  relativeX   = (e.touches[0].pageX - pos.left);
              }
              //Normal case
              else {
                  relativeY   = (e.pageY - pos.top);
                  relativeX   = (e.pageX - pos.left);
              }
              // Support for synthetic events
              relativeX = relativeX >= 0 ? relativeX : 0;
              relativeY = relativeY >= 0 ? relativeY : 0;
  
              var scale     = 'scale(' + ((element.clientWidth / 100) * 3) + ')';
              var translate = 'translate(0,0)';
  
              if (velocity) {
                  translate = 'translate(' + (velocity.x) + 'px, ' + (velocity.y) + 'px)';
              }
  
              // Attach data to element
              ripple.setAttribute('data-hold', Date.now());
              ripple.setAttribute('data-x', relativeX);
              ripple.setAttribute('data-y', relativeY);
              ripple.setAttribute('data-scale', scale);
              ripple.setAttribute('data-translate', translate);
  
              // Set ripple position
              var rippleStyle = {
                  top: relativeY + 'px',
                  left: relativeX + 'px'
              };
  
              ripple.classList.add('waves-notransition');
              ripple.setAttribute('style', convertStyle(rippleStyle));
              ripple.classList.remove('waves-notransition');
  
              // Scale the ripple
              rippleStyle['-webkit-transform'] = scale + ' ' + translate;
              rippleStyle['-moz-transform'] = scale + ' ' + translate;
              rippleStyle['-ms-transform'] = scale + ' ' + translate;
              rippleStyle['-o-transform'] = scale + ' ' + translate;
              rippleStyle.transform = scale + ' ' + translate;
              rippleStyle.opacity = '1';
  
              var duration = e.type === 'mousemove' ? 2500 : Effect.duration;
              rippleStyle['-webkit-transition-duration'] = duration + 'ms';
              rippleStyle['-moz-transition-duration']    = duration + 'ms';
              rippleStyle['-o-transition-duration']      = duration + 'ms';
              rippleStyle['transition-duration']         = duration + 'ms';
  
              ripple.setAttribute('style', convertStyle(rippleStyle));
          },
  
          hide: function(e, element) {
              element = element || this;
  
              var ripples = element.getElementsByClassName('waves-rippling');
  
              for (var i = 0, len = ripples.length; i < len; i++) {
                  removeRipple(e, element, ripples[i]);
              }
  
              if (isTouchAvailable) {
                  element.removeEventListener('touchend', Effect.hide);
                  element.removeEventListener('touchcancel', Effect.hide);
              }
  
              element.removeEventListener('mouseup', Effect.hide);
              element.removeEventListener('mouseleave', Effect.hide);
          }
      };
  
      /**
       * Collection of wrapper for HTML element that only have single tag
       * like <input> and <img>
       */
      var TagWrapper = {
  
          // Wrap <input> tag so it can perform the effect
          input: function(element) {
  
              var parent = element.parentNode;
  
              // If input already have parent just pass through
              if (parent.tagName.toLowerCase() === 'span' && parent.classList.contains('waves-effect')) {
                  return;
              }
  
              // Put element class and style to the specified parent
              var wrapper       = document.createElement('span');
              wrapper.className = 'waves-input-wrapper';
              // element.className = 'waves-button-input';
  
              // Put element as child
              parent.replaceChild(wrapper, element);
              wrapper.appendChild(element);
  
          },
  
          // Wrap <img> tag so it can perform the effect
          img: function(element) {
  
              var parent = element.parentNode;
  
              // If input already have parent just pass through
              if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {
                  return;
              }
  
              // Put element as child
              var wrapper  = document.createElement('i');
              parent.replaceChild(wrapper, element);
              wrapper.appendChild(element);
  
          }
      };
  
      /**
       * Hide the effect and remove the ripple. Must be
       * a separate function to pass the JSLint...
       */
      function removeRipple(e, el, ripple) {
  
          // Check if the ripple still exist
          if (!ripple) {
              return;
          }
  
          ripple.classList.remove('waves-rippling');
  
          var relativeX = ripple.getAttribute('data-x');
          var relativeY = ripple.getAttribute('data-y');
          var scale     = ripple.getAttribute('data-scale');
          var translate = ripple.getAttribute('data-translate');
  
          // Get delay beetween mousedown and mouse leave
          var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
          var delay = 350 - diff;
  
          if (delay < 0) {
              delay = 0;
          }
  
          if (e.type === 'mousemove') {
              delay = 150;
          }
  
          // Fade out ripple after delay
          var duration = e.type === 'mousemove' ? 2500 : Effect.duration;
  
          setTimeout(function() {
  
              var style = {
                  top: relativeY + 'px',
                  left: relativeX + 'px',
                  opacity: '0',
  
                  // Duration
                  '-webkit-transition-duration': duration + 'ms',
                  '-moz-transition-duration': duration + 'ms',
                  '-o-transition-duration': duration + 'ms',
                  'transition-duration': duration + 'ms',
                  '-webkit-transform': scale + ' ' + translate,
                  '-moz-transform': scale + ' ' + translate,
                  '-ms-transform': scale + ' ' + translate,
                  '-o-transform': scale + ' ' + translate,
                  'transform': scale + ' ' + translate
              };
  
              ripple.setAttribute('style', convertStyle(style));
  
              setTimeout(function() {
                  try {
                      el.removeChild(ripple);
                  } catch (e) {
                      return false;
                  }
              }, duration);
  
          }, delay);
      }
  
  
      /**
       * Disable mousedown event for 500ms during and after touch
       */
      var TouchHandler = {
  
          /* uses an integer rather than bool so there's no issues with
           * needing to clear timeouts if another touch event occurred
           * within the 500ms. Cannot mouseup between touchstart and
           * touchend, nor in the 500ms after touchend. */
          touches: 0,
  
          allowEvent: function(e) {
  
              var allow = true;
  
              if (/^(mousedown|mousemove)$/.test(e.type) && TouchHandler.touches) {
                  allow = false;
              }
  
              return allow;
          },
          registerEvent: function(e) {
              var eType = e.type;
  
              if (eType === 'touchstart') {
  
                  TouchHandler.touches += 1; // push
  
              } else if (/^(touchend|touchcancel)$/.test(eType)) {
  
                  setTimeout(function() {
                      if (TouchHandler.touches) {
                          TouchHandler.touches -= 1; // pop after 500ms
                      }
                  }, 500);
  
              }
          }
      };
  
  
      /**
       * Delegated click handler for .waves-effect element.
       * returns null when .waves-effect element not in "click tree"
       */
      function getWavesEffectElement(e) {
  
          if (TouchHandler.allowEvent(e) === false) {
              return null;
          }
  
          var element = null;
          var target = e.target || e.srcElement;
  
          while (target.parentElement) {
              if ( (!(target instanceof SVGElement)) && target.classList.contains('waves-effect')) {
                  element = target;
                  break;
              }
              target = target.parentElement;
          }
  
          return element;
      }
  
      /**
       * Bubble the click and show effect if .waves-effect elem was found
       */
      function showEffect(e) {
  
          // Disable effect if element has "disabled" property on it
          // In some cases, the event is not triggered by the current element
          // if (e.target.getAttribute('disabled') !== null) {
          //     return;
          // }
  
          var element = getWavesEffectElement(e);
  
          if (element !== null) {
  
              // Make it sure the element has either disabled property, disabled attribute or 'disabled' class
              if (element.disabled || element.getAttribute('disabled') || element.classList.contains('disabled')) {
                  return;
              }
  
              TouchHandler.registerEvent(e);
  
              if (e.type === 'touchstart' && Effect.delay) {
  
                  var hidden = false;
  
                  var timer = setTimeout(function () {
                      timer = null;
                      Effect.show(e, element);
                  }, Effect.delay);
  
                  var hideEffect = function(hideEvent) {
  
                      // if touch hasn't moved, and effect not yet started: start effect now
                      if (timer) {
                          clearTimeout(timer);
                          timer = null;
                          Effect.show(e, element);
                      }
                      if (!hidden) {
                          hidden = true;
                          Effect.hide(hideEvent, element);
                      }
  
                      removeListeners();
                  };
  
                  var touchMove = function(moveEvent) {
                      if (timer) {
                          clearTimeout(timer);
                          timer = null;
                      }
                      hideEffect(moveEvent);
  
                      removeListeners();
                  };
  
                  element.addEventListener('touchmove', touchMove, false);
                  element.addEventListener('touchend', hideEffect, false);
                  element.addEventListener('touchcancel', hideEffect, false);
  
                  var removeListeners = function() {
                      element.removeEventListener('touchmove', touchMove);
                      element.removeEventListener('touchend', hideEffect);
                      element.removeEventListener('touchcancel', hideEffect);
                  };
              } else {
  
                  Effect.show(e, element);
  
                  if (isTouchAvailable) {
                      element.addEventListener('touchend', Effect.hide, false);
                      element.addEventListener('touchcancel', Effect.hide, false);
                  }
  
                  element.addEventListener('mouseup', Effect.hide, false);
                  element.addEventListener('mouseleave', Effect.hide, false);
              }
          }
      }
  
      Waves.init = function(options) {
          var body = document.body;
  
          options = options || {};
  
          if ('duration' in options) {
              Effect.duration = options.duration;
          }
  
          if ('delay' in options) {
              Effect.delay = options.delay;
          }
  
          if (isTouchAvailable) {
              body.addEventListener('touchstart', showEffect, false);
              body.addEventListener('touchcancel', TouchHandler.registerEvent, false);
              body.addEventListener('touchend', TouchHandler.registerEvent, false);
          }
  
          body.addEventListener('mousedown', showEffect, false);
      };
  
  
      /**
       * Attach Waves to dynamically loaded inputs, or add .waves-effect and other
       * waves classes to a set of elements. Set drag to true if the ripple mouseover
       * or skimming effect should be applied to the elements.
       */
      Waves.attach = function(elements, classes) {
  
          elements = getWavesElements(elements);
  
          if (toString.call(classes) === '[object Array]') {
              classes = classes.join(' ');
          }
  
          classes = classes ? ' ' + classes : '';
  
          var element, tagName;
  
          for (var i = 0, len = elements.length; i < len; i++) {
  
              element = elements[i];
              tagName = element.tagName.toLowerCase();
  
              if (['input', 'img'].indexOf(tagName) !== -1) {
                  TagWrapper[tagName](element);
                  element = element.parentElement;
              }
  
              if (element.className.indexOf('waves-effect') === -1) {
                  element.className += ' waves-effect' + classes;
              }
          }
      };
  
  
      /**
       * Cause a ripple to appear in an element via code.
       */
      Waves.ripple = function(elements, options) {
          elements = getWavesElements(elements);
          var elementsLen = elements.length;
  
          options          = options || {};
          options.wait     = options.wait || 0;
          options.position = options.position || null; // default = centre of element
  
  
          if (elementsLen) {
              var element, pos, off, centre = {}, i = 0;
              var mousedown = {
                  type: 'mousedown',
                  button: 1
              };
              var hideRipple = function(mouseup, element) {
                  return function() {
                      Effect.hide(mouseup, element);
                  };
              };
  
              for (; i < elementsLen; i++) {
                  element = elements[i];
                  pos = options.position || {
                      x: element.clientWidth / 2,
                      y: element.clientHeight / 2
                  };
  
                  off      = offset(element);
                  centre.x = off.left + pos.x;
                  centre.y = off.top + pos.y;
  
                  mousedown.pageX = centre.x;
                  mousedown.pageY = centre.y;
  
                  Effect.show(mousedown, element);
  
                  if (options.wait >= 0 && options.wait !== null) {
                      var mouseup = {
                          type: 'mouseup',
                          button: 1
                      };
  
                      setTimeout(hideRipple(mouseup, element), options.wait);
                  }
              }
          }
      };
  
      /**
       * Remove all ripples from an element.
       */
      Waves.calm = function(elements) {
          elements = getWavesElements(elements);
          var mouseup = {
              type: 'mouseup',
              button: 1
          };
  
          for (var i = 0, len = elements.length; i < len; i++) {
              Effect.hide(mouseup, elements[i]);
          }
      };
  
      /**
       * Deprecated API fallback
       */
      Waves.displayEffect = function(options) {
          console.error('Waves.displayEffect() has been deprecated and will be removed in future version. Please use Waves.init() to initialize Waves effect');
          Waves.init(options);
      };
  
      return Waves;
  });
  
  //Initialization
  Waves.attach('.btn:not(.btn-flat), .btn-floating', ['waves-light']);
  Waves.attach('.btn-flat', ['waves-effect']);
  Waves.attach('.chip', ['waves-effect']);
  Waves.attach('.view a .mask', ['waves-light']);
  Waves.attach('.waves-light', ['waves-light']);
  Waves.attach('.navbar-nav a:not(.navbar-brand), .nav-icons li a, .nav-tabs .nav-item:not(.dropdown)', ['waves-light']);
  Waves.attach('.pager li a', ['waves-light']);
  Waves.attach('.pagination .page-item .page-link', ['waves-effect']);
  Waves.init();
  "use strict";
  
  var _this = void 0;
  
  (function ($) {
    var inputSelector = "".concat(['text', 'password', 'email', 'url', 'tel', 'number', 'search', 'search-md'].map(function (selector) {
      return "input[type=".concat(selector, "]");
    }).join(', '), ", textarea");
    var textAreaSelector = '.materialize-textarea';
  
    var updateTextFields = function updateTextFields($input) {
      var $labelAndIcon = $input.siblings('label, i');
      var hasValue = $input.val().length;
      var hasPlaceholder = $input.attr('placeholder');
      var addOrRemove = "".concat(hasValue || hasPlaceholder ? 'add' : 'remove', "Class");
      $labelAndIcon[addOrRemove]('active');
    };
  
    var validateField = function validateField($input) {
      if ($input.hasClass('validate')) {
        var value = $input.val();
        var noValue = !value.length;
        var isValid = !$input[0].validity.badInput;
  
        if (noValue && isValid) {
          $input.removeClass('valid').removeClass('invalid');
        } else {
          var valid = $input.is(':valid');
          var length = Number($input.attr('length')) || 0;
  
          if (valid && (!length || length > value.length)) {
            $input.removeClass('invalid').addClass('valid');
          } else {
            $input.removeClass('valid').addClass('invalid');
          }
        }
      }
    };
  
    var textAreaAutoResize = function textAreaAutoResize() {
      var $textarea = $(_this);
  
      if ($textarea.val().length) {
        var $hiddenDiv = $('.hiddendiv');
        var fontFamily = $textarea.css('font-family');
        var fontSize = $textarea.css('font-size');
  
        if (fontSize) {
          $hiddenDiv.css('font-size', fontSize);
        }
  
        if (fontFamily) {
          $hiddenDiv.css('font-family', fontFamily);
        }
  
        if ($textarea.attr('wrap') === 'off') {
          $hiddenDiv.css('overflow-wrap', 'normal').css('white-space', 'pre');
        }
  
        $hiddenDiv.text("".concat($textarea.val(), "\n"));
        var content = $hiddenDiv.html().replace(/\n/g, '<br>');
        $hiddenDiv.html(content); // When textarea is hidden, width goes crazy.
        // Approximate with half of window size
  
        $hiddenDiv.css('width', $textarea.is(':visible') ? $textarea.width() : $(window).width() / 2);
        $textarea.css('height', $hiddenDiv.height());
      }
    };
  
    $(inputSelector).each(function (index, input) {
      var $this = $(input);
      var $labelAndIcon = $this.siblings('label, i');
      updateTextFields($this);
      var isValid = input.validity.badInput;
  
      if (isValid) {
        $labelAndIcon.addClass('active');
      }
    });
    $(document).on('focus', inputSelector, function (e) {
      $(e.target).siblings('label, i').addClass('active');
    });
    $(document).on('blur', inputSelector, function (e) {
      var $this = $(e.target);
      var noValue = !$this.val();
      var invalid = !e.target.validity.badInput;
      var noPlaceholder = $this.attr('placeholder') === undefined;
  
      if (noValue && invalid && noPlaceholder) {
        $this.siblings('label, i').removeClass('active');
      }
  
      validateField($this);
    });
    $(document).on('change', inputSelector, function (e) {
      var $this = $(e.target);
      updateTextFields($this);
      validateField($this);
    });
    $('input[autofocus]').siblings('label, i').addClass('active');
    $(document).on('reset', function (e) {
      var $formReset = $(e.target);
  
      if ($formReset.is('form')) {
        var $formInputs = $formReset.find(inputSelector);
        $formInputs.removeClass('valid').removeClass('invalid').each(function (index, input) {
          var $this = $(input);
          var noDefaultValue = !$this.val();
          var noPlaceholder = !$this.attr('placeholder');
  
          if (noDefaultValue && noPlaceholder) {
            $this.siblings('label, i').removeClass('active');
          }
        });
        $formReset.find('select.initialized').each(function (index, select) {
          var $select = $(select);
          var $visibleInput = $select.siblings('input.select-dropdown');
          var defaultValue = $select.children('[selected]').val();
          $select.val(defaultValue);
          $visibleInput.val(defaultValue);
        });
      }
    });
  
    function init() {
      var $text = $('.md-textarea-auto');
  
      if ($text.length) {
        var observe;
  
        if (window.attachEvent) {
          observe = function observe(element, event, handler) {
            element.attachEvent("on".concat(event), handler);
          };
        } else {
          observe = function observe(element, event, handler) {
            element.addEventListener(event, handler, false);
          };
        }
  
        $text.each(function () {
          var self = this;
  
          function resize() {
            self.style.height = 'auto';
            self.style.height = "".concat(self.scrollHeight, "px");
          }
  
          function delayedResize() {
            window.setTimeout(resize, 0);
          }
  
          observe(self, 'change', resize);
          observe(self, 'cut', delayedResize);
          observe(self, 'paste', delayedResize);
          observe(self, 'drop', delayedResize);
          observe(self, 'keydown', delayedResize);
          resize();
        });
      }
    }
  
    init();
    var $body = $('body');
  
    if (!$('.hiddendiv').first().length) {
      var $hiddenDiv = $('<div class="hiddendiv common"></div>');
      $body.append($hiddenDiv);
    }
  
    $(textAreaSelector).each(textAreaAutoResize);
    $body.on('keyup keydown', textAreaSelector, textAreaAutoResize);
  })(jQuery);
  "use strict";
  
  (function ($) {
    $(document).on('click.card', '.card', function (e) {
      var $reveal = $(this).find('.card-reveal');
  
      if ($reveal.length) {
        var $clicked = $(e.target);
        var isTitle = $clicked.is('.card-reveal .card-title');
        var isTitleIcon = $clicked.is('.card-reveal .card-title i');
        var isActivator = $clicked.is('.card .activator');
        var isActivatorIcon = $clicked.is('.card .activator i');
  
        if (isTitle || isTitleIcon) {
          // down
          $(this).find('.card-reveal').velocity({
            translateY: 0
          }, {
            duration: 225,
            queue: false,
            easing: 'easeInOutQuad',
            complete: function complete() {
              $(this).css({
                display: 'none'
              });
            }
          });
        } else if (isActivator || isActivatorIcon) {
          // up
          $(this).find('.card-reveal').css({
            display: 'block'
          }).velocity('stop', false).velocity({
            translateY: '-100%'
          }, {
            duration: 300,
            queue: false,
            easing: 'easeInOutQuad'
          });
        }
      }
    });
    $('.rotate-btn').on('click', function () {
      var cardId = $(this).attr('data-card');
      $("#".concat(cardId)).toggleClass('flipped');
    });
    $(window).on('load', function () {
      var frontHeight = $('.front').outerHeight();
      var backHeight = $('.back').outerHeight();
  
      if (frontHeight > backHeight) {
        $('.card-wrapper, .back').height(frontHeight);
      } else if (frontHeight > backHeight) {
        $('.card-wrapper, .front').height(backHeight);
      } else {
        $('.card-wrapper').height(backHeight);
      }
    });
    $('.card-share > a').on('click', function (e) {
      e.preventDefault();
      $(this).toggleClass('share-expanded').parent().find('div').toggleClass('social-reveal-active');
    });
  })(jQuery);
  
  $('.map-card').click(function () {
    $('.card-body').toggleClass('closed');
  });
  /*
   * Toastr
   * Copyright 2012-2015
   * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
   * All Rights Reserved.
   * Use, reproduction, distribution, and modification of this code is subject to the terms and
   * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
   *
   * ARIA Support: Greta Krafsig
   *
   * Project: https://github.com/CodeSeven/toastr
   */
  /* global define */
  ; (function (define) {
      define(['jquery'], function ($) {
          return (function () {
              var $container;
              var listener;
              var toastId = 0;
              var toastType = {
                  error: 'error',
                  info: 'info',
                  success: 'success',
                  warning: 'warning'
              };
  
              var toastr = {
                  clear: clear,
                  remove: remove,
                  error: error,
                  getContainer: getContainer,
                  info: info,
                  options: {},
                  subscribe: subscribe,
                  success: success,
                  version: '2.1.1',
                  warning: warning
              };
  
              var previousToast;
  
              return toastr;
  
              ////////////////
  
              function error(message, title, optionsOverride) {
                  return notify({
                      type: toastType.error,
                      iconClass: getOptions().iconClasses.error,
                      message: message,
                      optionsOverride: optionsOverride,
                      title: title
                  });
              }
  
              function getContainer(options, create) {
                  if (!options) { options = getOptions(); }
                  $container = $('#' + options.containerId);
                  if ($container.length) {
                      return $container;
                  }
                  if (create) {
                      $container = createContainer(options);
                  }
                  return $container;
              }
  
              function info(message, title, optionsOverride) {
                  return notify({
                      type: toastType.info,
                      iconClass: getOptions().iconClasses.info,
                      message: message,
                      optionsOverride: optionsOverride,
                      title: title
                  });
              }
  
              function subscribe(callback) {
                  listener = callback;
              }
  
              function success(message, title, optionsOverride) {
                  return notify({
                      type: toastType.success,
                      iconClass: getOptions().iconClasses.success,
                      message: message,
                      optionsOverride: optionsOverride,
                      title: title
                  });
              }
  
              function warning(message, title, optionsOverride) {
                  return notify({
                      type: toastType.warning,
                      iconClass: getOptions().iconClasses.warning,
                      message: message,
                      optionsOverride: optionsOverride,
                      title: title
                  });
              }
  
              function clear($toastElement, clearOptions) {
                  var options = getOptions();
                  if (!$container) { getContainer(options); }
                  if (!clearToast($toastElement, options, clearOptions)) {
                      clearContainer(options);
                  }
              }
  
              function remove($toastElement) {
                  var options = getOptions();
                  if (!$container) { getContainer(options); }
                  if ($toastElement && $(':focus', $toastElement).length === 0) {
                      removeToast($toastElement);
                      return;
                  }
                  if ($container.children().length) {
                      $container.remove();
                  }
              }
  
              // internal functions
  
              function clearContainer (options) {
                  var toastsToClear = $container.children();
                  for (var i = toastsToClear.length - 1; i >= 0; i--) {
                      clearToast($(toastsToClear[i]), options);
                  }
              }
  
              function clearToast ($toastElement, options, clearOptions) {
                  var force = clearOptions && clearOptions.force ? clearOptions.force : false;
                  if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
                      $toastElement[options.hideMethod]({
                          duration: options.hideDuration,
                          easing: options.hideEasing,
                          complete: function () { removeToast($toastElement); }
                      });
                      return true;
                  }
                  return false;
              }
  
              function createContainer(options) {
                  $container = $('<div/>')
                      .attr('id', options.containerId)
                      .addClass(options.positionClass)
                      .attr('aria-live', 'polite')
                      .attr('role', 'alert');
  
                  $container.appendTo($(options.target));
                  return $container;
              }
  
              function getDefaults() {
                  return {
                      tapToDismiss: true,
                      toastClass: 'md-toast',
                      containerId: 'toast-container',
                      debug: false,
  
                      showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
                      showDuration: 300,
                      showEasing: 'swing', //swing and linear are built into jQuery
                      onShown: undefined,
                      hideMethod: 'fadeOut',
                      hideDuration: 1000,
                      hideEasing: 'swing',
                      onHidden: undefined,
  
                      extendedTimeOut: 1000,
                      iconClasses: {
                          error: 'md-toast-error',
                          info: 'md-toast-info',
                          success: 'md-toast-success',
                          warning: 'md-toast-warning'
                      },
                      iconClass: 'md-toast-info',
                      positionClass: 'md-toast-top-right',
                      timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
                      titleClass: 'md-toast-title',
                      messageClass: 'md-toast-message',
                      target: 'body',
                      closeHtml: '<button type="button">&times;</button>',
                      newestOnTop: true,
                      preventDuplicates: false,
                      progressBar: false
                  };
              }
  
              function publish(args) {
                  if (!listener) { return; }
                  listener(args);
              }
  
              function notify(map) {
                  var options = getOptions();
                  var iconClass = map.iconClass || options.iconClass;
  
                  if (typeof (map.optionsOverride) !== 'undefined') {
                      options = $.extend(options, map.optionsOverride);
                      iconClass = map.optionsOverride.iconClass || iconClass;
                  }
  
                  if (shouldExit(options, map)) { return; }
  
                  toastId++;
  
                  $container = getContainer(options, true);
  
                  var intervalId = null;
                  var $toastElement = $('<div/>');
                  var $titleElement = $('<div/>');
                  var $messageElement = $('<div/>');
                  var $progressElement = $('<div/>');
                  var $closeElement = $(options.closeHtml);
                  var progressBar = {
                      intervalId: null,
                      hideEta: null,
                      maxHideTime: null
                  };
                  var response = {
                      toastId: toastId,
                      state: 'visible',
                      startTime: new Date(),
                      options: options,
                      map: map
                  };
  
                  personalizeToast();
  
                  displayToast();
  
                  handleEvents();
  
                  publish(response);
  
                  if (options.debug && console) {
                      console.log(response);
                  }
  
                  return $toastElement;
  
                  function personalizeToast() {
                      setIcon();
                      setTitle();
                      setMessage();
                      setCloseButton();
                      setProgressBar();
                      setSequence();
                  }
  
                  function handleEvents() {
                      $toastElement.hover(stickAround, delayedHideToast);
                      if (!options.onclick && options.tapToDismiss) {
                          $toastElement.click(hideToast);
                      }
  
                      if (options.closeButton && $closeElement) {
                          $closeElement.click(function (event) {
                              if (event.stopPropagation) {
                                  event.stopPropagation();
                              } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
                                  event.cancelBubble = true;
                              }
                              hideToast(true);
                          });
                      }
  
                      if (options.onclick) {
                          $toastElement.click(function () {
                              options.onclick();
                              hideToast();
                          });
                      }
                  }
  
                  function displayToast() {
                      $toastElement.hide();
  
                      $toastElement[options.showMethod](
                          {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
                      );
  
                      if (options.timeOut > 0) {
                          intervalId = setTimeout(hideToast, options.timeOut);
                          progressBar.maxHideTime = parseFloat(options.timeOut);
                          progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
                          if (options.progressBar) {
                              progressBar.intervalId = setInterval(updateProgress, 10);
                          }
                      }
                  }
  
                  function setIcon() {
                      if (map.iconClass) {
                          $toastElement.addClass(options.toastClass).addClass(iconClass);
                      }
                  }
  
                  function setSequence() {
                      if (options.newestOnTop) {
                          $container.prepend($toastElement);
                      } else {
                          $container.append($toastElement);
                      }
                  }
  
                  function setTitle() {
                      if (map.title) {
                          $titleElement.append(map.title).addClass(options.titleClass);
                          $toastElement.append($titleElement);
                      }
                  }
  
                  function setMessage() {
                      if (map.message) {
                          $messageElement.append(map.message).addClass(options.messageClass);
                          $toastElement.append($messageElement);
                      }
                  }
  
                  function setCloseButton() {
                      if (options.closeButton) {
                          $closeElement.addClass('md-toast-close-button').attr('role', 'button');
                          $toastElement.prepend($closeElement);
                      }
                  }
  
                  function setProgressBar() {
                      if (options.progressBar) {
                          $progressElement.addClass('md-toast-progress');
                          $toastElement.prepend($progressElement);
                      }
                  }
  
                  function shouldExit(options, map) {
                      if (options.preventDuplicates) {
                          if (map.message === previousToast) {
                              return true;
                          } else {
                              previousToast = map.message;
                          }
                      }
                      return false;
                  }
  
                  function hideToast(override) {
                      if ($(':focus', $toastElement).length && !override) {
                          return;
                      }
                      clearTimeout(progressBar.intervalId);
                      return $toastElement[options.hideMethod]({
                          duration: options.hideDuration,
                          easing: options.hideEasing,
                          complete: function () {
                              removeToast($toastElement);
                              if (options.onHidden && response.state !== 'hidden') {
                                  options.onHidden();
                              }
                              response.state = 'hidden';
                              response.endTime = new Date();
                              publish(response);
                          }
                      });
                  }
  
                  function delayedHideToast() {
                      if (options.timeOut > 0 || options.extendedTimeOut > 0) {
                          intervalId = setTimeout(hideToast, options.extendedTimeOut);
                          progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
                          progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
                      }
                  }
  
                  function stickAround() {
                      clearTimeout(intervalId);
                      progressBar.hideEta = 0;
                      $toastElement.stop(true, true)[options.showMethod](
                          {duration: options.showDuration, easing: options.showEasing}
                      );
                  }
  
                  function updateProgress() {
                      var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
                      $progressElement.width(percentage + '%');
                  }
              }
  
              function getOptions() {
                  return $.extend({}, getDefaults(), toastr.options);
              }
  
              function removeToast($toastElement) {
                  if (!$container) { $container = getContainer(); }
                  if ($toastElement.is(':visible')) {
                      return;
                  }
                  $toastElement.remove();
                  $toastElement = null;
                  if ($container.children().length === 0) {
                      $container.remove();
                      previousToast = undefined;
                  }
              }
  
          })();
      });
  }(typeof define === 'function' && define.amd ? define : function (deps, factory) {
      if (typeof module !== 'undefined' && module.exports) { //Node
          module.exports = factory(require('jquery'));
      } else {
          window['toastr'] = factory(window['jQuery']);
      }
  }));
  
  "use strict";
  
  var SMOOTH_SCROLL_DURATION = 700;
  $('.smooth-scroll').on('click', 'a', function () {
    var elAttr = $(this).attr('href');
  
    if (typeof elAttr !== typeof undefined && elAttr.indexOf('#') === 0) {
      var offset = $(this).attr('data-offset') ? $(this).attr('data-offset') : 0;
      var setHash = $(this).parentsUntil('.smooth-scroll').last().parent().attr('data-allow-hashes');
      $('body,html').animate({
        scrollTop: $(elAttr).offset().top - offset
      }, SMOOTH_SCROLL_DURATION);
  
      if (typeof setHash !== typeof undefined && setHash !== false) {
        history.replaceState(null, null, elAttr);
      }
  
      return false;
    }
  });
  "use strict";
  
  (function ($) {
    $.fn.scrollTo = function (elem) {
      $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top);
      return this;
    };
  
    $.fn.dropdown = function (option) {
      this.each(function () {
        var origin = $(this);
        var options = $.extend({}, $.fn.dropdown.defaults, option);
        var isFocused = false; // Dropdown menu
  
        var activates = $("#".concat(origin.attr('data-activates')));
  
        function updateOptions() {
          if (origin.data('induration') !== undefined) {
            options.inDuration = origin.data('inDuration');
          }
  
          if (origin.data('outduration') !== undefined) {
            options.outDuration = origin.data('outDuration');
          }
  
          if (origin.data('constrainwidth') !== undefined) {
            options.constrain_width = origin.data('constrainwidth');
          }
  
          if (origin.data('hover') !== undefined) {
            options.hover = origin.data('hover');
          }
  
          if (origin.data('gutter') !== undefined) {
            options.gutter = origin.data('gutter');
          }
  
          if (origin.data('beloworigin') !== undefined) {
            options.belowOrigin = origin.data('beloworigin');
          }
  
          if (origin.data('alignment') !== undefined) {
            options.alignment = origin.data('alignment');
          }
        }
  
        updateOptions(); // Attach dropdown to its activator
  
        origin.after(activates);
        /*
          Helper function to position and resize dropdown.
          Used in hover and click handler.
        */
  
        function placeDropdown(eventType) {
          // Check for simultaneous focus and click events.
          if (eventType === 'focus') {
            isFocused = true;
          } // Check html data attributes
  
  
          updateOptions(); // Set Dropdown state
  
          activates.addClass('active');
          origin.addClass('active'); // Constrain width
  
          if (options.constrain_width === true) {
            activates.css('width', origin.outerWidth());
          } else {
            activates.css('white-space', 'nowrap');
          } // Offscreen detection
  
  
          var windowHeight = window.innerHeight;
          var originHeight = origin.innerHeight();
          var offsetLeft = origin.offset().left;
          var offsetTop = origin.offset().top - $(window).scrollTop();
          var currAlignment = options.alignment;
          var gutterSpacing = 0;
          var leftPosition = 0; // Below Origin
  
          var verticalOffset = 0;
  
          if (options.belowOrigin === true) {
            verticalOffset = originHeight;
          } // Check for scrolling positioned container.
  
  
          var scrollOffset = 0;
          var wrapper = origin.parent();
  
          if (!wrapper.is('body') && wrapper[0].scrollHeight > wrapper[0].clientHeight) {
            scrollOffset = wrapper[0].scrollTop;
          }
  
          if (offsetLeft + activates.innerWidth() > $(window).width()) {
            // Dropdown goes past screen on right, force right alignment
            currAlignment = 'right';
          } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) {
            // Dropdown goes past screen on left, force left alignment
            currAlignment = 'left';
          } // Vertical bottom offscreen detection
  
  
          if (offsetTop + activates.innerHeight() > windowHeight) {
            // If going upwards still goes offscreen, just crop height of dropdown.
            if (offsetTop + originHeight - activates.innerHeight() < 0) {
              var adjustedHeight = windowHeight - offsetTop - verticalOffset;
              activates.css('max-height', adjustedHeight);
            } else {
              // Flow upwards.
              if (!verticalOffset) {
                verticalOffset += originHeight;
              }
  
              verticalOffset -= activates.innerHeight();
            }
          } // Handle edge alignment
  
  
          if (currAlignment === 'left') {
            gutterSpacing = options.gutter;
            leftPosition = origin.position().left + gutterSpacing;
          } else if (currAlignment === 'right') {
            var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth();
            gutterSpacing = -options.gutter;
            leftPosition = offsetRight + gutterSpacing;
          } // Position dropdown
  
  
          activates.css({
            position: 'absolute',
            top: origin.position().top + verticalOffset + scrollOffset,
            left: leftPosition
          }); // Show dropdown
  
          activates.stop(true, true).css('opacity', 0).slideDown({
            queue: false,
            duration: options.inDuration,
            easing: 'easeOutCubic',
            complete: function complete() {
              $(this).css('height', '');
            }
          }).animate({
            opacity: 1,
            scrollTop: 0
          }, {
            queue: false,
            duration: options.inDuration,
            easing: 'easeOutSine'
          });
        }
  
        function hideDropdown() {
          // Check for simultaneous focus and click events.
          isFocused = false;
          activates.fadeOut(options.outDuration);
          activates.removeClass('active');
          origin.removeClass('active');
          setTimeout(function () {
            activates.css('max-height', '');
          }, options.outDuration);
        } // Hover
  
  
        if (options.hover) {
          var open = false;
          origin.unbind("click.".concat(origin.attr('id'))); // Hover handler to show dropdown
  
          origin.on('mouseenter', function () {
            // Mouse over
            if (open === false) {
              placeDropdown();
              open = true;
            }
          });
          origin.on('mouseleave', function (e) {
            // If hover on origin then to something other than dropdown content, then close
            var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element
  
            if (!$(toEl).closest('.dropdown-content').is(activates)) {
              activates.stop(true, true);
              hideDropdown();
              open = false;
            }
          });
          activates.on('mouseleave', function (e) {
            // Mouse out
            var toEl = e.toElement || e.relatedTarget;
  
            if (!$(toEl).closest('.dropdown-button').is(origin)) {
              activates.stop(true, true);
              hideDropdown();
              open = false;
            }
          }); // Click
        } else {
          // Click handler to show dropdown
          origin.unbind("click.".concat(origin.attr('id')));
          origin.bind("click.".concat(origin.attr('id')), function (e) {
            if (!isFocused) {
              if (origin[0] === e.currentTarget && !origin.hasClass('active') && $(e.target).closest('.dropdown-content').length === 0) {
                e.preventDefault(); // Prevents button click from moving window
  
                placeDropdown('click');
              } else if (origin.hasClass('active')) {
                // If origin is clicked and menu is open, close menu
                hideDropdown();
                $(document).unbind("click.".concat(activates.attr('id'), " touchstart.").concat(activates.attr('id')));
              } // If menu open, add click close handler to document
  
  
              if (activates.hasClass('active')) {
                $(document).bind("click.".concat(activates.attr('id'), " touchstart.").concat(activates.attr('id')), function (e) {
                  if (!activates.is(e.target) && !origin.is(e.target) && !origin.find(e.target).length) {
                    hideDropdown();
                    $(document).unbind("click.".concat(activates.attr('id'), " touchstart.").concat(activates.attr('id')));
                  }
                });
              }
            }
          });
        }
  
        origin.on('open', function (e, eventType) {
          placeDropdown(eventType);
        });
        origin.on('close', hideDropdown);
      });
    };
  
    $.fn.dropdown.defaults = {
      inDuration: 300,
      outDuration: 225,
      constrain_width: true,
      hover: false,
      gutter: 0,
      belowOrigin: false,
      alignment: 'left'
    };
    $('.dropdown-button').dropdown();
  
    $.fn.mdbDropSearch = function (options) {
      var $mdbInput = $(this).find('input');
      this.filter(function (value, index) {
        $(index).on('keyup', function () {
          var $linksInDropMenu = $mdbInput.closest('div[id]').find('a, li');
  
          for (var i = 0; i < $linksInDropMenu.length; i++) {
            if ($linksInDropMenu.eq(i).html().toUpperCase().indexOf($mdbInput.val().toUpperCase()) > -1) {
              $linksInDropMenu.eq(i).css({
                display: ''
              });
            } else {
              $linksInDropMenu.eq(i).css({
                display: 'none'
              });
            }
          }
        });
      });
      var settings = $.extend({
        color: '#000',
        backgroundColor: '',
        fontSize: '.9rem',
        fontWeight: '400',
        borderRadius: '',
        borderColor: ''
      }, options);
      return this.css({
        color: settings.color,
        backgroundColor: settings.backgroundColor,
        fontSize: settings.fontSize,
        fontWeight: settings.fontWeight,
        borderRadius: settings.borderRadius,
        border: settings.border,
        margin: settings.margin
      });
    };
  })(jQuery);
  
  var dropdownSelectors = $('.dropdown, .dropup'); // Custom function to read dropdown data
  
  function dropdownEffectData(target) {
    // TODO - page level global?
    var effectInDefault = 'fadeIn';
    var effectOutDefault = 'fadeOut';
    var dropdown = $(target);
    var dropdownMenu = $('.dropdown-menu', target);
    var parentUl = dropdown.parents('ul.nav'); // If parent is ul.nav allow global effect settings
  
    if (parentUl.height > 0) {
      effectInDefault = parentUl.data('dropdown-in') || null;
      effectOutDefault = parentUl.data('dropdown-out') || null;
    }
  
    return {
      target: target,
      dropdown: dropdown,
      dropdownMenu: dropdownMenu,
      effectIn: dropdownMenu.data('dropdown-in') || effectInDefault,
      effectOut: dropdownMenu.data('dropdown-out') || effectOutDefault
    };
  } // Custom function to start effect (in or out)
  
  
  function dropdownEffectStart(data, effectToStart) {
    if (effectToStart) {
      data.dropdown.addClass('dropdown-animating');
      data.dropdownMenu.addClass(['animated', effectToStart].join(' '));
    }
  } // Custom function to read when animation is over
  
  
  function dropdownEffectEnd(data, callbackFunc) {
    var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
    data.dropdown.one(animationEnd, function () {
      data.dropdown.removeClass('dropdown-animating');
      data.dropdownMenu.removeClass(['animated', data.effectIn, data.effectOut].join(' ')); // Custom callback option, used to remove open class in out effect
  
      if (typeof callbackFunc === 'function') {
        callbackFunc();
      }
    });
  } // Bootstrap API hooks
  
  
  dropdownSelectors.on({
    'show.bs.dropdown': function showBsDropdown() {
      // On show, start in effect
      var dropdown = dropdownEffectData(this);
      dropdownEffectStart(dropdown, dropdown.effectIn);
    },
    'shown.bs.dropdown': function shownBsDropdown() {
      // On shown, remove in effect once complete
      var dropdown = dropdownEffectData(this);
  
      if (dropdown.effectIn && dropdown.effectOut) {
        dropdownEffectEnd(dropdown);
      }
    },
    'hide.bs.dropdown': function hideBsDropdown(e) {
      // On hide, start out effect
      var dropdown = dropdownEffectData(this);
  
      if (dropdown.effectOut) {
        e.preventDefault();
        dropdownEffectStart(dropdown, dropdown.effectOut);
        dropdownEffectEnd(dropdown, function () {
          dropdown.dropdown.removeClass('show');
          dropdown.dropdownMenu.removeClass('show');
        });
      }
    }
  });
  "use strict";
  
  (function ($) {
    var _this = this;
  
    $(document).ready(function () {
      $(document).on('mouseenter', '.fixed-action-btn', function () {
        var $this = $(this);
        openFABMenu($this);
      });
      $(document).on('mouseleave', '.fixed-action-btn', function () {
        var $this = $(this);
        closeFABMenu($this);
      });
      $(document).on('click', '.fixed-action-btn > a', function () {
        var $this = $(this);
        var $menu = $this.parent();
        $menu.hasClass('active') ? openFABMenu($menu) : closeFABMenu($menu);
  
        if ($menu.hasClass('active')) {
          closeFABMenu($menu);
        } else {
          openFABMenu($menu);
        }
      });
    });
    $.fn.extend({
      openFAB: function openFAB() {
        openFABMenu($(this));
      },
      closeFAB: function closeFAB() {
        closeFABMenu($(this));
      }
    });
  
    var openFABMenu = function openFABMenu(btn) {
      var fab = btn;
  
      if (!fab.hasClass('active')) {
        fab.addClass('active');
        var btnList = document.querySelectorAll('ul .btn-floating');
        btnList.forEach(function (el) {
          el.classList.add('shown');
        });
      }
    };
  
    var closeFABMenu = function closeFABMenu(btn) {
      var fab = btn;
      fab.removeClass('active');
      var btnList = document.querySelectorAll('ul .btn-floating');
      btnList.forEach(function (el) {
        el.classList.remove('shown');
      });
    };
  
    $('.fixed-action-btn:not(.smooth-scroll) > .btn-floating').on('click', function (e) {
      if (!$(_this).hasClass('smooth-scroll')) {
        e.preventDefault();
        toggleFABMenu($('.fixed-action-btn'));
        return false;
      }
    });
  
    function toggleFABMenu(btn) {
      var elem = btn;
  
      if (elem.hasClass('active')) {
        closeFABMenu(elem);
      } else {
        openFABMenu(elem);
      }
    }
  })(jQuery);
  "use strict";
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
  
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  
  (function ($) {
    var MENU_WIDTH = 240;
    var SN_BREAKPOINT = 1440;
    var MENU_WIDTH_HALF = 2;
    var MENU_LEFT_MIN_BORDER = 0.3;
    var MENU_LEFT_MAX_BORDER = -0.5;
    var MENU_RIGHT_MIN_BORDER = -0.3;
    var MENU_RIGHT_MAX_BORDER = 0.5;
    var MENU_VELOCITY_OFFSET = 10;
    var MENU_TIME_DURATION_OPEN = 300;
    var MENU_TIME_DURATION_CLOSE = 200;
    var MENU_TIME_DURATION_OVERLAY_OPEN = 50;
    var MENU_TIME_DURATION_OVERLAY_CLOSE = 200;
    var MENU_EASING_OPEN = 'easeOutQuad';
    var MENU_EASING_CLOSE = 'easeOutCubic';
    var SHOW_OVERLAY = true;
    var SHOW_CLOSE_BUTTON = false;
  
    var SideNav =
    /*#__PURE__*/
    function () {
      function SideNav(element, options) {
        _classCallCheck(this, SideNav);
  
        this.defaults = {
          MENU_WIDTH: MENU_WIDTH,
          edge: 'left',
          closeOnClick: false,
          breakpoint: SN_BREAKPOINT,
          timeDurationOpen: MENU_TIME_DURATION_OPEN,
          timeDurationClose: MENU_TIME_DURATION_CLOSE,
          timeDurationOverlayOpen: MENU_TIME_DURATION_OVERLAY_OPEN,
          timeDurationOverlayClose: MENU_TIME_DURATION_OVERLAY_CLOSE,
          easingOpen: MENU_EASING_OPEN,
          easingClose: MENU_EASING_CLOSE,
          showOverlay: SHOW_OVERLAY,
          showCloseButton: SHOW_CLOSE_BUTTON
        };
        this.$element = element;
        this.$elementCloned = element.clone().css({
          display: 'inline-block',
          lineHeight: '24px'
        });
        this.options = this.assignOptions(options);
        this.menuOut = false;
        this.lastTouchVelocity = {
          x: {
            startPosition: 0,
            startTime: 0,
            endPosition: 0,
            endTime: 0
          }
        };
        this.$body = $('body');
        this.$menu = $("#".concat(this.$element.attr('data-activates')));
        this.$sidenavOverlay = $('#sidenav-overlay');
        this.$dragTarget = $('<div class="drag-target"></div>');
        this.$body.append(this.$dragTarget);
        this.init();
      }
  
      _createClass(SideNav, [{
        key: "init",
        value: function init() {
          this.setMenuWidth();
          this.setMenuTranslation();
          this.closeOnClick();
          this.openOnClick();
          this.bindTouchEvents();
          this.showCloseButton();
          this.inputOnClick();
        }
      }, {
        key: "bindTouchEvents",
        value: function bindTouchEvents() {
          var _this = this;
  
          this.$dragTarget.on('click', function () {
            return _this.removeMenu();
          });
          this.$elementCloned.on('click', function () {
            return _this.removeMenu();
          });
          this.$dragTarget.on('touchstart', function (e) {
            _this.lastTouchVelocity.x.startPosition = e.touches[0].clientX;
            _this.lastTouchVelocity.x.startTime = Date.now();
          });
          this.$dragTarget.on('touchmove', this.touchmoveEventHandler.bind(this));
          this.$dragTarget.on('touchend', this.touchendEventHandler.bind(this));
        }
      }, {
        key: "touchmoveEventHandler",
        value: function touchmoveEventHandler(e) {
          if (e.type !== 'touchmove') {
            return;
          }
  
          var touch = e.touches[0];
          var touchX = touch.clientX; // calculate velocity every 20ms
  
          if (Date.now() - this.lastTouchVelocity.x.startTime > 20) {
            this.lastTouchVelocity.x.startPosition = touch.clientX;
            this.lastTouchVelocity.x.startTime = Date.now();
          }
  
          this.disableScrolling();
          var overlayExists = this.$sidenavOverlay.length !== 0;
  
          if (!overlayExists) {
            this.buildSidenavOverlay();
          } // Keep within boundaries
  
  
          if (this.options.edge === 'left') {
            if (touchX > this.options.MENU_WIDTH) {
              touchX = this.options.MENU_WIDTH;
            } else if (touchX < 0) {
              touchX = 0;
            }
          }
  
          this.translateSidenavX(touchX);
          this.updateOverlayOpacity(touchX);
        }
      }, {
        key: "panEventHandler",
        value: function panEventHandler(e) {
          if (e.gesture.pointerType !== 'touch') {
            return;
          }
  
          var touchX = e.gesture.center.x;
          this.disableScrolling();
          var overlayExists = this.$sidenavOverlay.length !== 0;
  
          if (!overlayExists) {
            this.buildSidenavOverlay();
          } // Keep within boundaries
  
  
          if (this.options.edge === 'left') {
            if (touchX > this.options.MENU_WIDTH) {
              touchX = this.options.MENU_WIDTH;
            } else if (touchX < 0) {
              touchX = 0;
            }
          }
  
          this.translateSidenavX(touchX);
          this.updateOverlayOpacity(touchX);
        }
      }, {
        key: "translateSidenavX",
        value: function translateSidenavX(touchX) {
          if (this.options.edge === 'left') {
            var isRightDirection = touchX >= this.options.MENU_WIDTH / MENU_WIDTH_HALF;
            this.menuOut = isRightDirection;
            this.$menu.css('transform', "translateX(".concat(touchX - this.options.MENU_WIDTH, "px)"));
          } else {
            var isLeftDirection = touchX < window.innerWidth - this.options.MENU_WIDTH / MENU_WIDTH_HALF;
            this.menuOut = isLeftDirection;
            var rightPos = touchX - this.options.MENU_WIDTH / MENU_WIDTH_HALF;
  
            if (rightPos < 0) {
              rightPos = 0;
            }
  
            this.$menu.css('transform', "translateX(".concat(rightPos, "px)"));
          }
        }
      }, {
        key: "updateOverlayOpacity",
        value: function updateOverlayOpacity(touchX) {
          var overlayPercentage;
  
          if (this.options.edge === 'left') {
            overlayPercentage = touchX / this.options.MENU_WIDTH;
          } else {
            overlayPercentage = Math.abs((touchX - window.innerWidth) / this.options.MENU_WIDTH);
          }
  
          this.$sidenavOverlay.velocity({
            opacity: overlayPercentage
          }, {
            duration: 10,
            queue: false,
            easing: this.options.easingOpen
          });
        }
      }, {
        key: "buildSidenavOverlay",
        value: function buildSidenavOverlay() {
          var _this2 = this;
  
          if (this.options.showOverlay === true) {
            this.$sidenavOverlay = $('<div id="sidenav-overlay"></div>');
            this.$sidenavOverlay.css('opacity', 0).on('click', function () {
              return _this2.removeMenu();
            });
            this.$body.append(this.$sidenavOverlay);
          }
        }
      }, {
        key: "disableScrolling",
        value: function disableScrolling() {
          var oldWidth = this.$body.innerWidth();
          this.$body.css('overflow', 'hidden');
          this.$body.width(oldWidth);
        }
      }, {
        key: "touchendEventHandler",
        value: function touchendEventHandler(e) {
          if (e.type !== 'touchend') {
            return;
          }
  
          var touch = e.changedTouches[0];
          this.lastTouchVelocity.x.endTime = Date.now();
          this.lastTouchVelocity.x.endPosition = touch.clientX;
          var velocityX = this.calculateTouchVelocityX();
          var touchX = touch.clientX;
          var leftPos = touchX - this.options.MENU_WIDTH;
          var rightPos = touchX - this.options.MENU_WIDTH / MENU_WIDTH_HALF;
  
          if (leftPos > 0) {
            leftPos = 0;
          }
  
          if (rightPos < 0) {
            rightPos = 0;
          }
  
          if (this.options.edge === 'left') {
            // If velocityX <= 0.3 then the user is flinging the menu closed so ignore this.menuOut
            if (this.menuOut && velocityX <= MENU_LEFT_MIN_BORDER || velocityX < MENU_LEFT_MAX_BORDER) {
              if (leftPos !== 0) {
                this.translateMenuX([0, leftPos], '300');
              }
  
              this.showSidenavOverlay();
            } else if (!this.menuOut || velocityX > MENU_LEFT_MIN_BORDER) {
              this.enableScrolling();
              this.translateMenuX([-1 * this.options.MENU_WIDTH - MENU_VELOCITY_OFFSET, leftPos], '200');
              this.hideSidenavOverlay();
            }
  
            this.$dragTarget.css({
              width: '10px',
              right: '',
              left: 0
            });
          } else if (this.menuOut && velocityX >= MENU_RIGHT_MIN_BORDER || velocityX > MENU_RIGHT_MAX_BORDER) {
            this.translateMenuX([0, rightPos], '300');
            this.showSidenavOverlay();
            this.$dragTarget.css({
              width: '50%',
              right: '',
              left: 0
            });
          } else if (!this.menuOut || velocityX < MENU_RIGHT_MIN_BORDER) {
            this.enableScrolling();
            this.translateMenuX([this.options.MENU_WIDTH + MENU_VELOCITY_OFFSET, rightPos], '200');
            this.hideSidenavOverlay();
            this.$dragTarget.css({
              width: '10px',
              right: 0,
              left: ''
            });
          }
        }
      }, {
        key: "calculateTouchVelocityX",
        value: function calculateTouchVelocityX() {
          var distance = Math.abs(this.lastTouchVelocity.x.endPosition - this.lastTouchVelocity.x.startPosition);
          var time = Math.abs(this.lastTouchVelocity.x.endTime - this.lastTouchVelocity.x.startTime);
          return distance / time;
        }
      }, {
        key: "panendEventHandler",
        value: function panendEventHandler(e) {
          if (e.gesture.pointerType !== 'touch') {
            return;
          }
  
          var velocityX = e.gesture.velocityX;
          var touchX = e.gesture.center.x;
          var leftPos = touchX - this.options.MENU_WIDTH;
          var rightPos = touchX - this.options.MENU_WIDTH / MENU_WIDTH_HALF;
  
          if (leftPos > 0) {
            leftPos = 0;
          }
  
          if (rightPos < 0) {
            rightPos = 0;
          }
  
          if (this.options.edge === 'left') {
            // If velocityX <= 0.3 then the user is flinging the menu closed so ignore this.menuOut
            if (this.menuOut && velocityX <= MENU_LEFT_MIN_BORDER || velocityX < MENU_LEFT_MAX_BORDER) {
              if (leftPos !== 0) {
                this.translateMenuX([0, leftPos], '300');
              }
  
              this.showSidenavOverlay();
            } else if (!this.menuOut || velocityX > MENU_LEFT_MIN_BORDER) {
              this.enableScrolling();
              this.translateMenuX([-1 * this.options.MENU_WIDTH - MENU_VELOCITY_OFFSET, leftPos], '200');
              this.hideSidenavOverlay();
            }
  
            this.$dragTarget.css({
              width: '10px',
              right: '',
              left: 0
            });
          } else if (this.menuOut && velocityX >= MENU_RIGHT_MIN_BORDER || velocityX > MENU_RIGHT_MAX_BORDER) {
            this.translateMenuX([0, rightPos], '300');
            this.showSidenavOverlay();
            this.$dragTarget.css({
              width: '50%',
              right: '',
              left: 0
            });
          } else if (!this.menuOut || velocityX < MENU_RIGHT_MIN_BORDER) {
            this.enableScrolling();
            this.translateMenuX([this.options.MENU_WIDTH + MENU_VELOCITY_OFFSET, rightPos], '200');
            this.hideSidenavOverlay();
            this.$dragTarget.css({
              width: '10px',
              right: 0,
              left: ''
            });
          }
        }
      }, {
        key: "translateMenuX",
        value: function translateMenuX(fromTo, duration) {
          this.$menu.velocity({
            translateX: fromTo
          }, {
            duration: typeof duration === 'string' ? Number(duration) : duration,
            queue: false,
            easing: this.options.easingOpen
          });
        }
      }, {
        key: "hideSidenavOverlay",
        value: function hideSidenavOverlay() {
          this.$sidenavOverlay.velocity({
            opacity: 0
          }, {
            duration: this.options.timeDurationOverlayClose,
            queue: false,
            easing: this.options.easingOpen,
            complete: function complete() {
              $(this).remove();
            }
          });
        }
      }, {
        key: "showSidenavOverlay",
        value: function showSidenavOverlay() {
          this.$sidenavOverlay.velocity({
            opacity: 1
          }, {
            duration: this.options.timeDurationOverlayOpen,
            queue: false,
            easing: this.options.easingOpen
          });
        }
      }, {
        key: "enableScrolling",
        value: function enableScrolling() {
          this.$body.css({
            overflow: '',
            width: ''
          });
        }
      }, {
        key: "openOnClick",
        value: function openOnClick() {
          var _this3 = this;
  
          this.$element.on('click', function (e) {
            e.preventDefault();
  
            if (_this3.menuOut === true) {
              _this3.menuOut = false;
  
              _this3.removeMenu();
            } else {
              if (_this3.options.showOverlay === true) {
                _this3.$sidenavOverlay = $('<div id="sidenav-overlay"></div>');
  
                _this3.$body.append(_this3.$sidenavOverlay);
              } else {
                _this3.showCloseButton();
              }
  
              var translateX = [];
  
              if (_this3.options.edge === 'left') {
                translateX = [0, -1 * _this3.options.MENU_WIDTH];
              } else {
                translateX = [0, _this3.options.MENU_WIDTH];
              }
  
              _this3.$menu.velocity({
                translateX: translateX
              }, {
                duration: _this3.options.timeDurationOpen,
                queue: false,
                easing: _this3.options.easingOpen
              });
  
              _this3.$sidenavOverlay.on('click', function () {
                return _this3.removeMenu();
              });
  
              _this3.$sidenavOverlay.on('touchmove', _this3.touchmoveEventHandler.bind(_this3));
  
              _this3.$menu.on('touchmove', function (e) {
                e.preventDefault();
  
                _this3.$menu.find('.custom-scrollbar').css('padding-bottom', '30px');
              });
            }
          });
        }
      }, {
        key: "closeOnClick",
        value: function closeOnClick() {
          var _this4 = this;
  
          if (this.options.closeOnClick === true) {
            this.$menu.on('click', 'a:not(.collapsible-header)', function () {
              return _this4.removeMenu();
            });
          }
        }
      }, {
        key: "showCloseButton",
        value: function showCloseButton() {
          if (this.options.showCloseButton === true) {
            this.$menu.prepend(this.$elementCloned);
            this.$menu.find('.logo-wrapper').css({
              borderTop: '1px solid rgba(153,153,153,.3)'
            });
          }
        }
      }, {
        key: "setMenuTranslation",
        value: function setMenuTranslation() {
          var _this5 = this;
  
          if (this.options.edge === 'left') {
            this.$menu.css('transform', 'translateX(-100%)');
            this.$dragTarget.css({
              left: 0
            });
          } else {
            this.$menu.addClass('right-aligned').css('transform', 'translateX(100%)');
            this.$dragTarget.css({
              right: 0
            });
          }
  
          if (this.$menu.hasClass('fixed')) {
            if (window.innerWidth > this.options.breakpoint) {
              this.$menu.css('transform', 'translateX(0)');
            }
  
            this.$menu.find('input[type=text]').on('touchstart', function () {
              _this5.$menu.addClass('transform-fix-input');
            });
            $(window).resize(function () {
              if (window.innerWidth > _this5.options.breakpoint) {
                if (_this5.$sidenavOverlay.length) {
                  _this5.removeMenu(true);
                } else {
                  _this5.$menu.css('transform', 'translateX(0%)');
                }
              } else if (_this5.menuOut === false) {
                var xValue = _this5.options.edge === 'left' ? '-100' : '100';
  
                _this5.$menu.css('transform', "translateX(".concat(xValue, "%)"));
              }
            });
          }
        }
      }, {
        key: "setMenuWidth",
        value: function setMenuWidth() {
          var $sidenavBg = $("#".concat(this.$menu.attr('id'))).find('> .sidenav-bg');
  
          if (this.options.MENU_WIDTH !== MENU_WIDTH) {
            this.$menu.css('width', this.options.MENU_WIDTH);
            $sidenavBg.css('width', this.options.MENU_WIDTH);
          }
        }
      }, {
        key: "inputOnClick",
        value: function inputOnClick() {
          var _this6 = this;
  
          this.$menu.find('input[type=text]').on('touchstart', function () {
            return _this6.$menu.css('transform', 'translateX(0)');
          });
        }
      }, {
        key: "assignOptions",
        value: function assignOptions(newOptions) {
          return $.extend({}, this.defaults, newOptions);
        }
      }, {
        key: "removeMenu",
        value: function removeMenu(restoreMenu) {
          var _this7 = this;
  
          this.$body.css({
            overflow: '',
            width: ''
          });
          this.$menu.velocity({
            translateX: this.options.edge === 'left' ? '-100%' : '100%'
          }, {
            duration: this.options.timeDurationClose,
            queue: false,
            easing: this.options.easingClose,
            complete: function complete() {
              if (restoreMenu === true) {
                _this7.$menu.removeAttr('style');
  
                _this7.$menu.css('width', _this7.options.MENU_WIDTH);
              }
            }
          });
  
          if (this.$menu.hasClass('transform-fix-input')) {
            this.$menu.removeClass('transform-fix-input');
          }
  
          this.hideSidenavOverlay();
        }
      }]);
  
      return SideNav;
    }();
  
    $.fn.sideNav = function (options) {
      return this.each(function () {
        new SideNav($(this), options);
      });
    };
  })(jQuery);
  
  $(function () {
    $("#toggle").click(function () {
      if ($("#slide-out").hasClass('slim')) {
        $("#slide-out").removeClass('slim');
        $(".sv-slim-icon").removeClass('fa-angle-double-right').addClass('fa-angle-double-left');
      } else {
        $("#slide-out").addClass('slim');
        $(".sv-slim-icon").removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
      }
    });
  });
  "use strict";
  
  (function ($) {
    $.fn.collapsible = function (options) {
      var defaults = {
        accordion: undefined
      };
      options = $.extend(defaults, options);
  
      function accordionOpen($collapsible, object) {
        $panelHeaders = $collapsible.find('> li > .collapsible-header');
  
        if (object.hasClass('active')) {
          object.parent().addClass('active');
        } else {
          object.parent().removeClass('active');
        }
  
        if (object.parent().hasClass('active')) {
          object.siblings('.collapsible-body').stop(true, false).slideDown({
            duration: 350,
            easing: 'easeOutQuart',
            queue: false,
            complete: function complete() {
              $(this).css('height', '');
            }
          });
        } else {
          object.siblings('.collapsible-body').stop(true, false).slideUp({
            duration: 350,
            easing: 'easeOutQuart',
            queue: false,
            complete: function complete() {
              $(this).css('height', '');
            }
          });
        }
  
        $panelHeaders.not(object).removeClass('active').parent().removeClass('active');
        $panelHeaders.not(object).parent().children('.collapsible-body').stop(true, false).slideUp({
          duration: 350,
          easing: 'easeOutQuart',
          queue: false,
          complete: function complete() {
            $(this).css('height', '');
          }
        });
      }
  
      function expandableOpen(object) {
        if (object.hasClass('active')) {
          object.parent().addClass('active');
        } else {
          object.parent().removeClass('active');
        }
  
        if (object.parent().hasClass('active')) {
          object.siblings('.collapsible-body').stop(true, false).slideDown({
            duration: 350,
            easing: 'easeOutQuart',
            queue: false,
            complete: function complete() {
              $(this).css('height', '');
            }
          });
        } else {
          object.siblings('.collapsible-body').stop(true, false).slideUp({
            duration: 350,
            easing: 'easeOutQuart',
            queue: false,
            complete: function complete() {
              $(this).css('height', '');
            }
          });
        }
      }
  
      function isChildrenOfPanelHeader(object) {
        var panelHeader = getPanelHeader(object);
        return panelHeader.length > 0;
      }
  
      function getPanelHeader(object) {
        return object.closest('li > .collapsible-header');
      }
  
      return this.each(function () {
        var $this = $(this);
        var $panelHeaders = $(this).find('> li > .collapsible-header');
        var collapsibleType = $this.data('collapsible'); // Turn off any existing event handlers
  
        $this.off('click.collapse', '.collapsible-header');
        $panelHeaders.off('click.collapse');
  
        if (options.accordion || collapsibleType === 'accordion' || collapsibleType === undefined) {
          $panelHeaders = $this.find('> li > .collapsible-header');
          $panelHeaders.on('click.collapse', function (e) {
            var element = $(e.target);
  
            if (isChildrenOfPanelHeader(element)) {
              element = getPanelHeader(element);
            }
  
            element.toggleClass('active');
            accordionOpen($this, element);
          });
          accordionOpen($this, $panelHeaders.filter('.active').first());
        } else {
          $panelHeaders.each(function () {
            $(this).on('click.collapse', function (e) {
              var element = $(e.target);
  
              if (isChildrenOfPanelHeader(element)) {
                element = getPanelHeader(element);
              }
  
              element.toggleClass('active');
              expandableOpen(element);
            });
  
            if ($(this).hasClass('active')) {
              expandableOpen($(this));
            }
          });
        }
      });
    };
  
    $('.collapsible').collapsible();
  })(jQuery);
  /**!
   * easy-pie-chart
   * Lightweight plugin to render simple, animated and retina optimized pie charts
   *
   * @license 
   * @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
   * @version 2.1.7
   **/
  
  (function (root, factory) {
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module unless amdModuleId is set
      define(["jquery"], function (a0) {
        return (factory(a0));
      });
    } else if (typeof exports === 'object') {
      // Node. Does not work with strict CommonJS, but
      // only CommonJS-like environments that support module.exports,
      // like Node.
      module.exports = factory(require("jquery"));
    } else {
      factory(jQuery);
    }
  }(this, function ($) {
  
  /**
   * Renderer to render the chart on a canvas object
   * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)
   * @param {object}     options options object of the plugin
   */
  var CanvasRenderer = function(el, options) {
  	var cachedBackground;
  	var canvas = document.createElement('canvas');
  
  	el.appendChild(canvas);
  
  	if (typeof(G_vmlCanvasManager) === 'object') {
  		G_vmlCanvasManager.initElement(canvas);
  	}
  
  	var ctx = canvas.getContext('2d');
  
  	canvas.width = canvas.height = options.size;
  
  	// canvas on retina devices
  	var scaleBy = 1;
  	if (window.devicePixelRatio > 1) {
  		scaleBy = window.devicePixelRatio;
  		canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
  		canvas.width = canvas.height = options.size * scaleBy;
  		ctx.scale(scaleBy, scaleBy);
  	}
  
  	// move 0,0 coordinates to the center
  	ctx.translate(options.size / 2, options.size / 2);
  
  	// rotate canvas -90deg
  	ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
  
  	var radius = (options.size - options.lineWidth) / 2;
  	if (options.scaleColor && options.scaleLength) {
  		radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
  	}
  
  	// IE polyfill for Date
  	Date.now = Date.now || function() {
  		return +(new Date());
  	};
  
  	/**
  	 * Draw a circle around the center of the canvas
  	 * @param {strong} color     Valid CSS color string
  	 * @param {number} lineWidth Width of the line in px
  	 * @param {number} percent   Percentage to draw (float between -1 and 1)
  	 */
  	var drawCircle = function(color, lineWidth, percent) {
  		percent = Math.min(Math.max(-1, percent || 0), 1);
  		var isNegative = percent <= 0 ? true : false;
  
  		ctx.beginPath();
  		ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
  
  		ctx.strokeStyle = color;
  		ctx.lineWidth = lineWidth;
  
  		ctx.stroke();
  	};
  
  	/**
  	 * Draw the scale of the chart
  	 */
  	var drawScale = function() {
  		var offset;
  		var length;
  
  		ctx.lineWidth = 1;
  		ctx.fillStyle = options.scaleColor;
  
  		ctx.save();
  		for (var i = 24; i > 0; --i) {
  			if (i % 6 === 0) {
  				length = options.scaleLength;
  				offset = 0;
  			} else {
  				length = options.scaleLength * 0.6;
  				offset = options.scaleLength - length;
  			}
  			ctx.fillRect(-options.size/2 + offset, 0, length, 1);
  			ctx.rotate(Math.PI / 12);
  		}
  		ctx.restore();
  	};
  
  	/**
  	 * Request animation frame wrapper with polyfill
  	 * @return {function} Request animation frame method or timeout fallback
  	 */
  	var reqAnimationFrame = (function() {
  		return  window.requestAnimationFrame ||
  				window.webkitRequestAnimationFrame ||
  				window.mozRequestAnimationFrame ||
  				function(callback) {
  					window.setTimeout(callback, 1000 / 60);
  				};
  	}());
  
  	/**
  	 * Draw the background of the plugin including the scale and the track
  	 */
  	var drawBackground = function() {
  		if(options.scaleColor) drawScale();
  		if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
  	};
  
    /**
      * Canvas accessor
     */
    this.getCanvas = function() {
      return canvas;
    };
  
    /**
      * Canvas 2D context 'ctx' accessor
     */
    this.getCtx = function() {
      return ctx;
    };
  
  	/**
  	 * Clear the complete canvas
  	 */
  	this.clear = function() {
  		ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
  	};
  
  	/**
  	 * Draw the complete chart
  	 * @param {number} percent Percent shown by the chart between -100 and 100
  	 */
  	this.draw = function(percent) {
  		// do we need to render a background
  		if (!!options.scaleColor || !!options.trackColor) {
  			// getImageData and putImageData are supported
  			if (ctx.getImageData && ctx.putImageData) {
  				if (!cachedBackground) {
  					drawBackground();
  					cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
  				} else {
  					ctx.putImageData(cachedBackground, 0, 0);
  				}
  			} else {
  				this.clear();
  				drawBackground();
  			}
  		} else {
  			this.clear();
  		}
  
  		ctx.lineCap = options.lineCap;
  
  		// if barcolor is a function execute it and pass the percent as a value
  		var color;
  		if (typeof(options.barColor) === 'function') {
  			color = options.barColor(percent);
  		} else {
  			color = options.barColor;
  		}
  
  		// draw bar
  		drawCircle(color, options.lineWidth, percent / 100);
  	}.bind(this);
  
  	/**
  	 * Animate from some percent to some other percentage
  	 * @param {number} from Starting percentage
  	 * @param {number} to   Final percentage
  	 */
  	this.animate = function(from, to) {
  		var startTime = Date.now();
  		options.onStart(from, to);
  		var animation = function() {
  			var process = Math.min(Date.now() - startTime, options.animate.duration);
  			var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
  			this.draw(currentValue);
  			options.onStep(from, to, currentValue);
  			if (process >= options.animate.duration) {
  				options.onStop(from, to);
  			} else {
  				reqAnimationFrame(animation);
  			}
  		}.bind(this);
  
  		reqAnimationFrame(animation);
  	}.bind(this);
  };
  
  var EasyPieChart = function(el, opts) {
  	var defaultOptions = {
  		barColor: '#ef1e25',
  		trackColor: '#f9f9f9',
  		scaleColor: '#dfe0e0',
  		scaleLength: 5,
  		lineCap: 'round',
  		lineWidth: 3,
  		trackWidth: undefined,
  		size: 110,
  		rotate: 0,
  		animate: {
  			duration: 1000,
  			enabled: true
  		},
  		easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
  			t = t / (d/2);
  			if (t < 1) {
  				return c / 2 * t * t + b;
  			}
  			return -c/2 * ((--t)*(t-2) - 1) + b;
  		},
  		onStart: function(from, to) {
  			return;
  		},
  		onStep: function(from, to, currentValue) {
  			return;
  		},
  		onStop: function(from, to) {
  			return;
  		}
  	};
  
  	// detect present renderer
  	if (typeof(CanvasRenderer) !== 'undefined') {
  		defaultOptions.renderer = CanvasRenderer;
  	} else if (typeof(SVGRenderer) !== 'undefined') {
  		defaultOptions.renderer = SVGRenderer;
  	} else {
  		throw new Error('Please load either the SVG- or the CanvasRenderer');
  	}
  
  	var options = {};
  	var currentValue = 0;
  
  	/**
  	 * Initialize the plugin by creating the options object and initialize rendering
  	 */
  	var init = function() {
  		this.el = el;
  		this.options = options;
  
  		// merge user options into default options
  		for (var i in defaultOptions) {
  			if (defaultOptions.hasOwnProperty(i)) {
  				options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
  				if (typeof(options[i]) === 'function') {
  					options[i] = options[i].bind(this);
  				}
  			}
  		}
  
  		// check for jQuery easing
  		if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
  			options.easing = jQuery.easing[options.easing];
  		} else {
  			options.easing = defaultOptions.easing;
  		}
  
  		// process earlier animate option to avoid bc breaks
  		if (typeof(options.animate) === 'number') {
  			options.animate = {
  				duration: options.animate,
  				enabled: true
  			};
  		}
  
  		if (typeof(options.animate) === 'boolean' && !options.animate) {
  			options.animate = {
  				duration: 1000,
  				enabled: options.animate
  			};
  		}
  
  		// create renderer
  		this.renderer = new options.renderer(el, options);
  
  		// initial draw
  		this.renderer.draw(currentValue);
  
  		// initial update
  		if (el.dataset && el.dataset.percent) {
  			this.update(parseFloat(el.dataset.percent));
  		} else if (el.getAttribute && el.getAttribute('data-percent')) {
  			this.update(parseFloat(el.getAttribute('data-percent')));
  		}
  	}.bind(this);
  
  	/**
  	 * Update the value of the chart
  	 * @param  {number} newValue Number between 0 and 100
  	 * @return {object}          Instance of the plugin for method chaining
  	 */
  	this.update = function(newValue) {
  		newValue = parseFloat(newValue);
  		if (options.animate.enabled) {
  			this.renderer.animate(currentValue, newValue);
  		} else {
  			this.renderer.draw(newValue);
  		}
  		currentValue = newValue;
  		return this;
  	}.bind(this);
  
  	/**
  	 * Disable animation
  	 * @return {object} Instance of the plugin for method chaining
  	 */
  	this.disableAnimation = function() {
  		options.animate.enabled = false;
  		return this;
  	};
  
  	/**
  	 * Enable animation
  	 * @return {object} Instance of the plugin for method chaining
  	 */
  	this.enableAnimation = function() {
  		options.animate.enabled = true;
  		return this;
  	};
  
  	init();
  };
  
  $.fn.easyPieChart = function(options) {
  	return this.each(function() {
  		var instanceOptions;
  
  		if (!$.data(this, 'easyPieChart')) {
  			instanceOptions = $.extend({}, options, $(this).data());
  			$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
  		}
  	});
  };
  
  
  }));
  
  'use strict';
  
  (function ($) {
  
    $(document).on('change', '.file-field input[type="file"]', function (e) {
  
      var $this = $(e.target);
      var $fileField = $this.closest('.file-field');
      var $pathInput = $fileField.find('input.file-path');
      var files = $this[0].files;
      var fileNames = [];
      files.forEach(function (file) {
        return fileNames.push(file.name);
      });
      $pathInput.val(fileNames.join(', '));
      $pathInput.trigger('change');
    });
  })(jQuery);
  "use strict";
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
  
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  
  (function ($) {
    var MaterialSelect =
    /*#__PURE__*/
    function () {
      function MaterialSelect($nativeSelect, options) {
        _classCallCheck(this, MaterialSelect);
  
        this.$nativeSelect = $nativeSelect;
        this.defaults = {
          destroy: false,
          nativeID: null,
          BSsearchIn: false,
          BSinputText: false,
          fasClasses: '',
          farClasses: '',
          fabClasses: '',
          copyClassesOption: false,
          language: {
            active: false,
            pl: {
              selectAll: 'Wybierz wszystko',
              optionsSelected: 'wybranych opcji'
            },
            in: {
              selectAll: 'Pilih semuanya',
              optionsSelected: 'opsi yang dipilih'
            },
            fr: {
              selectAll: 'Tout choisir',
              optionsSelected: 'options sélectionnées'
            },
            ge: {
              selectAll: 'Wähle alles aus',
              optionsSelected: 'ausgewählte Optionen'
            },
            ar: {
              selectAll: 'اختر كل شيء',
              optionsSelected: 'الخيارات المحددة'
            }
          }
        };
        this.options = this.assignOptions(options);
        this.isMultiple = Boolean(this.$nativeSelect.attr('multiple'));
        this.isSearchable = Boolean(this.$nativeSelect.attr('searchable'));
        this.isRequired = Boolean(this.$nativeSelect.attr('required'));
        this.uuid = this.options.nativeID !== null && this.options.nativeID !== '' && this.options.nativeID !== undefined && typeof this.options.nativeID === 'string' ? this.options.nativeID : this._randomUUID();
        this.$selectWrapper = $('<div class="select-wrapper"></div>');
        this.$materialOptionsList = $("<ul id=\"select-options-".concat(this.uuid, "\" class=\"dropdown-content select-dropdown w-100 ").concat(this.isMultiple ? 'multiple-select-dropdown' : '', "\"></ul>"));
        this.$materialSelectedOption = this.$nativeSelect.find('option:selected');
        this.$materialSelectInitialOption = this.$nativeSelect.find('option:first').text() || '';
        this.$nativeSelectChildren = this.$nativeSelect.children('option, optgroup');
        this.$materialSelect = $("<input type=\"text\" class=\"".concat(this.options.BSinputText ? 'browser-default custom-select multi-bs-select select-dropdown' : 'select-dropdown', "\" readonly=\"true\" ").concat(this.$nativeSelect.is(' :disabled') ? 'disabled' : '', " data-activates=\"select-options-").concat(this.uuid, "\" value=\"\"/>"));
        this.$dropdownIcon = this.options.BSinputText ? '' : $('<span class="caret">&#9660;</span>');
        this.$searchInput = null;
        this.$toggleAll = $('<li class="select-toggle-all"><span><input type="checkbox" class="form-check-input"><label>Select all</label></span></li>');
        this.label = this.$nativeSelect.next('label').not('.mdb-main-label');
        this.mainLabel = this.$nativeSelect.next('.mdb-main-label');
        this.valuesSelected = [];
        this.keyCodes = {
          tab: 9,
          esc: 27,
          enter: 13,
          arrowUp: 38,
          arrowDown: 40
        };
        MaterialSelect.mutationObservers = [];
      }
  
      _createClass(MaterialSelect, [{
        key: "assignOptions",
        value: function assignOptions(newOptions) {
          return $.extend({}, this.defaults, newOptions);
        }
      }, {
        key: "init",
        value: function init() {
          var alreadyInitialized = Boolean(this.$nativeSelect.data('select-id'));
  
          if (alreadyInitialized) {
            this._removeMaterialWrapper();
          }
  
          if (this.options.destroy) {
            this.$nativeSelect.data('select-id', null).removeClass('initialized');
            return;
          }
  
          if (this.options.BSsearchIn || this.options.BSinputText) {
            this.$selectWrapper.addClass(this.$nativeSelect.attr('class').split(' ').filter(function (el) {
              return el !== 'md-form';
            }).join(' ')).css({
              marginTop: '1.5rem',
              marginBottom: '1.5rem'
            });
          } else {
            this.$selectWrapper.addClass(this.$nativeSelect.attr('class'));
          }
  
          this.$nativeSelect.data('select-id', this.uuid);
          var sanitizedLabelHtml = this.$materialSelectInitialOption.replace(/"/g, '&quot;').replace(/  +/g, ' ').trim();
  
          if (this.mainLabel.length === 0) {
            this.$materialSelect.val(sanitizedLabelHtml);
          } else {
            this.mainLabel.text();
          }
  
          if (this.$materialSelectedOption.length > 0 && this.$nativeSelect.hasClass('md-selected')) {
            this.mainLabel.addClass('active');
            this.$materialSelect.val(this.$materialSelectedOption.text());
          }
  
          this.renderMaterialSelect();
          this.bindEvents();
  
          if (this.isRequired) {
            this.enableValidation();
          }
  
          if (this.options.language.active && this.$toggleAll) {
            if (this.options.language.pl) {
              this.$toggleAll.find('label').text(this.options.language.pl.selectAll ? this.options.language.pl.selectAll : this.defaults.language.pl.selectAll);
            }
  
            if (this.options.language.fr) {
              this.$toggleAll.find('label').text(this.options.language.fr.selectAll ? this.options.language.fr.selectAll : this.defaults.language.fr.selectAll);
            }
  
            if (this.options.language.ge) {
              this.$toggleAll.find('label').text(this.options.language.ge.selectAll ? this.options.language.ge.selectAll : this.defaults.language.ge.selectAll);
            }
  
            if (this.options.language.ar) {
              this.$toggleAll.find('label').text(this.options.language.ar.selectAll ? this.options.language.ar.selectAll : this.defaults.language.ar.selectAll);
            }
  
            if (this.options.language.in) {
              this.$toggleAll.find('label').text(this.options.language.in.selectAll ? this.options.language.in.selectAll : this.defaults.language.in.selectAll);
            }
          }
  
          if (this.$materialSelect.hasClass('custom-select') && this.$materialSelect.hasClass('select-dropdown')) {
            this.$materialSelect.css({
              display: 'inline-block',
              width: '100%',
              height: 'calc(1.5em + .75rem + 2px)',
              padding: '.375rem 1.75rem .375rem .75rem',
              fontSize: '1rem',
              lineHeight: '1.5',
              backgroundColor: '#fff',
              border: '1px solid #ced4da'
            });
          }
        }
      }, {
        key: "_removeMaterialWrapper",
        value: function _removeMaterialWrapper() {
          var currentUuid = this.$nativeSelect.data('select-id');
          this.$nativeSelect.parent().find('span.caret').remove();
          this.$nativeSelect.parent().find('input').remove();
          this.$nativeSelect.unwrap();
          $("ul#select-options-".concat(currentUuid)).remove();
        }
      }, {
        key: "renderMaterialSelect",
        value: function renderMaterialSelect() {
          var _this = this;
  
          this.$nativeSelect.before(this.$selectWrapper);
          this.appendDropdownIcon();
          this.appendMaterialSelect();
          this.appendMaterialOptionsList();
          this.appendNativeSelect();
          this.appendSaveSelectButton();
  
          if (!this.$nativeSelect.is(':disabled')) {
            this.$materialSelect.dropdown({
              hover: false,
              closeOnClick: false
            });
          }
  
          if (this.$nativeSelect.data('inherit-tabindex') !== false) {
            this.$materialSelect.attr('tabindex', this.$nativeSelect.attr('tabindex'));
          }
  
          if (this.isMultiple) {
            this.$nativeSelect.find('option:selected:not(:disabled)').each(function (i, element) {
              var index = element.index;
  
              _this._toggleSelectedValue(index);
  
              _this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(index).find(':checkbox').prop('checked', true);
            });
          } else {
            var index = this.$nativeSelect.find('option:selected').index();
            this.$materialOptionsList.find('li').eq(index).addClass('active');
          }
  
          this.$nativeSelect.addClass('initialized');
  
          if (this.options.BSinputText) {
            this.mainLabel.css('top', '-7px');
          }
        }
      }, {
        key: "appendDropdownIcon",
        value: function appendDropdownIcon() {
          if (this.$nativeSelect.is(':disabled')) {
            this.$dropdownIcon.addClass('disabled');
          }
  
          this.$selectWrapper.append(this.$dropdownIcon);
        }
      }, {
        key: "appendMaterialSelect",
        value: function appendMaterialSelect() {
          this.$selectWrapper.append(this.$materialSelect);
        }
      }, {
        key: "appendMaterialOptionsList",
        value: function appendMaterialOptionsList() {
          if (this.isSearchable) {
            this.appendSearchInputOption();
          }
  
          this.buildMaterialOptions();
  
          if (this.isMultiple) {
            this.appendToggleAllCheckbox();
          }
  
          this.$selectWrapper.append(this.$materialOptionsList);
        }
      }, {
        key: "appendNativeSelect",
        value: function appendNativeSelect() {
          this.$nativeSelect.appendTo(this.$selectWrapper);
        }
      }, {
        key: "appendSearchInputOption",
        value: function appendSearchInputOption() {
          var placeholder = this.$nativeSelect.attr('searchable');
  
          if (this.options.BSsearchIn) {
            this.$searchInput = $("<span class=\"search-wrap ml-2\"><div class=\"mt-0\"><input type=\"text\" class=\"search form-control mb-2 w-100 d-block select-default\" placeholder=\"".concat(placeholder, "\"></div></span>"));
          } else {
            this.$searchInput = $("<span class=\"search-wrap ml-2\"><div class=\"md-form mt-0\"><input type=\"text\" class=\"search form-control w-100 d-block\" placeholder=\"".concat(placeholder, "\"></div></span>"));
          }
  
          this.$materialOptionsList.append(this.$searchInput);
          this.$searchInput.on('click', function (e) {
            e.stopPropagation();
          });
        }
      }, {
        key: "appendToggleAllCheckbox",
        value: function appendToggleAllCheckbox() {
          this.$materialOptionsList.find('li.disabled').first().after(this.$toggleAll);
        }
      }, {
        key: "appendSaveSelectButton",
        value: function appendSaveSelectButton() {
          this.$selectWrapper.parent().find('button.btn-save').appendTo(this.$materialOptionsList);
        }
      }, {
        key: "buildMaterialOptions",
        value: function buildMaterialOptions() {
          var _this2 = this;
  
          this.$nativeSelectChildren.each(function (index, option) {
            var $this = $(option);
  
            if ($this.is('option')) {
              _this2.buildSingleOption($this, _this2.isMultiple ? 'multiple' : '');
            } else if ($this.is('optgroup')) {
              var $materialOptgroup = $("<li class=\"optgroup\"><span>".concat($this.attr('label'), "</span></li>"));
  
              _this2.$materialOptionsList.append($materialOptgroup);
  
              var $optgroupOptions = $this.children('option');
              $optgroupOptions.each(function (index, optgroupOption) {
                _this2.buildSingleOption($(optgroupOption), 'optgroup-option');
              });
            }
          });
        }
      }, {
        key: "buildSingleOption",
        value: function buildSingleOption($nativeSelectChild, type) {
          var disabled = $nativeSelectChild.is(':disabled') ? 'disabled' : '';
          var optgroupClass = type === 'optgroup-option' ? 'optgroup-option' : '';
          var iconUrl = $nativeSelectChild.data('icon');
          var fas = $nativeSelectChild.data('fas') ? "<i class=\"fa-pull-right m-2 fas fa-".concat($nativeSelectChild.data('fas'), " ").concat([...this.options.fasClasses].join(''), "\"></i> ") : '';
          var far = $nativeSelectChild.data('far') ? "<i class=\"fa-pull-right m-2 far fa-".concat($nativeSelectChild.data('far'), " ").concat([...this.options.farClasses].join(''), "\"></i> ") : '';
          var fab = $nativeSelectChild.data('fab') ? "<i class=\"fa-pull-right m-2 fab fa-".concat($nativeSelectChild.data('fab'), " ").concat([...this.options.fabClasses].join(''), "\"></i> ") : '';
          var classes = $nativeSelectChild.attr('class');
          var iconHtml = iconUrl ? "<img alt=\"\" src=\"".concat(iconUrl, "\" class=\"").concat(classes, "\">") : '';
          var checkboxHtml = this.isMultiple ? "<input type=\"checkbox\" class=\"form-check-input\" ".concat(disabled, "/><label></label>") : '';
          this.$materialOptionsList.append($("<li class=\"".concat(disabled, " ").concat(optgroupClass, " ").concat(this.options.copyClassesOption ? classes : '', " \">").concat(iconHtml, "<span class=\"filtrable\">").concat(checkboxHtml, " ").concat($nativeSelectChild.html(), " ").concat(fas, " ").concat(far, " ").concat(fab, "</span></li>")));
        }
      }, {
        key: "enableValidation",
        value: function enableValidation() {
          this.$nativeSelect.css({
            position: 'absolute',
            top: '1rem',
            left: '0',
            height: '0',
            width: '0',
            opacity: '0',
            padding: '0',
            'pointer-events': 'none'
          });
  
          if (this.$nativeSelect.attr('style').indexOf('inline!important') === -1) {
            this.$nativeSelect.attr('style', "".concat(this.$nativeSelect.attr('style'), " display: inline!important;"));
          }
  
          this.$nativeSelect.attr('tabindex', -1);
          this.$nativeSelect.data('inherit-tabindex', false);
        }
      }, {
        key: "bindEvents",
        value: function bindEvents() {
          var _this3 = this;
  
          var config = {
            attributes: true,
            childList: true,
            characterData: true,
            subtree: true
          };
          var observer = new MutationObserver(this._onMutationObserverChange.bind(this));
          observer.observe(this.$nativeSelect.get(0), config);
          observer.customId = this.uuid;
          observer.customStatus = 'observing';
          MaterialSelect.clearMutationObservers();
          MaterialSelect.mutationObservers.push(observer);
          var $saveSelectBtn = this.$nativeSelect.parent().find('button.btn-save');
          $saveSelectBtn.on('click', this._onSaveSelectBtnClick.bind(this));
          this.$materialSelect.on('focus', this._onMaterialSelectFocus.bind(this));
          this.$materialSelect.on('click', this._onMaterialSelectClick.bind(this));
          this.$materialSelect.on('blur', this._onMaterialSelectBlur.bind(this));
          this.$materialSelect.on('keydown', this._onMaterialSelectKeydown.bind(this));
          this.$toggleAll.on('click', this._onToggleAllClick.bind(this));
          this.$materialOptionsList.on('mousedown', this._onEachMaterialOptionMousedown.bind(this));
          this.$materialOptionsList.find('li:not(.optgroup)').not(this.$toggleAll).each(function (materialOptionIndex, materialOption) {
            $(materialOption).on('click', _this3._onEachMaterialOptionClick.bind(_this3, materialOptionIndex, materialOption));
          });
  
          if (!this.isMultiple && this.isSearchable) {
            this.$materialOptionsList.find('li').on('click', this._onSingleMaterialOptionClick.bind(this));
          }
  
          if (this.isSearchable) {
            this.$searchInput.find('.search').on('keyup', this._onSearchInputKeyup);
          }
  
          $('html').on('click', this._onHTMLClick.bind(this));
        }
      }, {
        key: "_onMutationObserverChange",
        value: function _onMutationObserverChange(mutationsList) {
          mutationsList.forEach(function (mutation) {
            var $select = $(mutation.target).closest('select');
  
            if ($select.data('stop-refresh') !== true && (mutation.type === 'childList' || mutation.type === 'attributes' && $(mutation.target).is('option'))) {
              MaterialSelect.clearMutationObservers();
              $select.materialSelect({
                destroy: true
              });
              $select.materialSelect();
            }
          });
        }
      }, {
        key: "_onSaveSelectBtnClick",
        value: function _onSaveSelectBtnClick() {
          $('input.multi-bs-select').trigger('close');
          this.$materialOptionsList.hide();
          this.$materialSelect.removeClass('active');
        }
      }, {
        key: "_onEachMaterialOptionClick",
        value: function _onEachMaterialOptionClick(materialOptionIndex, materialOption, e) {
          e.stopPropagation();
          var $this = $(materialOption);
  
          if ($this.hasClass('disabled') || $this.hasClass('optgroup')) {
            return;
          }
  
          var selected = true;
  
          if (this.isMultiple) {
            $this.find('input[type="checkbox"]').prop('checked', function (index, oldPropertyValue) {
              return !oldPropertyValue;
            });
            var hasOptgroup = Boolean(this.$nativeSelect.find('optgroup').length);
            var thisIndex = this._isToggleAllPresent() ? $this.index() - 1 : $this.index();
  
            if (this.isSearchable && hasOptgroup) {
              selected = this._toggleSelectedValue(thisIndex - $this.prevAll('.optgroup').length - 1);
            } else if (this.isSearchable) {
              selected = this._toggleSelectedValue(thisIndex - 1);
            } else if (hasOptgroup) {
              selected = this._toggleSelectedValue(thisIndex - $this.prevAll('.optgroup').length);
            } else {
              selected = this._toggleSelectedValue(thisIndex);
            }
  
            if (this._isToggleAllPresent()) {
              this._updateToggleAllOption();
            }
  
            this.$materialSelect.trigger('focus');
          } else {
            this.$materialOptionsList.find('li').removeClass('active');
            $this.toggleClass('active');
            this.$materialSelect.val($this.text().replace(/  +/g, ' ').trim());
            this.$materialSelect.trigger('close');
          }
  
          this._selectSingleOption($this);
  
          this.$nativeSelect.data('stop-refresh', true);
          this.$nativeSelect.find('option').eq(materialOptionIndex).prop('selected', selected);
          this.$nativeSelect.removeData('stop-refresh');
  
          this._triggerChangeOnNativeSelect();
  
          if (this.mainLabel.prev().find('input').hasClass('select-dropdown')) {
            if (this.mainLabel.prev().find('input.select-dropdown').val().length > 0) {
              this.mainLabel.addClass('active');
            }
          }
  
          if (typeof this.options === 'function') {
            this.options();
          }
  
          if ($this.hasClass('li-added')) {
            this.$materialOptionsList.append(this.buildSingleOption($this, ''));
          }
        }
      }, {
        key: "_triggerChangeOnNativeSelect",
        value: function _triggerChangeOnNativeSelect() {
          var keyboardEvt = new KeyboardEvent('change', {
            bubbles: true,
            cancelable: true
          });
          this.$nativeSelect.get(0).dispatchEvent(keyboardEvt);
        }
      }, {
        key: "_onMaterialSelectFocus",
        value: function _onMaterialSelectFocus(e) {
          var $this = $(e.target);
  
          if ($('ul.select-dropdown').not(this.$materialOptionsList.get(0)).is(':visible')) {
            $('input.select-dropdown').trigger('close');
          }
  
          this.mainLabel.addClass('active');
  
          if (!this.$materialOptionsList.is(':visible')) {
            $this.trigger('open', ['focus']);
            var label = $this.val();
            var $selectedOption = this.$materialOptionsList.find('li').filter(function () {
              return $(this).text().toLowerCase() === label.toLowerCase();
            })[0];
  
            this._selectSingleOption($selectedOption);
          }
  
          if (!this.isMultiple) {
            this.mainLabel.addClass('active ');
          }
  
          $(document).find('input.select-dropdown').each(function (i, el) {
            return $(el).val().length <= 0;
          }).parent().next('.mdb-main-label').filter(function (i, el) {
            return $(el).prev().find('input.select-dropdown').val().length <= 0 && !$(el).prev().find('input.select-dropdown').hasClass('active');
          }).removeClass('active');
        }
      }, {
        key: "_onMaterialSelectClick",
        value: function _onMaterialSelectClick(e) {
          this.mainLabel.addClass('active ');
          e.stopPropagation();
        }
      }, {
        key: "_onMaterialSelectBlur",
        value: function _onMaterialSelectBlur(e) {
          var $this = $(e);
  
          if (!this.isMultiple && !this.isSearchable) {
            $this.trigger('close');
          }
  
          this.$materialOptionsList.find('li.selected').removeClass('selected');
        }
      }, {
        key: "_onSingleMaterialOptionClick",
        value: function _onSingleMaterialOptionClick() {
          this.$materialSelect.trigger('close');
        }
      }, {
        key: "_onEachMaterialOptionMousedown",
        value: function _onEachMaterialOptionMousedown(e) {
          var option = e.target;
  
          if ($('.modal-content').find(this.$materialOptionsList).length) {
            if (option.scrollHeight > option.offsetHeight) {
              e.preventDefault();
            }
          }
        }
      }, {
        key: "_onHTMLClick",
        value: function _onHTMLClick(e) {
          if (!$(e.target).closest("#select-options-".concat(this.uuid)).length && !$(e.target).hasClass('mdb-select') && $("#select-options-".concat(this.uuid)).hasClass('active')) {
            this.$materialSelect.trigger('close');
  
            if (!this.$materialSelect.val().length > 0) {
              this.mainLabel.removeClass('active');
            }
          }
  
          if (this.isSearchable && this.$searchInput !== null && this.$materialOptionsList.hasClass('active')) {
            this.$materialOptionsList.find('.search-wrap input.search').focus();
          }
        }
      }, {
        key: "_onToggleAllClick",
        value: function _onToggleAllClick(e) {
          var _this4 = this;
  
          var checkbox = $(this.$toggleAll).find('input[type="checkbox"]').first();
          var state = !$(checkbox).prop('checked');
          $(checkbox).prop('checked', state);
          this.$materialOptionsList.find('li:not(.optgroup):not(.disabled):not(.select-toggle-all)').each(function (materialOptionIndex, materialOption) {
            var $optionCheckbox = $(materialOption).find('input[type="checkbox"]');
  
            if (state && $optionCheckbox.is(':checked') || !state && !$optionCheckbox.is(':checked')) {
              return;
            }
  
            if (_this4._isToggleAllPresent()) {
              materialOptionIndex++;
            }
  
            $optionCheckbox.prop('checked', state);
  
            _this4.$nativeSelect.find('option').eq(materialOptionIndex).prop('selected', state);
  
            if (state) {
              $(materialOption).removeClass('active');
            } else {
              $(materialOption).addClass('active');
            }
  
            _this4._toggleSelectedValue(materialOptionIndex);
  
            _this4._selectOption(materialOption);
  
            _this4._setValueToMaterialSelect();
          });
          this.$nativeSelect.data('stop-refresh', true);
  
          this._triggerChangeOnNativeSelect();
  
          this.$nativeSelect.removeData('stop-refresh');
          e.stopPropagation();
        }
      }, {
        key: "_onMaterialSelectKeydown",
        value: function _onMaterialSelectKeydown(e) {
          var $this = $(e.target);
          var isTab = e.which === this.keyCodes.tab;
          var isEsc = e.which === this.keyCodes.esc;
          var isEnter = e.which === this.keyCodes.enter;
          var isArrowUp = e.which === this.keyCodes.arrowUp;
          var isArrowDown = e.which === this.keyCodes.arrowDown;
          var isMaterialSelectVisible = this.$materialOptionsList.is(':visible');
  
          if (isTab) {
            this._handleTabKey($this);
  
            return;
          } else if (isArrowDown && !isMaterialSelectVisible) {
            $this.trigger('open');
            return;
          } else if (isEnter && !isMaterialSelectVisible) {
            return;
          }
  
          e.preventDefault();
  
          if (isEnter) {
            this._handleEnterKey($this);
          } else if (isArrowDown) {
            this._handleArrowDownKey();
          } else if (isArrowUp) {
            this._handleArrowUpKey();
          } else if (isEsc) {
            this._handleEscKey($this);
          } else {
            this._handleLetterKey(e);
          }
        }
      }, {
        key: "_handleTabKey",
        value: function _handleTabKey(materialSelect) {
          this._handleEscKey(materialSelect);
        }
      }, {
        key: "_handleEnterKey",
        value: function _handleEnterKey(materialSelect) {
          var $activeOption = this.$materialOptionsList.find('li.selected:not(.disabled)');
          $activeOption.trigger('click').addClass('active');
  
          if (!this.isMultiple) {
            $(materialSelect).trigger('close');
          }
        }
      }, {
        key: "_handleArrowDownKey",
        value: function _handleArrowDownKey() {
          var $firstOption = this.$materialOptionsList.find('li').not('.disabled').first();
          var $lastOption = this.$materialOptionsList.find('li').not('.disabled').last();
          var anySelected = this.$materialOptionsList.find('li.selected').length > 0;
          var $currentOption = anySelected ? this.$materialOptionsList.find('li.selected') : $firstOption;
          var $matchedMaterialOption = $currentOption.is($lastOption) || !anySelected ? $currentOption : $currentOption.next('li:not(.disabled)');
  
          this._selectSingleOption($matchedMaterialOption);
  
          if (!$matchedMaterialOption.find('input').is(':checked')) {
            $matchedMaterialOption.removeClass('active');
          }
  
          if (!$matchedMaterialOption.prev().hasClass('selected') && !$matchedMaterialOption.prev().find('input').is(':checked')) {
            $matchedMaterialOption.prev().removeClass('active');
          }
  
          $matchedMaterialOption.addClass('active');
        }
      }, {
        key: "_handleArrowUpKey",
        value: function _handleArrowUpKey() {
          var $firstOption = this.$materialOptionsList.find('li').not('.disabled').first();
          var $lastOption = this.$materialOptionsList.find('li').not('.disabled').last();
          var anySelected = this.$materialOptionsList.find('li.selected').length > 0;
          var $currentOption = anySelected ? this.$materialOptionsList.find('li.selected') : $lastOption;
          var $matchedMaterialOption = $currentOption.is($firstOption) || !anySelected ? $currentOption : $currentOption.prev('li:not(.disabled)');
  
          this._selectSingleOption($matchedMaterialOption);
  
          if (!$matchedMaterialOption.find('input').is(':checked')) {
            $matchedMaterialOption.removeClass('active');
          }
  
          if (!$matchedMaterialOption.next().hasClass('selected') && !$matchedMaterialOption.next().find('input').is(':checked')) {
            $matchedMaterialOption.next().removeClass('active');
          }
  
          $matchedMaterialOption.addClass('active');
        }
      }, {
        key: "_handleEscKey",
        value: function _handleEscKey(materialSelect) {
          $(materialSelect).trigger('close');
        }
      }, {
        key: "_handleLetterKey",
        value: function _handleLetterKey(e) {
          var _this5 = this;
  
          var filterQueryString = '';
          var letter = String.fromCharCode(e.which).toLowerCase();
          var nonLetters = Object.keys(this.keyCodes).map(function (key) {
            return _this5.keyCodes[key];
          });
          var isLetterSearchable = letter && nonLetters.indexOf(e.which) === -1;
  
          if (isLetterSearchable) {
            filterQueryString += letter;
            var $matchedMaterialOption = this.$materialOptionsList.find('li').filter(function (index, element) {
              return $(element).text().toLowerCase().includes(filterQueryString);
            }).first();
  
            if (!this.isMultiple) {
              this.$materialOptionsList.find('li').removeClass('active');
            }
  
            $matchedMaterialOption.addClass('active');
  
            this._selectSingleOption($matchedMaterialOption);
          }
        }
      }, {
        key: "_onSearchInputKeyup",
        value: function _onSearchInputKeyup(e) {
          var $this = $(e.target);
          var $ul = $this.closest('ul');
          var searchValue = $this.val();
          var $options = $ul.find('li span.filtrable');
          $options.each(function () {
            var $option = $(this);
  
            if (typeof this.outerHTML === 'string') {
              var liValue = this.textContent.toLowerCase();
  
              if (liValue.includes(searchValue.toLowerCase())) {
                $option.show().parent().show();
              } else {
                $option.hide().parent().hide();
              }
            }
          });
        }
      }, {
        key: "_isToggleAllPresent",
        value: function _isToggleAllPresent() {
          return this.$materialOptionsList.find(this.$toggleAll).length;
        }
      }, {
        key: "_updateToggleAllOption",
        value: function _updateToggleAllOption() {
          var $allOptionsButToggleAll = this.$materialOptionsList.find('li').not('.select-toggle-all, .disabled').find('[type=checkbox]');
          var $checkedOptionsButToggleAll = $allOptionsButToggleAll.filter(':checked');
          var isToggleAllChecked = this.$toggleAll.find('[type=checkbox]').is(':checked');
  
          if ($checkedOptionsButToggleAll.length === $allOptionsButToggleAll.length && !isToggleAllChecked) {
            this.$toggleAll.find('[type=checkbox]').prop('checked', true);
          } else if ($checkedOptionsButToggleAll.length < $allOptionsButToggleAll.length && isToggleAllChecked) {
            this.$toggleAll.find('[type=checkbox]').prop('checked', false);
          }
        }
      }, {
        key: "_toggleSelectedValue",
        value: function _toggleSelectedValue(optionIndex) {
          var selectedValueIndex = this.valuesSelected.indexOf(optionIndex);
          var isSelected = selectedValueIndex !== -1;
  
          if (!isSelected) {
            this.valuesSelected.push(optionIndex);
          } else {
            this.valuesSelected.splice(selectedValueIndex, 1);
          }
  
          this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(optionIndex).toggleClass('active');
          this.$nativeSelect.find('option').eq(optionIndex).prop('selected', !isSelected);
  
          this._setValueToMaterialSelect();
  
          return !isSelected;
        }
      }, {
        key: "_selectSingleOption",
        value: function _selectSingleOption(newOption) {
          this.$materialOptionsList.find('li.selected').removeClass('selected');
  
          this._selectOption(newOption);
        }
      }, {
        key: "_selectOption",
        value: function _selectOption(newOption) {
          var option = $(newOption);
          option.addClass('selected');
        }
      }, {
        key: "_setValueToMaterialSelect",
        value: function _setValueToMaterialSelect() {
          var _this6 = this;
  
          var value = '';
          var optionsSelected = 'options selected';
          var itemsCount = this.valuesSelected.length;
  
          if (this.options.language.active && this.$toggleAll) {
            if (this.options.language.pl) {
              optionsSelected = this.options.language.pl.optionsSelected ? this.options.language.pl.optionsSelected : this.defaults.language.pl.optionsSelected;
            } else if (this.options.language.fr) {
              optionsSelected = this.options.language.fr.optionsSelected ? this.options.language.fr.optionsSelected : this.defaults.language.fr.optionsSelected;
            } else if (this.options.language.ge) {
              optionsSelected = this.options.language.ge.optionsSelected ? this.options.language.ge.optionsSelected : this.defaults.language.ge.optionsSelected;
            } else if (this.options.language.ar) {
              optionsSelected = this.options.language.ar.optionsSelected ? this.options.language.ar.optionsSelected : this.defaults.language.ar.optionsSelected;
            } else if (this.options.language.in) {
              optionsSelected = this.options.language.in.optionsSelected ? this.options.language.in.optionsSelected : this.defaults.language.in.optionsSelected;
            }
          }
  
          this.valuesSelected.map(function (el) {
            return value += ", ".concat(_this6.$nativeSelect.find('option').eq(el).text().replace(/  +/g, ' ').trim());
          });
          itemsCount >= 5 ? value = "".concat(itemsCount, " ").concat(optionsSelected) : value = value.substring(2);
          value.length === 0 && this.mainLabel.length === 0 ? value = this.$nativeSelect.find('option:disabled').eq(0).text() : null;
          value.length > 0 && !this.options.BSinputText ? this.mainLabel.addClass('active ') : this.mainLabel.removeClass('active');
          this.options.BSinputText ? this.mainLabel.css('top', '-7px') : null;
          this.$nativeSelect.siblings("".concat(this.options.BSinputText ? 'input.multi-bs-select' : 'input.select-dropdown')).val(value);
        }
      }, {
        key: "_randomUUID",
        value: function _randomUUID() {
          var d = new Date().getTime();
          return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c === 'x' ? r : r & 0x3 | 0x8).toString(16);
          });
        }
      }], [{
        key: "clearMutationObservers",
        value: function clearMutationObservers() {
          MaterialSelect.mutationObservers.forEach(function (observer) {
            observer.disconnect();
            observer.customStatus = 'stopped';
          });
        }
      }]);
  
      return MaterialSelect;
    }();
  
    $.fn.materialSelect = function (callback) {
      $(this).not('.browser-default').not('.custom-select').each(function () {
        var materialSelect = new MaterialSelect($(this), callback);
        materialSelect.init();
      });
    };
  
    $.fn.material_select = $.fn.materialSelect;
  
    (function (originalVal) {
      $.fn.val = function (value) {
        if (!arguments.length) {
          return originalVal.call(this);
        }
  
        if (this.data('stop-refresh') !== true && this.hasClass('mdb-select') && this.hasClass('initialized')) {
          MaterialSelect.clearMutationObservers();
          this.materialSelect({
            destroy: true
          });
          var ret = originalVal.call(this, value);
          this.materialSelect();
          return ret;
        }
  
        return originalVal.call(this, value);
      };
    })($.fn.val);
  })(jQuery);
  
  $('select').siblings('input.select-dropdown', 'input.multi-bs-select').on('mousedown', function (e) {
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
      if (e.clientX >= e.target.clientWidth || e.clientY >= e.target.clientHeight) {
        e.preventDefault();
      }
    }
  });
  /*!
   * pickadate.js v3.6.3, 2019/04/03
   * By Amsul, http://amsul.ca
   * Hosted on http://amsul.github.io/pickadate.js
   * Licensed under MIT
   */
  
  (function ( factory ) {
  
    // AMD.
    if ( typeof define == 'function' && define.amd )
        define( 'picker', ['jquery'], factory )
  
    // Node.js/browserify.
    else if ( typeof exports == 'object' )
        module.exports = factory( require('jquery') )
  
    // Browser globals.
    else this.Picker = factory( jQuery )
  
  }(function( $ ) {
  
  var $window = $( window )
  var $document = $( document )
  var $html = $( document.documentElement )
  var supportsTransitions = document.documentElement.style.transition != null
  
  
  /**
  * The picker constructor that creates a blank picker.
  */
  function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) {
  
    // If there’s no element, return the picker constructor.
    if ( !ELEMENT ) return PickerConstructor
  
  
    var
        IS_DEFAULT_THEME = false,
  
  
        // The state of the picker.
        STATE = {
            id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ),
            handlingOpen: false,
        },
  
  
        // Merge the defaults and options passed.
        SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {},
  
  
        // Merge the default classes with the settings classes.
        CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ),
  
  
        // The element node wrapper into a jQuery object.
        $ELEMENT = $( ELEMENT ),
  
  
        // Pseudo picker constructor.
        PickerInstance = function() {
            return this.start()
        },
  
  
        // The picker prototype.
        P = PickerInstance.prototype = {
  
            constructor: PickerInstance,
  
            $node: $ELEMENT,
  
  
            /**
             * Initialize everything
             */
            start: function() {
  
                // If it’s already started, do nothing.
                if ( STATE && STATE.start ) return P
  
  
                // Update the picker states.
                STATE.methods = {}
                STATE.start = true
                STATE.open = false
                STATE.type = ELEMENT.type
  
  
                // Confirm focus state, convert into text input to remove UA stylings,
                // and set as readonly to prevent keyboard popup.
                ELEMENT.autofocus = ELEMENT == getActiveElement()
                ELEMENT.readOnly = !SETTINGS.editable
                ELEMENT.id = ELEMENT.id || STATE.id
                if ( ELEMENT.type != 'text' ) {
                    ELEMENT.type = 'text'
                }
  
  
                // Create a new picker component with the settings.
                P.component = new COMPONENT(P, SETTINGS)
  
  
                // Create the picker root and then prepare it.
                P.$root = $( '<div class="' + CLASSES.picker + '" id="' + ELEMENT.id + '_root" />' )
                prepareElementRoot()
  
  
                // Create the picker holder and then prepare it.
                P.$holder = $( createWrappedComponent() ).appendTo( P.$root )
                prepareElementHolder()
  
  
                // If there’s a format for the hidden input element, create the element.
                if ( SETTINGS.formatSubmit ) {
                    prepareElementHidden()
                }
  
  
                // Prepare the input element.
                prepareElement()
  
  
                // Insert the hidden input as specified in the settings.
                if ( SETTINGS.containerHidden ) $( SETTINGS.containerHidden ).append( P._hidden )
                else $ELEMENT.after( P._hidden )
  
  
                // Insert the root as specified in the settings.
                if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root )
                else $ELEMENT.after( P.$root )
  
  
                // Bind the default component and settings events.
                P.on({
                    start: P.component.onStart,
                    render: P.component.onRender,
                    stop: P.component.onStop,
                    open: P.component.onOpen,
                    close: P.component.onClose,
                    set: P.component.onSet
                }).on({
                    start: SETTINGS.onStart,
                    render: SETTINGS.onRender,
                    stop: SETTINGS.onStop,
                    open: SETTINGS.onOpen,
                    close: SETTINGS.onClose,
                    set: SETTINGS.onSet
                })
  
  
                // Once we’re all set, check the theme in use.
                IS_DEFAULT_THEME = isUsingDefaultTheme( P.$holder[0] )
  
  
                // If the element has autofocus, open the picker.
                if ( ELEMENT.autofocus ) {
                    P.open()
                }
  
  
                // Trigger queued the “start” and “render” events.
                return P.trigger( 'start' ).trigger( 'render' )
            }, //start
  
  
            /**
             * Render a new picker
             */
            render: function( entireComponent ) {
  
                // Insert a new component holder in the root or box.
                if ( entireComponent ) {
                    P.$holder = $( createWrappedComponent() )
                    prepareElementHolder()
                    P.$root.html( P.$holder )
                }
                else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) )
  
                // Trigger the queued “render” events.
                return P.trigger( 'render' )
            }, //render
  
  
            /**
             * Destroy everything
             */
            stop: function() {
  
                // If it’s already stopped, do nothing.
                if ( !STATE.start ) return P
  
                // Then close the picker.
                P.close()
  
                // Remove the hidden field.
                if ( P._hidden ) {
                    P._hidden.parentNode.removeChild( P._hidden )
                }
  
                // Remove the root.
                P.$root.remove()
  
                // Remove the input class, remove the stored data, and unbind
                // the events (after a tick for IE - see `P.close`).
                $ELEMENT.removeClass( CLASSES.input ).removeData( NAME )
                setTimeout( function() {
                    $ELEMENT.off( '.' + STATE.id )
                }, 0)
  
                // Restore the element state
                ELEMENT.type = STATE.type
                ELEMENT.readOnly = false
  
                // Trigger the queued “stop” events.
                P.trigger( 'stop' )
  
                // Reset the picker states.
                STATE.methods = {}
                STATE.start = false
  
                return P
            }, //stop
  
  
            /**
             * Open up the picker
             */
            open: function( dontGiveFocus ) {
  
                // If it’s already open, do nothing.
                if ( STATE.open ) return P
  
                // Add the “active” class.
                $ELEMENT.addClass( CLASSES.active )
                aria( ELEMENT, 'expanded', true )
  
                // * A Firefox bug, when `html` has `overflow:hidden`, results in
                //   killing transitions :(. So add the “opened” state on the next tick.
                //   Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
                setTimeout( function() {
  
                    // Add the “opened” class to the picker root.
                    P.$root.addClass( CLASSES.opened )
                    aria( P.$root[0], 'hidden', false )
  
                }, 0 )
  
                // If we have to give focus, bind the element and doc events.
                if ( dontGiveFocus !== false ) {
  
                    // Set it as open.
                    STATE.open = true
  
                    // Prevent the page from scrolling.
                    if ( IS_DEFAULT_THEME ) {
                        $('body').
                            css( 'overflow', 'hidden' ).
                            css( 'padding-right', '+=' + getScrollbarWidth() )
                    }
  
                    // Pass focus to the root element’s jQuery object.
                    focusPickerOnceOpened()
  
                    // Bind the document events.
                    $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) {
                        // If the picker is currently midway through processing
                        // the opening sequence of events then don't handle clicks
                        // on any part of the DOM. This is caused by a bug in Chrome 73
                        // where a click event is being generated with the incorrect
                        // path in it.
                        // In short, if someone does a click that finishes after the
                        // new element is created then the path contains only the
                        // parent element and not the input element itself.
                        if (STATE.handlingOpen) {
                          return;
                        }
  
                        var target = getRealEventTarget( event, ELEMENT )
  
                        // If the target of the event is not the element, close the picker picker.
                        // * Don’t worry about clicks or focusins on the root because those don’t bubble up.
                        //   Also, for Firefox, a click on an `option` element bubbles up directly
                        //   to the doc. So make sure the target wasn't the doc.
                        // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling,
                        //   which causes the picker to unexpectedly close when right-clicking it. So make
                        //   sure the event wasn’t a right-click.
                        // * In Chrome 62 and up, password autofill causes a simulated focusin event which
                        //   closes the picker.
                        if ( ! event.isSimulated && target != ELEMENT && target != document && event.which != 3 ) {
  
                            // If the target was the holder that covers the screen,
                            // keep the element focused to maintain tabindex.
                            P.close( target === P.$holder[0] )
                        }
  
                    }).on( 'keydown.' + STATE.id, function( event ) {
  
                        var
                            // Get the keycode.
                            keycode = event.keyCode,
  
                            // Translate that to a selection change.
                            keycodeToMove = P.component.key[ keycode ],
  
                            // Grab the target.
                            target = getRealEventTarget( event, ELEMENT )
  
  
                        // On escape, close the picker and give focus.
                        if ( keycode == 27 ) {
                            P.close( true )
                        }
  
  
                        // Check if there is a key movement or “enter” keypress on the element.
                        else if ( target == P.$holder[0] && ( keycodeToMove || keycode == 13 ) ) {
  
                            // Prevent the default action to stop page movement.
                            event.preventDefault()
  
                            // Trigger the key movement action.
                            if ( keycodeToMove ) {
                                PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] )
                            }
  
                            // On “enter”, if the highlighted item isn’t disabled, set the value and close.
                            else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) {
                                P.set( 'select', P.component.item.highlight )
                                if ( SETTINGS.closeOnSelect ) {
                                    P.close( true )
                                }
                            }
                        }
  
  
                        // If the target is within the root and “enter” is pressed,
                        // prevent the default action and trigger a click on the target instead.
                        else if ( $.contains( P.$root[0], target ) && keycode == 13 ) {
                            event.preventDefault()
                            target.click()
                        }
                    })
                }
  
                // Trigger the queued “open” events.
                return P.trigger( 'open' )
            }, //open
  
  
            /**
             * Close the picker
             */
            close: function( giveFocus ) {
  
                // If we need to give focus, do it before changing states.
                if ( giveFocus ) {
                    if ( SETTINGS.editable ) {
                        ELEMENT.focus()
                    }
                    else {
                        // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
                        // The focus is triggered *after* the close has completed - causing it
                        // to open again. So unbind and rebind the event at the next tick.
                        P.$holder.off( 'focus.toOpen' ).focus()
                        setTimeout( function() {
                            P.$holder.on( 'focus.toOpen', handleFocusToOpenEvent )
                        }, 0 )
                    }
                }
  
                // Remove the “active” class.
                $ELEMENT.removeClass( CLASSES.active )
                aria( ELEMENT, 'expanded', false )
  
                // * A Firefox bug, when `html` has `overflow:hidden`, results in
                //   killing transitions :(. So remove the “opened” state on the next tick.
                //   Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
                setTimeout( function() {
  
                    // Remove the “opened” and “focused” class from the picker root.
                    P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused )
                    aria( P.$root[0], 'hidden', true )
  
                }, 0 )
  
                // If it’s already closed, do nothing more.
                if ( !STATE.open ) return P
  
                // Set it as closed.
                STATE.open = false
  
                // Allow the page to scroll.
                if ( IS_DEFAULT_THEME ) {
                    $('body').
                        css( 'overflow', '' ).
                        css( 'padding-right', '-=' + getScrollbarWidth() )
                }
  
                // Unbind the document events.
                $document.off( '.' + STATE.id )
  
                // Trigger the queued “close” events.
                return P.trigger( 'close' )
            }, //close
  
  
            /**
             * Clear the values
             */
            clear: function( options ) {
                return P.set( 'clear', null, options )
            }, //clear
  
  
            /**
             * Set something
             */
            set: function( thing, value, options ) {
  
                var thingItem, thingValue,
                    thingIsObject = $.isPlainObject( thing ),
                    thingObject = thingIsObject ? thing : {}
  
                // Make sure we have usable options.
                options = thingIsObject && $.isPlainObject( value ) ? value : options || {}
  
                if ( thing ) {
  
                    // If the thing isn’t an object, make it one.
                    if ( !thingIsObject ) {
                        thingObject[ thing ] = value
                    }
  
                    // Go through the things of items to set.
                    for ( thingItem in thingObject ) {
  
                        // Grab the value of the thing.
                        thingValue = thingObject[ thingItem ]
  
                        // First, if the item exists and there’s a value, set it.
                        if ( thingItem in P.component.item ) {
                            if ( thingValue === undefined ) thingValue = null
                            P.component.set( thingItem, thingValue, options )
                        }
  
                        // Then, check to update the element value and broadcast a change.
                        if ( ( thingItem == 'select' || thingItem == 'clear' ) && SETTINGS.updateInput ) {
                            $ELEMENT.
                                val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ).
                                trigger( 'change' )
                        }
                    }
  
                    // Render a new picker.
                    P.render()
                }
  
                // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`.
                return options.muted ? P : P.trigger( 'set', thingObject )
            }, //set
  
  
            /**
             * Get something
             */
            get: function( thing, format ) {
  
                // Make sure there’s something to get.
                thing = thing || 'value'
  
                // If a picker state exists, return that.
                if ( STATE[ thing ] != null ) {
                    return STATE[ thing ]
                }
  
                // Return the submission value, if that.
                if ( thing == 'valueSubmit' ) {
                    if ( P._hidden ) {
                        return P._hidden.value
                    }
                    thing = 'value'
                }
  
                // Return the value, if that.
                if ( thing == 'value' ) {
                    return ELEMENT.value
                }
  
                // Check if a component item exists, return that.
                if ( thing in P.component.item ) {
                    if ( typeof format == 'string' ) {
                        var thingValue = P.component.get( thing )
                        return thingValue ?
                            PickerConstructor._.trigger(
                                P.component.formats.toString,
                                P.component,
                                [ format, thingValue ]
                            ) : ''
                    }
                    return P.component.get( thing )
                }
            }, //get
  
  
  
            /**
             * Bind events on the things.
             */
            on: function( thing, method, internal ) {
  
                var thingName, thingMethod,
                    thingIsObject = $.isPlainObject( thing ),
                    thingObject = thingIsObject ? thing : {}
  
                if ( thing ) {
  
                    // If the thing isn’t an object, make it one.
                    if ( !thingIsObject ) {
                        thingObject[ thing ] = method
                    }
  
                    // Go through the things to bind to.
                    for ( thingName in thingObject ) {
  
                        // Grab the method of the thing.
                        thingMethod = thingObject[ thingName ]
  
                        // If it was an internal binding, prefix it.
                        if ( internal ) {
                            thingName = '_' + thingName
                        }
  
                        // Make sure the thing methods collection exists.
                        STATE.methods[ thingName ] = STATE.methods[ thingName ] || []
  
                        // Add the method to the relative method collection.
                        STATE.methods[ thingName ].push( thingMethod )
                    }
                }
  
                return P
            }, //on
  
  
  
            /**
             * Unbind events on the things.
             */
            off: function() {
                var i, thingName,
                    names = arguments;
                for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) {
                    thingName = names[i]
                    if ( thingName in STATE.methods ) {
                        delete STATE.methods[thingName]
                    }
                }
                return P
            },
  
  
            /**
             * Fire off method events.
             */
            trigger: function( name, data ) {
                var _trigger = function( name ) {
                    var methodList = STATE.methods[ name ]
                    if ( methodList ) {
                        methodList.map( function( method ) {
                            PickerConstructor._.trigger( method, P, [ data ] )
                        })
                    }
                }
                _trigger( '_' + name )
                _trigger( name )
                return P
            } //trigger
        } //PickerInstance.prototype
  
  
    /**
     * Wrap the picker holder components together.
     */
    function createWrappedComponent() {
  
        // Create a picker wrapper holder
        return PickerConstructor._.node( 'div',
  
            // Create a picker wrapper node
            PickerConstructor._.node( 'div',
  
                // Create a picker frame
                PickerConstructor._.node( 'div',
  
                    // Create a picker box node
                    PickerConstructor._.node( 'div',
  
                        // Create the components nodes.
                        P.component.nodes( STATE.open ),
  
                        // The picker box class
                        CLASSES.box
                    ),
  
                    // Picker wrap class
                    CLASSES.wrap
                ),
  
                // Picker frame class
                CLASSES.frame
            ),
  
            // Picker holder class
            CLASSES.holder,
  
            'tabindex="-1"'
        ) //endreturn
    } //createWrappedComponent
  
    /**
     * Prepare the input element with all bindings.
     */
    function prepareElement() {
  
        $ELEMENT.
  
            // Store the picker data by component name.
            data(NAME, P).
  
            // Add the “input” class name.
            addClass(CLASSES.input).
  
            // If there’s a `data-value`, update the value of the element.
            val( $ELEMENT.data('value') ?
                P.get('select', SETTINGS.format) :
                ELEMENT.value
            ).
  
            // On focus/click, open the picker.
            on( 'focus.' + STATE.id + ' click.' + STATE.id,
            debounce(function(event) {
                event.preventDefault()
                P.open()
            }, 100))
  
            // Mousedown handler to capture when the user starts interacting
            // with the picker. This is used in working around a bug in Chrome 73.
            .on('mousedown', function() {
              STATE.handlingOpen = true;
              var handler = function() {
                // By default mouseup events are fired before a click event.
                // By using a timeout we can force the mouseup to be handled
                // after the corresponding click event is handled.
                setTimeout(function() {
                  $(document).off('mouseup', handler);
                  STATE.handlingOpen = false;
                }, 0);
              };
              $(document).on('mouseup', handler);
            });
  
  
        // Only bind keydown events if the element isn’t editable.
        if ( !SETTINGS.editable ) {
  
            $ELEMENT.
  
                // Handle keyboard event based on the picker being opened or not.
                on( 'keydown.' + STATE.id, handleKeydownEvent )
        }
  
  
        // Update the aria attributes.
        aria(ELEMENT, {
            haspopup: true,
            expanded: false,
            readonly: false,
            owns: ELEMENT.id + '_root'
        })
    }
  
  
    /**
     * Prepare the root picker element with all bindings.
     */
    function prepareElementRoot() {
        aria( P.$root[0], 'hidden', true )
    }
  
  
     /**
      * Prepare the holder picker element with all bindings.
      */
    function prepareElementHolder() {
  
        P.$holder.
  
            on({
  
                // For iOS8.
                keydown: handleKeydownEvent,
  
                'focus.toOpen': handleFocusToOpenEvent,
  
                blur: function() {
                    // Remove the “target” class.
                    $ELEMENT.removeClass( CLASSES.target )
                },
  
                // When something within the holder is focused, stop from bubbling
                // to the doc and remove the “focused” state from the root.
                focusin: function( event ) {
                    P.$root.removeClass( CLASSES.focused )
                    event.stopPropagation()
                },
  
                // When something within the holder is clicked, stop it
                // from bubbling to the doc.
                'mousedown click': function( event ) {
  
                    var target = getRealEventTarget( event, ELEMENT )
  
                    // Make sure the target isn’t the root holder so it can bubble up.
                    if ( target != P.$holder[0] ) {
  
                        event.stopPropagation()
  
                        // * For mousedown events, cancel the default action in order to
                        //   prevent cases where focus is shifted onto external elements
                        //   when using things like jQuery mobile or MagnificPopup (ref: #249 & #120).
                        //   Also, for Firefox, don’t prevent action on the `option` element.
                        if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) {
  
                            event.preventDefault()
  
                            // Re-focus onto the holder so that users can click away
                            // from elements focused within the picker.
                            P.$holder.eq(0).focus()
                        }
                    }
                }
  
            }).
  
            // If there’s a click on an actionable element, carry out the actions.
            on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() {
  
                var $target = $( this ),
                    targetData = $target.data(),
                    targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ),
  
                    // * For IE, non-focusable elements can be active elements as well
                    //   (http://stackoverflow.com/a/2684561).
                    activeElement = getActiveElement()
                    activeElement = activeElement && ( (activeElement.type || activeElement.href ) ? activeElement : null);
  
                // If it’s disabled or nothing inside is actively focused, re-focus the element.
                if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) {
                    P.$holder.eq(0).focus()
                }
  
                // If something is superficially changed, update the `highlight` based on the `nav`.
                if ( !targetDisabled && targetData.nav ) {
                    P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } )
                }
  
                // If something is picked, set `select` then close with focus.
                else if ( !targetDisabled && 'pick' in targetData ) {
                    P.set( 'select', targetData.pick )
                    if ( SETTINGS.closeOnSelect ) {
                        P.close( true )
                    }
                }
  
                // If a “clear” button is pressed, empty the values and close with focus.
                else if ( targetData.clear ) {
                    P.clear()
                    if ( SETTINGS.closeOnClear ) {
                        P.close( true )
                    }
                }
  
                else if ( targetData.close ) {
                    P.close( true )
                }
  
            }) //P.$holder
  
    }
  
  
     /**
      * Prepare the hidden input element along with all bindings.
      */
    function prepareElementHidden() {
  
        var name
  
        if ( SETTINGS.hiddenName === true ) {
            name = ELEMENT.name
            ELEMENT.name = ''
        }
        else {
            name = [
                typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '',
                typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit'
            ]
            name = name[0] + ELEMENT.name + name[1]
        }
  
        P._hidden = $(
            '<input ' +
            'type=hidden ' +
  
            // Create the name using the original input’s with a prefix and suffix.
            'name="' + name + '"' +
  
            // If the element has a value, set the hidden value as well.
            (
                $ELEMENT.data('value') || ELEMENT.value ?
                    ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' :
                    ''
            ) +
            '>'
        )[0]
  
        $ELEMENT.
  
            // If the value changes, update the hidden input with the correct format.
            on('change.' + STATE.id, function() {
                P._hidden.value = ELEMENT.value ?
                    P.get('select', SETTINGS.formatSubmit) :
                    ''
            })
    }
  
  
    // Wait for transitions to end before focusing the holder. Otherwise, while
    // using the `container` option, the view jumps to the container.
    function focusPickerOnceOpened() {
  
        if (IS_DEFAULT_THEME && supportsTransitions) {
            P.$holder.find('.' + CLASSES.frame).one('transitionend', function() {
                P.$holder.eq(0).focus()
            })
        }
        else {
            setTimeout(function() {
                P.$holder.eq(0).focus()
            }, 0)
        }
    }
  
  
    function handleFocusToOpenEvent(event) {
  
        // Stop the event from propagating to the doc.
        event.stopPropagation()
  
        // Add the “target” class.
        $ELEMENT.addClass( CLASSES.target )
  
        // Add the “focused” class to the root.
        P.$root.addClass( CLASSES.focused )
  
        // And then finally open the picker.
        P.open()
    }
  
  
    // For iOS8.
    function handleKeydownEvent( event ) {
  
        var keycode = event.keyCode,
  
            // Check if one of the delete keys was pressed.
            isKeycodeDelete = /^(8|46)$/.test(keycode)
  
        // For some reason IE clears the input value on “escape”.
        if ( keycode == 27 ) {
            P.close( true )
            return false
        }
  
        // Check if `space` or `delete` was pressed or the picker is closed with a key movement.
        if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) {
  
            // Prevent it from moving the page and bubbling to doc.
            event.preventDefault()
            event.stopPropagation()
  
            // If `delete` was pressed, clear the values and close the picker.
            // Otherwise open the picker.
            if ( isKeycodeDelete ) { P.clear().close() }
            else { P.open() }
        }
    }
  
  
    // Return a new picker instance.
    return new PickerInstance()
  } //PickerConstructor
  
  
  
  /**
  * The default classes and prefix to use for the HTML classes.
  */
  PickerConstructor.klasses = function( prefix ) {
    prefix = prefix || 'picker'
    return {
  
        picker: prefix,
        opened: prefix + '--opened',
        focused: prefix + '--focused',
  
        input: prefix + '__input',
        active: prefix + '__input--active',
        target: prefix + '__input--target',
  
        holder: prefix + '__holder',
  
        frame: prefix + '__frame',
        wrap: prefix + '__wrap',
  
        box: prefix + '__box'
    }
  } //PickerConstructor.klasses
  
  
  
  /**
  * Check if the default theme is being used.
  */
  function isUsingDefaultTheme( element ) {
  
    var theme,
        prop = 'position'
  
    // For IE.
    if ( element.currentStyle ) {
        theme = element.currentStyle[prop]
    }
  
    // For normal browsers.
    else if ( window.getComputedStyle ) {
        theme = getComputedStyle( element )[prop]
    }
  
    return theme == 'fixed'
  }
  
  
  
  /**
  * Get the width of the browser’s scrollbar.
  * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js
  */
  function getScrollbarWidth() {
  
    if ( $html.height() <= $window.height() ) {
        return 0
    }
  
    var $outer = $( '<div style="visibility:hidden;width:100px" />' ).
        appendTo( 'body' )
  
    // Get the width without scrollbars.
    var widthWithoutScroll = $outer[0].offsetWidth
  
    // Force adding scrollbars.
    $outer.css( 'overflow', 'scroll' )
  
    // Add the inner div.
    var $inner = $( '<div style="width:100%" />' ).appendTo( $outer )
  
    // Get the width with scrollbars.
    var widthWithScroll = $inner[0].offsetWidth
  
    // Remove the divs.
    $outer.remove()
  
    // Return the difference between the widths.
    return widthWithoutScroll - widthWithScroll
  }
  
  
  
  /**
  * Get the target element from the event.
  * If ELEMENT is supplied and present in the event path (ELEMENT is ancestor of the target),
  * returns ELEMENT instead
  */
  function getRealEventTarget( event, ELEMENT ) {
  
    var path = []
  
    if ( event.path ) {
        path = event.path
    }
  
    if ( event.originalEvent && event.originalEvent.path ) {
        path = event.originalEvent.path
    }
  
    if ( path && path.length > 0 ) {
        if ( ELEMENT && path.indexOf( ELEMENT ) >= 0 ) {
            return ELEMENT
        } else {
            return path[0]
        }
    }
  
    return event.target
  }
  
  // taken from https://davidwalsh.name/javascript-debounce-function
  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
  }
  
  /**
  * PickerConstructor helper methods.
  */
  PickerConstructor._ = {
  
    /**
     * Create a group of nodes. Expects:
     * `
        {
            min:    {Integer},
            max:    {Integer},
            i:      {Integer},
            node:   {String},
            item:   {Function}
        }
     * `
     */
    group: function( groupObject ) {
  
        var
            // Scope for the looped object
            loopObjectScope,
  
            // Create the nodes list
            nodesList = '',
  
            // The counter starts from the `min`
            counter = PickerConstructor._.trigger( groupObject.min, groupObject )
  
  
        // Loop from the `min` to `max`, incrementing by `i`
        for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) {
  
            // Trigger the `item` function within scope of the object
            loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] )
  
            // Splice the subgroup and create nodes out of the sub nodes
            nodesList += PickerConstructor._.node(
                groupObject.node,
                loopObjectScope[ 0 ],   // the node
                loopObjectScope[ 1 ],   // the classes
                loopObjectScope[ 2 ]    // the attributes
            )
        }
  
        // Return the list of nodes
        return nodesList
    }, //group
  
  
    /**
     * Create a dom node string
     */
    node: function( wrapper, item, klass, attribute ) {
  
        // If the item is false-y, just return an empty string
        if ( !item ) return ''
  
        // If the item is an array, do a join
        item = $.isArray( item ) ? item.join( '' ) : item
  
        // Check for the class
        klass = klass ? ' class="' + klass + '"' : ''
  
        // Check for any attributes
        attribute = attribute ? ' ' + attribute : ''
  
        // Return the wrapped item
        return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>'
    }, //node
  
  
    /**
     * Lead numbers below 10 with a zero.
     */
    lead: function( number ) {
        return ( number < 10 ? '0': '' ) + number
    },
  
  
    /**
     * Trigger a function otherwise return the value.
     */
    trigger: function( callback, scope, args ) {
        return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback
    },
  
  
    /**
     * If the second character is a digit, length is 2 otherwise 1.
     */
    digits: function( string ) {
        return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1
    },
  
  
    /**
     * Tell if something is a date object.
     */
    isDate: function( value ) {
        return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() )
    },
  
  
    /**
     * Tell if something is an integer.
     */
    isInteger: function( value ) {
        return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
    },
  
  
    /**
     * Create ARIA attribute strings.
     */
    ariaAttr: ariaAttr
  } //PickerConstructor._
  
  
  
  /**
  * Extend the picker with a component and defaults.
  */
  PickerConstructor.extend = function( name, Component ) {
  
    // Extend jQuery.
    $.fn[ name ] = function( options, action ) {
  
        // Grab the component data.
        var componentData = this.data( name )
  
        // If the picker is requested, return the data object.
        if ( options == 'picker' ) {
            return componentData
        }
  
        // If the component data exists and `options` is a string, carry out the action.
        if ( componentData && typeof options == 'string' ) {
            return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] )
        }
  
        // Otherwise go through each matched element and if the component
        // doesn’t exist, create a new picker using `this` element
        // and merging the defaults and options with a deep copy.
        return this.each( function() {
            var $this = $( this )
            if ( !$this.data( name ) ) {
                new PickerConstructor( this, name, Component, options )
            }
        })
    }
  
    // Set the defaults.
    $.fn[ name ].defaults = Component.defaults
  } //PickerConstructor.extend
  
  
  
  function aria(element, attribute, value) {
    if ( $.isPlainObject(attribute) ) {
        for ( var key in attribute ) {
            ariaSet(element, key, attribute[key])
        }
    }
    else {
        ariaSet(element, attribute, value)
    }
  }
  function ariaSet(element, attribute, value) {
    element.setAttribute(
        (attribute == 'role' ? '' : 'aria-') + attribute,
        value
    )
  }
  function ariaAttr(attribute, data) {
    if ( !$.isPlainObject(attribute) ) {
        attribute = { attribute: data }
    }
    data = ''
    for ( var key in attribute ) {
        var attr = (key == 'role' ? '' : 'aria-') + key,
            attrVal = attribute[key]
        data += attrVal == null ? '' : attr + '="' + attribute[key] + '"'
    }
    return data
  }
  
  // IE8 bug throws an error for activeElements within iframes.
  function getActiveElement() {
    try {
        return document.activeElement
    } catch ( err ) { }
  }
  
  
  
  // Expose the picker constructor.
  return PickerConstructor
  
  
  }));
  
  /*!
   * Date picker for pickadate.js v3.6.3
   * http://amsul.github.io/pickadate.js/date.htm
   */
  
  (function (factory) {
  
    // AMD.
    if (typeof define == 'function' && define.amd)
      define(['picker', 'jquery'], factory)
  
    // Node.js/browserify.
    else if (typeof exports == 'object')
      module.exports = factory(require('./picker.js'), require('jquery'))
  
    // Browser globals.
    else factory(Picker, jQuery)
  
  }(function (Picker, $) {
  
  
    /**
     * Globals and constants
     */
    var DAYS_IN_WEEK = 7,
      WEEKS_IN_CALENDAR = 6,
      _ = Picker._
  
  
  
    /**
     * The date picker constructor
     */
    function DatePicker(picker, settings) {
  
      var calendar = this,
        element = picker.$node[0],
        elementValue = element.value,
        elementDataValue = picker.$node.data('value'),
        valueString = elementDataValue || elementValue,
        formatString = elementDataValue ? settings.formatSubmit : settings.format,
        isRTL = function () {
  
          return element.currentStyle ?
  
            // For IE.
            element.currentStyle.direction == 'rtl' :
  
            // For normal browsers.
            getComputedStyle(picker.$root[0]).direction == 'rtl'
        }
  
      calendar.settings = settings
      calendar.$node = picker.$node
  
      // The queue of methods that will be used to build item objects.
      calendar.queue = {
        min: 'measure create',
        max: 'measure create',
        now: 'now create',
        select: 'parse create validate',
        highlight: 'parse navigate create validate',
        view: 'parse create validate viewset',
        disable: 'deactivate',
        enable: 'activate'
      }
  
      // The component's item object.
      calendar.item = {}
  
      calendar.item.clear = null
      calendar.item.disable = (settings.disable || []).slice(0)
      calendar.item.enable = -(function (collectionDisabled) {
        return collectionDisabled[0] === true ? collectionDisabled.shift() : -1
      })(calendar.item.disable)
  
      calendar.
      set('min', settings.min).
      set('max', settings.max).
      set('now')
  
      // When there’s a value, set the `select`, which in turn
      // also sets the `highlight` and `view`.
      if (valueString) {
        calendar.set('select', valueString, {
          format: formatString,
          defaultValue: true
        })
      }
  
      // If there’s no value, default to highlighting “today”.
      else {
        calendar.
        set('select', null).
        set('highlight', calendar.item.now)
      }
  
  
      // The keycode to movement mapping.
      calendar.key = {
        40: 7, // Down
        38: -7, // Up
        39: function () {
          return isRTL() ? -1 : 1
        }, // Right
        37: function () {
          return isRTL() ? 1 : -1
        }, // Left
        go: function (timeChange) {
          var highlightedObject = calendar.item.highlight,
            targetDate = new Date(highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange)
          calendar.set(
            'highlight',
            targetDate, {
              interval: timeChange
            }
          )
          this.render()
        }
      }
  
  
      // Bind some picker events.
      picker.
      on('render', function () {
        picker.$root.find('.' + settings.klass.selectMonth).on('change', function () {
          var value = this.value
          if (value) {
            picker.set('highlight', [picker.get('view').year, value, picker.get('highlight').date])
            picker.$root.find('.' + settings.klass.selectMonth).trigger('focus')
          }
        })
        picker.$root.find('.' + settings.klass.selectYear).on('change', function () {
          var value = this.value
          if (value) {
            picker.set('highlight', [value, picker.get('view').month, picker.get('highlight').date])
            picker.$root.find('.' + settings.klass.selectYear).trigger('focus')
          }
        })
      }, 1).
      on('open', function () {
        var includeToday = ''
        if (calendar.disabled(calendar.get('now'))) {
          includeToday = ':not(.' + settings.klass.buttonToday + ')'
        }
        picker.$root.find('button' + includeToday + ', select').attr('disabled', false)
      }, 1).
      on('close', function () {
        picker.$root.find('button, select').attr('disabled', true)
      }, 1)
  
    } //DatePicker
  
  
    /**
     * Set a datepicker item object.
     */
    DatePicker.prototype.set = function (type, value, options) {
  
      var calendar = this,
        calendarItem = calendar.item
  
      // If the value is `null` just set it immediately.
      if (value === null) {
        if (type == 'clear') type = 'select'
        calendarItem[type] = value
        return calendar
      }
  
      // Otherwise go through the queue of methods, and invoke the functions.
      // Update this as the time unit, and set the final value as this item.
      // * In the case of `enable`, keep the queue but set `disable` instead.
      //   And in the case of `flip`, keep the queue but set `enable` instead.
      calendarItem[(type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type)] = calendar.queue[type].split(' ').map(function (method) {
        value = calendar[method](type, value, options)
        return value
      }).pop()
  
      // Check if we need to cascade through more updates.
      if (type == 'select') {
        calendar.set('highlight', calendarItem.select, options)
      } else if (type == 'highlight') {
        calendar.set('view', calendarItem.highlight, options)
      } else if (type.match(/^(flip|min|max|disable|enable)$/)) {
        if (calendarItem.select && calendar.disabled(calendarItem.select)) {
          calendar.set('select', calendarItem.select, options)
        }
        if (calendarItem.highlight && calendar.disabled(calendarItem.highlight)) {
          calendar.set('highlight', calendarItem.highlight, options)
        }
      }
  
      return calendar
    } //DatePicker.prototype.set
  
  
    /**
     * Get a datepicker item object.
     */
    DatePicker.prototype.get = function (type) {
      return this.item[type]
    } //DatePicker.prototype.get
  
  
    /**
     * Create a picker date object.
     */
    DatePicker.prototype.create = function (type, value, options) {
  
      var isInfiniteValue,
        calendar = this
  
      // If there’s no value, use the type as the value.
      value = value === undefined ? type : value
  
  
      // If it’s infinity, update the value.
      if (value == -Infinity || value == Infinity) {
        isInfiniteValue = value
      }
  
      // If it’s an object, use the native date object.
      else if ($.isPlainObject(value) && _.isInteger(value.pick)) {
        value = value.obj
      }
  
      // If it’s an array, convert it into a date and make sure
      // that it’s a valid date – otherwise default to today.
      else if ($.isArray(value)) {
        value = new Date(value[0], value[1], value[2])
        value = _.isDate(value) ? value : calendar.create().obj
      }
  
      // If it’s a number or date object, make a normalized date.
      else if (_.isInteger(value) || _.isDate(value)) {
        value = calendar.normalize(new Date(value), options)
      }
  
      // If it’s a literal true or any other case, set it to now.
      else /*if ( value === true )*/ {
        value = calendar.now(type, value, options)
      }
  
      // Return the compiled object.
      return {
        year: isInfiniteValue || value.getFullYear(),
        month: isInfiniteValue || value.getMonth(),
        date: isInfiniteValue || value.getDate(),
        day: isInfiniteValue || value.getDay(),
        obj: isInfiniteValue || value,
        pick: isInfiniteValue || value.getTime()
      }
    } //DatePicker.prototype.create
  
  
    /**
     * Create a range limit object using an array, date object,
     * literal “true”, or integer relative to another time.
     */
    DatePicker.prototype.createRange = function (from, to) {
  
      var calendar = this,
        createDate = function (date) {
          if (date === true || $.isArray(date) || _.isDate(date)) {
            return calendar.create(date)
          }
          return date
        }
  
      // Create objects if possible.
      if (!_.isInteger(from)) {
        from = createDate(from)
      }
      if (!_.isInteger(to)) {
        to = createDate(to)
      }
  
      // Create relative dates.
      if (_.isInteger(from) && $.isPlainObject(to)) {
        from = [to.year, to.month, to.date + from];
      } else if (_.isInteger(to) && $.isPlainObject(from)) {
        to = [from.year, from.month, from.date + to];
      }
  
      return {
        from: createDate(from),
        to: createDate(to)
      }
    } //DatePicker.prototype.createRange
  
  
    /**
     * Check if a date unit falls within a date range object.
     */
    DatePicker.prototype.withinRange = function (range, dateUnit) {
      range = this.createRange(range.from, range.to)
      return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick
    }
  
  
    /**
     * Check if two date range objects overlap.
     */
    DatePicker.prototype.overlapRanges = function (one, two) {
  
      var calendar = this
  
      // Convert the ranges into comparable dates.
      one = calendar.createRange(one.from, one.to)
      two = calendar.createRange(two.from, two.to)
  
      return calendar.withinRange(one, two.from) || calendar.withinRange(one, two.to) ||
        calendar.withinRange(two, one.from) || calendar.withinRange(two, one.to)
    }
  
  
    /**
     * Get the date today.
     */
    DatePicker.prototype.now = function (type, value, options) {
      value = new Date()
      if (options && options.rel) {
        value.setDate(value.getDate() + options.rel)
      }
      return this.normalize(value, options)
    }
  
  
    /**
     * Navigate to next/prev month.
     */
    DatePicker.prototype.navigate = function (type, value, options) {
  
      var targetDateObject,
        targetYear,
        targetMonth,
        targetDate,
        isTargetArray = $.isArray(value),
        isTargetObject = $.isPlainObject(value),
        viewsetObject = this.item.view
      /*,
            safety = 100*/
  
  
      if (isTargetArray || isTargetObject) {
  
        if (isTargetObject) {
          targetYear = value.year
          targetMonth = value.month
          targetDate = value.date
        } else {
          targetYear = +value[0]
          targetMonth = +value[1]
          targetDate = +value[2]
        }
  
        // If we’re navigating months but the view is in a different
        // month, navigate to the view’s year and month.
        if (options && options.nav && viewsetObject && viewsetObject.month !== targetMonth) {
          targetYear = viewsetObject.year
          targetMonth = viewsetObject.month
        }
  
        // Figure out the expected target year and month.
        targetDateObject = new Date(targetYear, targetMonth + (options && options.nav ? options.nav : 0), 1)
        targetYear = targetDateObject.getFullYear()
        targetMonth = targetDateObject.getMonth()
  
        // If the month we’re going to doesn’t have enough days,
        // keep decreasing the date until we reach the month’s last date.
        while ( /*safety &&*/ new Date(targetYear, targetMonth, targetDate).getMonth() !== targetMonth) {
          targetDate -= 1
          /*safety -= 1
          if ( !safety ) {
              throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.'
          }*/
        }
  
        value = [targetYear, targetMonth, targetDate]
      }
  
      return value
    } //DatePicker.prototype.navigate
  
  
    /**
     * Normalize a date by setting the hours to midnight.
     */
    DatePicker.prototype.normalize = function (value /*, options*/ ) {
      value.setHours(0, 0, 0, 0)
      return value
    }
  
  
    /**
     * Measure the range of dates.
     */
    DatePicker.prototype.measure = function (type, value /*, options*/ ) {
  
      var calendar = this
  
      // If it's an integer, get a date relative to today.
      if (_.isInteger(value)) {
        value = calendar.now(type, value, {
          rel: value
        })
      }
  
      // If it’s anything false-y, remove the limits.
      else if (!value) {
        value = type == 'min' ? -Infinity : Infinity
      }
  
      // If it’s a string, parse it.
      else if (typeof value == 'string') {
        value = calendar.parse(type, value)
      }
  
      return value
    } ///DatePicker.prototype.measure
  
  
    /**
     * Create a viewset object based on navigation.
     */
    DatePicker.prototype.viewset = function (type, dateObject /*, options*/ ) {
      return this.create([dateObject.year, dateObject.month, 1])
    }
  
  
    /**
     * Validate a date as enabled and shift if needed.
     */
    DatePicker.prototype.validate = function (type, dateObject, options) {
  
      var calendar = this,
  
        // Keep a reference to the original date.
        originalDateObject = dateObject,
  
        // Make sure we have an interval.
        interval = options && options.interval ? options.interval : 1,
  
        // Check if the calendar enabled dates are inverted.
        isFlippedBase = calendar.item.enable === -1,
  
        // Check if we have any enabled dates after/before now.
        hasEnabledBeforeTarget, hasEnabledAfterTarget,
  
        // The min & max limits.
        minLimitObject = calendar.item.min,
        maxLimitObject = calendar.item.max,
  
        // Check if we’ve reached the limit during shifting.
        reachedMin, reachedMax,
  
        // Check if the calendar is inverted and at least one weekday is enabled.
        hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter(function (value) {
  
          // If there’s a date, check where it is relative to the target.
          if ($.isArray(value)) {
            var dateTime = calendar.create(value).pick
            if (dateTime < dateObject.pick) hasEnabledBeforeTarget = true
            else if (dateTime > dateObject.pick) hasEnabledAfterTarget = true
          }
  
          // Return only integers for enabled weekdays.
          return _.isInteger(value)
        }).length
      /*,
  
            safety = 100*/
  
  
  
      // Cases to validate for:
      // [1] Not inverted and date disabled.
      // [2] Inverted and some dates enabled.
      // [3] Not inverted and out of range.
      //
      // Cases to **not** validate for:
      // • Navigating months.
      // • Not inverted and date enabled.
      // • Inverted and all dates disabled.
      // • ..and anything else.
      if (!options || (!options.nav && !options.defaultValue))
        if (
          /* 1 */
          (!isFlippedBase && calendar.disabled(dateObject)) ||
          /* 2 */
          (isFlippedBase && calendar.disabled(dateObject) && (hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget)) ||
          /* 3 */
          (!isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick))
        ) {
  
  
          // When inverted, flip the direction if there aren’t any enabled weekdays
          // and there are no enabled dates in the direction of the interval.
          if (isFlippedBase && !hasEnabledWeekdays && ((!hasEnabledAfterTarget && interval > 0) || (!hasEnabledBeforeTarget && interval < 0))) {
            interval *= -1
          }
  
  
          // Keep looping until we reach an enabled date.
          while ( /*safety &&*/ calendar.disabled(dateObject)) {
  
            /*safety -= 1
            if ( !safety ) {
                throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.'
            }*/
  
  
            // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval.
            if (Math.abs(interval) > 1 && (dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month)) {
              dateObject = originalDateObject
              interval = interval > 0 ? 1 : -1
            }
  
  
            // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit.
            if (dateObject.pick <= minLimitObject.pick) {
              reachedMin = true
              interval = 1
              dateObject = calendar.create([
                minLimitObject.year,
                minLimitObject.month,
                minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1)
              ])
            } else if (dateObject.pick >= maxLimitObject.pick) {
              reachedMax = true
              interval = -1
              dateObject = calendar.create([
                maxLimitObject.year,
                maxLimitObject.month,
                maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1)
              ])
            }
  
  
            // If we’ve reached both limits, just break out of the loop.
            if (reachedMin && reachedMax) {
              break
            }
  
  
            // Finally, create the shifted date using the interval and keep looping.
            dateObject = calendar.create([dateObject.year, dateObject.month, dateObject.date + interval])
          }
  
        } //endif
  
  
      // Return the date object settled on.
      return dateObject
    } //DatePicker.prototype.validate
  
  
    /**
     * Check if a date is disabled.
     */
    DatePicker.prototype.disabled = function (dateToVerify) {
  
      var
        calendar = this,
  
        // Filter through the disabled dates to check if this is one.
        isDisabledMatch = calendar.item.disable.filter(function (dateToDisable) {
  
          // If the date is a number, match the weekday with 0index and `firstDay` check.
          if (_.isInteger(dateToDisable)) {
            return dateToVerify.day === (calendar.settings.firstDay ? dateToDisable : dateToDisable - 1) % 7
          }
  
          // If it’s an array or a native JS date, create and match the exact date.
          if ($.isArray(dateToDisable) || _.isDate(dateToDisable)) {
            return dateToVerify.pick === calendar.create(dateToDisable).pick
          }
  
          // If it’s an object, match a date within the “from” and “to” range.
          if ($.isPlainObject(dateToDisable)) {
            return calendar.withinRange(dateToDisable, dateToVerify)
          }
        })
  
      // If this date matches a disabled date, confirm it’s not inverted.
      isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function (dateToDisable) {
        return $.isArray(dateToDisable) && dateToDisable[3] == 'inverted' ||
          $.isPlainObject(dateToDisable) && dateToDisable.inverted
      }).length
  
      // Check the calendar “enabled” flag and respectively flip the
      // disabled state. Then also check if it’s beyond the min/max limits.
      return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch ||
        dateToVerify.pick < calendar.item.min.pick ||
        dateToVerify.pick > calendar.item.max.pick
  
    } //DatePicker.prototype.disabled
  
  
    /**
     * Parse a string into a usable type.
     */
    DatePicker.prototype.parse = function (type, value, options) {
  
      var calendar = this,
        parsingObject = {}
  
      // If it’s already parsed, we’re good.
      if (!value || typeof value != 'string') {
        return value
      }
  
      // We need a `.format` to parse the value with.
      if (!(options && options.format)) {
        options = options || {}
        options.format = calendar.settings.format
      }
  
      // Convert the format into an array and then map through it.
      calendar.formats.toArray(options.format).map(function (label) {
  
        var
          // Grab the formatting label.
          formattingLabel = calendar.formats[label],
  
          // The format length is from the formatting label function or the
          // label length without the escaping exclamation (!) mark.
          formatLength = formattingLabel ? _.trigger(formattingLabel, calendar, [value, parsingObject]) : label.replace(/^!/, '').length
  
        // If there's a format label, split the value up to the format length.
        // Then add it to the parsing object with appropriate label.
        if (formattingLabel) {
          parsingObject[label] = value.substr(0, formatLength)
        }
  
        // Update the value as the substring from format length to end.
        value = value.substr(formatLength)
      })
  
      // Compensate for month 0index.
      return [
        parsingObject.yyyy || parsingObject.yy,
        +(parsingObject.mm || parsingObject.m) - 1,
        parsingObject.dd || parsingObject.d
      ]
    } //DatePicker.prototype.parse
  
  
    /**
     * Various formats to display the object in.
     */
    DatePicker.prototype.formats = (function () {
  
      // Return the length of the first word in a collection.
      function getWordLengthFromCollection(string, collection, dateObject) {
  
        // Grab the first word from the string.
        // Regex pattern from http://stackoverflow.com/q/150033
        var word = string.match(/[^\x00-\x7F]+|\w+/)[0]
  
        // If there's no month index, add it to the date object
        if (!dateObject.mm && !dateObject.m) {
          dateObject.m = collection.indexOf(word) + 1
        }
  
        // Return the length of the word.
        return word.length
      }
  
      // Get the length of the first word in a string.
      function getFirstWordLength(string) {
        return string.match(/\w+/)[0].length
      }
  
      return {
  
        d: function (string, dateObject) {
  
          // If there's string, then get the digits length.
          // Otherwise return the selected date.
          return string ? _.digits(string) : dateObject.date
        },
        dd: function (string, dateObject) {
  
          // If there's a string, then the length is always 2.
          // Otherwise return the selected date with a leading zero.
          return string ? 2 : _.lead(dateObject.date)
        },
        ddd: function (string, dateObject) {
  
          // If there's a string, then get the length of the first word.
          // Otherwise return the short selected weekday.
          return string ? getFirstWordLength(string) : this.settings.weekdaysShort[dateObject.day]
        },
        dddd: function (string, dateObject) {
  
          // If there's a string, then get the length of the first word.
          // Otherwise return the full selected weekday.
          return string ? getFirstWordLength(string) : this.settings.weekdaysFull[dateObject.day]
        },
        m: function (string, dateObject) {
  
          // If there's a string, then get the length of the digits
          // Otherwise return the selected month with 0index compensation.
          return string ? _.digits(string) : dateObject.month + 1
        },
        mm: function (string, dateObject) {
  
          // If there's a string, then the length is always 2.
          // Otherwise return the selected month with 0index and leading zero.
          return string ? 2 : _.lead(dateObject.month + 1)
        },
        mmm: function (string, dateObject) {
  
          var collection = this.settings.monthsShort
  
          // If there's a string, get length of the relevant month from the short
          // months collection. Otherwise return the selected month from that collection.
          return string ? getWordLengthFromCollection(string, collection, dateObject) : collection[dateObject.month]
        },
        mmmm: function (string, dateObject) {
  
          var collection = this.settings.monthsFull
  
          // If there's a string, get length of the relevant month from the full
          // months collection. Otherwise return the selected month from that collection.
          return string ? getWordLengthFromCollection(string, collection, dateObject) : collection[dateObject.month]
        },
        yy: function (string, dateObject) {
  
          // If there's a string, then the length is always 2.
          // Otherwise return the selected year by slicing out the first 2 digits.
          return string ? 2 : ('' + dateObject.year).slice(2)
        },
        yyyy: function (string, dateObject) {
  
          // If there's a string, then the length is always 4.
          // Otherwise return the selected year.
          return string ? 4 : dateObject.year
        },
  
        // Create an array by splitting the formatting string passed.
        toArray: function (formatString) {
          return formatString.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)
        },
  
        // Format an object into a string using the formatting options.
        toString: function (formatString, itemObject) {
          var calendar = this
          return calendar.formats.toArray(formatString).map(function (label) {
            return _.trigger(calendar.formats[label], calendar, [0, itemObject]) || label.replace(/^!/, '')
          }).join('')
        }
      }
    })() //DatePicker.prototype.formats
  
  
  
  
    /**
     * Check if two date units are the exact.
     */
    DatePicker.prototype.isDateExact = function (one, two) {
  
      var calendar = this
  
      // When we’re working with weekdays, do a direct comparison.
      if (
        (_.isInteger(one) && _.isInteger(two)) ||
        (typeof one == 'boolean' && typeof two == 'boolean')
      ) {
        return one === two
      }
  
      // When we’re working with date representations, compare the “pick” value.
      if (
        (_.isDate(one) || $.isArray(one)) &&
        (_.isDate(two) || $.isArray(two))
      ) {
        return calendar.create(one).pick === calendar.create(two).pick
      }
  
      // When we’re working with range objects, compare the “from” and “to”.
      if ($.isPlainObject(one) && $.isPlainObject(two)) {
        return calendar.isDateExact(one.from, two.from) && calendar.isDateExact(one.to, two.to)
      }
  
      return false
    }
  
  
    /**
     * Check if two date units overlap.
     */
    DatePicker.prototype.isDateOverlap = function (one, two) {
  
      var calendar = this,
        firstDay = calendar.settings.firstDay ? 1 : 0
  
      // When we’re working with a weekday index, compare the days.
      if (_.isInteger(one) && (_.isDate(two) || $.isArray(two))) {
        one = one % 7 + firstDay
        return one === calendar.create(two).day + 1
      }
      if (_.isInteger(two) && (_.isDate(one) || $.isArray(one))) {
        two = two % 7 + firstDay
        return two === calendar.create(one).day + 1
      }
  
      // When we’re working with range objects, check if the ranges overlap.
      if ($.isPlainObject(one) && $.isPlainObject(two)) {
        return calendar.overlapRanges(one, two)
      }
  
      return false
    }
  
  
    /**
     * Flip the “enabled” state.
     */
    DatePicker.prototype.flipEnable = function (val) {
      var itemObject = this.item
      itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1)
    }
  
  
    /**
     * Mark a collection of dates as “disabled”.
     */
    DatePicker.prototype.deactivate = function (type, datesToDisable) {
  
      var calendar = this,
        disabledItems = calendar.item.disable.slice(0)
  
  
      // If we’re flipping, that’s all we need to do.
      if (datesToDisable == 'flip') {
        calendar.flipEnable()
      } else if (datesToDisable === false) {
        calendar.flipEnable(1)
        disabledItems = []
      } else if (datesToDisable === true) {
        calendar.flipEnable(-1)
        disabledItems = []
      }
  
      // Otherwise go through the dates to disable.
      else {
  
        datesToDisable.map(function (unitToDisable) {
  
          var matchFound
  
          // When we have disabled items, check for matches.
          // If something is matched, immediately break out.
          for (var index = 0; index < disabledItems.length; index += 1) {
            if (calendar.isDateExact(unitToDisable, disabledItems[index])) {
              matchFound = true
              break
            }
          }
  
          // If nothing was found, add the validated unit to the collection.
          if (!matchFound) {
            if (
              _.isInteger(unitToDisable) ||
              _.isDate(unitToDisable) ||
              $.isArray(unitToDisable) ||
              ($.isPlainObject(unitToDisable) && unitToDisable.from && unitToDisable.to)
            ) {
              disabledItems.push(unitToDisable)
            }
          }
        })
      }
  
      // Return the updated collection.
      return disabledItems
    } //DatePicker.prototype.deactivate
  
  
    /**
     * Mark a collection of dates as “enabled”.
     */
    DatePicker.prototype.activate = function (type, datesToEnable) {
  
      var calendar = this,
        disabledItems = calendar.item.disable,
        disabledItemsCount = disabledItems.length
  
      // If we’re flipping, that’s all we need to do.
      if (datesToEnable == 'flip') {
        calendar.flipEnable()
      } else if (datesToEnable === true) {
        calendar.flipEnable(1)
        disabledItems = []
      } else if (datesToEnable === false) {
        calendar.flipEnable(-1)
        disabledItems = []
      }
  
      // Otherwise go through the disabled dates.
      else {
  
        datesToEnable.map(function (unitToEnable) {
  
          var matchFound,
            disabledUnit,
            index,
            isExactRange
  
          // Go through the disabled items and try to find a match.
          for (index = 0; index < disabledItemsCount; index += 1) {
  
            disabledUnit = disabledItems[index]
  
            // When an exact match is found, remove it from the collection.
            if (calendar.isDateExact(disabledUnit, unitToEnable)) {
              matchFound = disabledItems[index] = null
              isExactRange = true
              break
            }
  
            // When an overlapped match is found, add the “inverted” state to it.
            else if (calendar.isDateOverlap(disabledUnit, unitToEnable)) {
              if ($.isPlainObject(unitToEnable)) {
                unitToEnable.inverted = true
                matchFound = unitToEnable
              } else if ($.isArray(unitToEnable)) {
                matchFound = unitToEnable
                if (!matchFound[3]) matchFound.push('inverted')
              } else if (_.isDate(unitToEnable)) {
                matchFound = [unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted']
              }
              break
            }
          }
  
          // If a match was found, remove a previous duplicate entry.
          if (matchFound)
            for (index = 0; index < disabledItemsCount; index += 1) {
              if (calendar.isDateExact(disabledItems[index], unitToEnable)) {
                disabledItems[index] = null
                break
              }
            }
  
          // In the event that we’re dealing with an exact range of dates,
          // make sure there are no “inverted” dates because of it.
          if (isExactRange)
            for (index = 0; index < disabledItemsCount; index += 1) {
              if (calendar.isDateOverlap(disabledItems[index], unitToEnable)) {
                disabledItems[index] = null
                break
              }
            }
  
          // If something is still matched, add it into the collection.
          if (matchFound) {
            disabledItems.push(matchFound)
          }
        })
      }
  
      // Return the updated collection.
      return disabledItems.filter(function (val) {
        return val != null
      })
    } //DatePicker.prototype.activate
  
  
    /**
     * Create a string for the nodes in the picker.
     */
    DatePicker.prototype.nodes = function (isOpen) {
  
      var
        calendar = this,
        settings = calendar.settings,
        calendarItem = calendar.item,
        nowObject = calendarItem.now,
        selectedObject = calendarItem.select,
        highlightedObject = calendarItem.highlight,
        viewsetObject = calendarItem.view,
        disabledCollection = calendarItem.disable,
        minLimitObject = calendarItem.min,
        maxLimitObject = calendarItem.max,
  
  
        // Create the calendar table head using a copy of weekday labels collection.
        // * We do a copy so we don't mutate the original array.
        tableHead = (function (collection, fullCollection) {
  
          // If the first day should be Monday, move Sunday to the end.
          if (settings.firstDay) {
            collection.push(collection.shift())
            fullCollection.push(fullCollection.shift())
          }
  
          // Create and return the table head group.
          return _.node(
            'thead',
            _.node(
              'tr',
              _.group({
                min: 0,
                max: DAYS_IN_WEEK - 1,
                i: 1,
                node: 'th',
                item: function (counter) {
                  return [
                    collection[counter],
                    settings.klass.weekdays,
                    'scope=col title="' + fullCollection[counter] + '"'
                  ]
                }
              })
            )
          ) //endreturn
        })((settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysShort).slice(0), settings.weekdaysFull.slice(0)), //tableHead
  
  
        // Create the nav for next/prev month.
        createMonthNav = function (next) {
  
          // Otherwise, return the created month tag.
          return _.node(
            'button',
            ' ',
            settings.klass['nav' + (next ? 'Next' : 'Prev')] + (
  
              // If the focused month is outside the range, disabled the button.
              (next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month) ||
              (!next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month) ?
              ' ' + settings.klass.navDisabled : ''
            ),
            'data-nav=' + (next || -1) + ' ' +
            _.ariaAttr({
              role: 'button',
  
              controls: calendar.$node[0].id + '_table'
            }) + ' ' +
            'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev) + '"'
          ) //endreturn
        }, //createMonthNav
  
  
        // Create the month label.
        createMonthLabel = function () {
  
          var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull
  
          // If there are months to select, add a dropdown menu.
          if (settings.selectMonths) {
  
            return _.node('select',
              _.group({
                min: 0,
                max: 11,
                i: 1,
                node: 'option',
                item: function (loopedMonth) {
  
                  return [
  
                    // The looped month and no classes.
                    monthsCollection[loopedMonth], 0,
  
                    // Set the value and selected index.
                    'value=' + loopedMonth +
                    (viewsetObject.month == loopedMonth ? ' selected' : '') +
                    (
                      (
                        (viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month) ||
                        (viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month)
                      ) ?
                      ' disabled' : ''
                    )
                  ]
                }
              }),
              settings.klass.selectMonth,
              (isOpen ? '' : 'disabled') + ' ' +
              _.ariaAttr({
                controls: calendar.$node[0].id + '_table'
              }) + ' ' +
              'title="' + settings.labelMonthSelect + '"'
            )
          }
  
          // If there's a need for a month selector
          return _.node('div', monthsCollection[viewsetObject.month], settings.klass.month)
        }, //createMonthLabel
  
  
        // Create the year label.
        createYearLabel = function () {
  
          var focusedYear = viewsetObject.year,
  
            // If years selector is set to a literal "true", set it to 5. Otherwise
            // divide in half to get half before and half after focused year.
            numberYears = settings.selectYears === true ? 5 : ~~(settings.selectYears / 2)
  
          // If there are years to select, add a dropdown menu.
          if (numberYears) {
  
            var
              minYear = minLimitObject.year,
              maxYear = maxLimitObject.year,
              lowestYear = focusedYear - numberYears,
              highestYear = focusedYear + numberYears
  
            // If the min year is greater than the lowest year, increase the highest year
            // by the difference and set the lowest year to the min year.
            if (minYear > lowestYear) {
              highestYear += minYear - lowestYear
              lowestYear = minYear
            }
  
            // If the max year is less than the highest year, decrease the lowest year
            // by the lower of the two: available and needed years. Then set the
            // highest year to the max year.
            if (maxYear < highestYear) {
  
              var availableYears = lowestYear - minYear,
                neededYears = highestYear - maxYear
  
              lowestYear -= availableYears > neededYears ? neededYears : availableYears
              highestYear = maxYear
            }
  
            return _.node('select',
              _.group({
                min: lowestYear,
                max: highestYear,
                i: 1,
                node: 'option',
                item: function (loopedYear) {
                  return [
  
                    // The looped year and no classes.
                    loopedYear, 0,
  
                    // Set the value and selected index.
                    'value=' + loopedYear + (focusedYear == loopedYear ? ' selected' : '')
                  ]
                }
              }),
              settings.klass.selectYear,
              (isOpen ? '' : 'disabled') + ' ' + _.ariaAttr({
                controls: calendar.$node[0].id + '_table'
              }) + ' ' +
              'title="' + settings.labelYearSelect + '"'
            )
          }
  
          // Otherwise just return the year focused
          return _.node('div', focusedYear, settings.klass.year)
        } //createYearLabel
  
  
      // Create and return the entire calendar.
      return _.node(
          'div',
          (settings.selectYears ? createYearLabel() + createMonthLabel() : createMonthLabel() + createYearLabel()) +
          createMonthNav() + createMonthNav(1),
          settings.klass.header
        ) + _.node(
          'table',
          tableHead +
          _.node(
            'tbody',
            _.group({
              min: 0,
              max: WEEKS_IN_CALENDAR - 1,
              i: 1,
              node: 'tr',
              item: function (rowCounter) {
  
                // If Monday is the first day and the month starts on Sunday, shift the date back a week.
                var shiftDateBy = settings.firstDay && calendar.create([viewsetObject.year, viewsetObject.month, 1]).day === 0 ? -7 : 0
  
                return [
                  _.group({
                    min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index
                    max: function () {
                      return this.min + DAYS_IN_WEEK - 1
                    },
                    i: 1,
                    node: 'td',
                    item: function (targetDate) {
  
                      // Convert the time date from a relative date to a target date.
                      targetDate = calendar.create([viewsetObject.year, viewsetObject.month, targetDate + (settings.firstDay ? 1 : 0)])
  
                      var isSelected = selectedObject && selectedObject.pick == targetDate.pick,
                        isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick,
                        isDisabled = disabledCollection && calendar.disabled(targetDate) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick,
                        formattedDate = _.trigger(calendar.formats.toString, calendar, [settings.format, targetDate])
  
                      return [
                        _.node(
                          'div',
                          targetDate.date,
                          (function (klasses) {
  
                            // Add the `infocus` or `outfocus` classes based on month in view.
                            klasses.push(viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus)
  
                            // Add the `today` class if needed.
                            if (nowObject.pick == targetDate.pick) {
                              klasses.push(settings.klass.now)
                            }
  
                            // Add the `selected` class if something's selected and the time matches.
                            if (isSelected) {
                              klasses.push(settings.klass.selected)
                            }
  
                            // Add the `highlighted` class if something's highlighted and the time matches.
                            if (isHighlighted) {
                              klasses.push(settings.klass.highlighted)
                            }
  
                            // Add the `disabled` class if something's disabled and the object matches.
                            if (isDisabled) {
                              klasses.push(settings.klass.disabled)
                            }
  
                            return klasses.join(' ')
                          })([settings.klass.day]),
                          'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({
                            role: 'gridcell',
                            label: formattedDate,
                            selected: isSelected && calendar.$node.val() === formattedDate ? true : null,
                            activedescendant: isHighlighted ? true : null,
                            disabled: isDisabled ? true : null
                          })
                        ),
                        '',
                        _.ariaAttr({
                          role: 'presentation'
                        })
                      ] //endreturn
                    }
                  })
                ] //endreturn
              }
            })
          ),
          settings.klass.table,
          'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({
            role: 'grid',
            controls: calendar.$node[0].id,
            readonly: true
          })
        ) +
  
        // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”.
        _.node(
          'div',
          _.node('button', settings.today, settings.klass.buttonToday,
            'type=button data-pick=' + nowObject.pick +
            (isOpen && !calendar.disabled(nowObject) ? '' : ' disabled') + ' ' +
            _.ariaAttr({
              controls: calendar.$node[0].id
            })) +
          _.node('button', settings.clear, settings.klass.buttonClear,
            'type=button data-clear=1' +
            (isOpen ? '' : ' disabled') + ' ' +
            _.ariaAttr({
              controls: calendar.$node[0].id
            })) +
          _.node('button', settings.close, settings.klass.buttonClose,
            'type=button data-close=true ' +
            (isOpen ? '' : ' disabled') + ' ' +
            _.ariaAttr({
              controls: calendar.$node[0].id
            })),
          settings.klass.footer
        ) //endreturn
    } //DatePicker.prototype.nodes
  
  
  
  
    /**
     * The date picker defaults.
     */
    DatePicker.defaults = (function (prefix) {
  
      return {
  
        // The title label to use for the month nav buttons
        labelMonthNext: 'Next month',
        labelMonthPrev: 'Previous month',
  
        // The title label to use for the dropdown selectors
        labelMonthSelect: 'Select a month',
        labelYearSelect: 'Select a year',
  
        // Months and weekdays
        monthsFull: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
        weekdaysFull: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
        weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  
        // Today and clear
        today: 'Today',
        clear: 'Clear',
        close: 'Close',
  
        // Picker close behavior
        closeOnSelect: true,
        closeOnClear: true,
  
        // Update input value on select/clear
        updateInput: true,
  
        // The format to show on the `input` element
        format: 'd mmmm, yyyy',
  
        // Classes
        klass: {
  
          table: prefix + 'table',
  
          header: prefix + 'header',
  
          navPrev: prefix + 'nav--prev btn btn-flat',
          navNext: prefix + 'nav--next btn btn-flat',
          navDisabled: prefix + 'nav--disabled',
  
          month: prefix + 'month',
          year: prefix + 'year',
  
          selectMonth: prefix + 'select--month',
          selectYear: prefix + 'select--year',
  
          weekdays: prefix + 'weekday',
  
          day: prefix + 'day',
          disabled: prefix + 'day--disabled',
          selected: prefix + 'day--selected',
          highlighted: prefix + 'day--highlighted',
          now: prefix + 'day--today',
          infocus: prefix + 'day--infocus',
          outfocus: prefix + 'day--outfocus',
  
          footer: prefix + 'footer',
  
          buttonClear: prefix + 'button--clear',
          buttonToday: prefix + 'button--today',
          buttonClose: prefix + 'button--close'
        }
      }
    })(Picker.klasses().picker + '__')
  
  
  
  
  
    /**
     * Extend the picker to add the date picker.
     */
    Picker.extend('pickadate', DatePicker)
  
  
  }));
  
  $.extend($.fn.pickadate.defaults, {
    selectMonths: true, // Creates a dropdown to control month
    selectYears: 15, // Creates a dropdown of 15 years to control year,
  
    onRender: function () {
      var $pickerInstance = this.$root;
  
      var year = this.get('highlight', 'yyyy');
      var day = this.get('highlight', 'dd');
      var month = this.get('highlight', 'mmm');
      var labeldayFirstThreeLetters = this.get('highlight', 'dddd').slice(0, 3);
      var monthFirstUC = month.charAt(0).toUpperCase() + month.slice(1)
  
      $pickerInstance.find('.picker__header').prepend('<div class="picker__date-display"><div class="picker__weekday-display">' + labeldayFirstThreeLetters + ', </div><div class="picker__month-display"><div>' + monthFirstUC + '</div></div><div class="picker__day-display"><div>' + day + '</div></div><div    class="picker__year-display"><div>' + year + '</div></div></div>');
    }
  });
  
  /*!
   * ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/)
   * Copyright 2014 Wang Shenwei.
   * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE)
   *
   * Further modified
   * Copyright 2015 Ching Yaw Hao.
   */
  
  ;(function(){
  	var $ = window.jQuery,
  			$win = $(window),
  			$doc = $(document);
  
  	// Can I use inline svg ?
  	var svgNS = 'http://www.w3.org/2000/svg',
  		  svgSupported = 'SVGAngle' in window && (function() {
  			  var supported,
  				el = document.createElement('div');
  				el.innerHTML = '<svg/>';
  				supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS;
  				el.innerHTML = '';
  				return supported;
  			})();
  
  	// Can I use transition ?
  	var transitionSupported = (function() {
  		var style = document.createElement('div').style;
  		return 'transition' in style ||
  					 'WebkitTransition' in style ||
  				   'MozTransition' in style ||
  					 'msTransition' in style ||
  					 'OTransition' in style;
  	})();
  
  	// Listen touch events in touch screen device, instead of mouse events in desktop.
  	var touchSupported = 'ontouchstart' in window,
  			mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''),
  			mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''),
  			mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : '');
  
  	// Vibrate the device if supported
  	var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null;
  
  	function createSvgElement(name) {
  		return document.createElementNS(svgNS, name);
  	}
  
    function debounce(func, wait, immediate) {
      var timeout;
      return function() {
          var context = this, args = arguments;
          var later = function() {
              timeout = null;
              if (!immediate) func.apply(context, args);
          };
          var callNow = immediate && !timeout;
          clearTimeout(timeout);
          timeout = setTimeout(later, wait);
          if (callNow) func.apply(context, args);
      };
  }
  
  	function leadingZero(num) {
  		return (num < 10 ? '0' : '') + num;
  	}
  
  	// Get a unique id
  	var idCounter = 0;
  	function uniqueId(prefix) {
  		var id = ++idCounter + '';
  		return prefix ? prefix + id : id;
  	}
  
  	// Clock size
  	var dialRadius = 135,
  			outerRadius = 110,
  			// innerRadius = 80 on 12 hour clock
  			innerRadius = 80,
  			tickRadius = 20,
  			diameter = dialRadius * 2,
  			duration = transitionSupported ? 350 : 1;
  
  	// Popover template
  	var tpl = [
  		'<div class="clockpicker picker">',
  			'<div class="picker__holder">',
  				'<div class="picker__frame">',
  					'<div class="picker__wrap">',
  						'<div class="picker__box">',
  							'<div class="picker__date-display">',
  								'<div class="clockpicker-display">',
  									'<div class="clockpicker-display-column">',
  										'<span class="clockpicker-span-hours text-primary"></span>',
  										':',
  										'<span class="clockpicker-span-minutes"></span>',
  									'</div>',
  									'<div class="clockpicker-display-column clockpicker-display-am-pm">',
  										'<div class="clockpicker-span-am-pm"></div>',
  									'</div>',
  								'</div>',
  							'</div>',
  							'<div class="picker__calendar-container">',
  								'<div class="clockpicker-plate">',
  									'<div class="clockpicker-canvas"></div>',
  									'<div class="clockpicker-dial clockpicker-hours"></div>',
  									'<div class="clockpicker-dial clockpicker-minutes clockpicker-dial-out"></div>',
  								'</div>',
  								'<div class="clockpicker-am-pm-block">',
  								'</div>',
  							'</div>',
  							'<div class="picker__footer">',
  							'</div>',
  						'</div>',
  					'</div>',
  				'</div>',
  			'</div>',
  		'</div>'
  	].join('');
  
  	// ClockPicker
  	function ClockPicker(element, options) {
  		var popover = $(tpl),
  				plate = popover.find('.clockpicker-plate'),
  				holder = popover.find('.picker__holder'),
  				hoursView = popover.find('.clockpicker-hours'),
  				minutesView = popover.find('.clockpicker-minutes'),
  				amPmBlock = popover.find('.clockpicker-am-pm-block'),
  				isInput = element.prop('tagName') === 'INPUT',
          input = isInput ? element : element.find('input'),
          isHTML5 = input.prop('type') === 'time',
  				label = $("label[for=" + input.attr("id") + "]"),
  				self = this,
  				timer;
  
  		this.id = uniqueId('cp');
  		this.element = element;
  		this.holder = holder;
  		this.options = options;
  		this.isAppended = false;
  		this.isShown = false;
  		this.currentView = 'hours';
  		this.isInput = isInput;
  		this.input = input;
  		this.label = label;
  		this.popover = popover;
  		this.plate = plate;
  		this.hoursView = hoursView;
  		this.minutesView = minutesView;
  		this.amPmBlock = amPmBlock;
  		this.spanHours = popover.find('.clockpicker-span-hours');
  		this.spanMinutes = popover.find('.clockpicker-span-minutes');
  		this.spanAmPm = popover.find('.clockpicker-span-am-pm');
  		this.footer = popover.find('.picker__footer');
  		this.amOrPm = "";
  
  		// Setup for for 12 hour clock if option is selected
  		if (options.twelvehour) {
  			var  amPmButtonsTemplate = [
  				'<div class="clockpicker-am-pm-block">',
  					'<button type="button" class="btn-floating btn-flat clockpicker-button clockpicker-am-button">',
  						'AM',
  					'</button>',
  					'<button type="button" class="btn-floating btn-flat clockpicker-button clockpicker-pm-button">',
  						'PM',
  					'</button>',
  				'</div>'
  			].join('');
  
  			var amPmButtons = $(amPmButtonsTemplate);
  
  			if (!options.ampmclickable) {
  				$('<button type="button" class="btn-floating btn-flat clockpicker-button am-button" tabindex="1">' + "AM" + '</button>').on("click", function() {
  					self.amOrPm = "AM";
  					self.amPmBlock.children('.pm-button').removeClass('active');
  					self.amPmBlock.children('.am-button').addClass('active');
  					self.spanAmPm.empty().append('AM');
  				}).appendTo(this.amPmBlock);
  				$('<button type="button" class="btn-floating btn-flat clockpicker-button pm-button" tabindex="2">' + "PM" + '</button>').on("click", function() {
  					self.amOrPm = 'PM';
  					self.amPmBlock.children('.am-button').removeClass('active');
  					self.amPmBlock.children('.pm-button').addClass('active');
  					self.spanAmPm.empty().append('PM');
  				}).appendTo(this.amPmBlock);
  			}
  			else {
  				this.spanAmPm.empty();
  				$('<div id="click-am">AM</div>').on("click", function() {
  					self.spanAmPm.children('#click-am').addClass("text-primary");
  					self.spanAmPm.children('#click-pm').removeClass("text-primary");
  					self.amOrPm = "AM";
  				}).appendTo(this.spanAmPm);
  				$('<div id="click-pm">PM</div>').on("click", function() {
  					self.spanAmPm.children('#click-pm').addClass("text-primary");
  					self.spanAmPm.children('#click-am').removeClass("text-primary");
  					self.amOrPm = 'PM';
  				}).appendTo(this.spanAmPm);
  			}
  		}
  
  		if(options.darktheme)
  			popover.addClass('darktheme');
  
  			// If autoclose is not setted, append a button
  		$('<button type="button" class="btn btn-flat clockpicker-button" tabindex="' + (options.twelvehour? '3' : '1') + '">' + options.donetext + '</button>').click($.proxy(this.done, this)).appendTo(this.footer);
  
  		$('<button type="button" class="btn btn-flat clockpicker-button" tabindex="' + (options.twelvehour? '4' : '2') + '">' + options.cleartext + '</button>').click($.proxy(this.clearInput, this)).appendTo(this.footer);
  		this.spanHours.click($.proxy(this.toggleView, this, 'hours'));
  		this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes'));
  
  		// Show or toggle
  		input.on('focus.clockpicker click.clockpicker', debounce( $.proxy(this.show, this), 100));
  
  		// Build ticks
  		var tickTpl = $('<div class="clockpicker-tick"></div>'),
  				i, tick, radian, radius;
  
  		// Hours view
      if (options.twelvehour) {
        for (i = 0; i < 12; i += options.hourstep) {
            tick = tickTpl.clone();
            radian = i / 6 * Math.PI;
            radius = outerRadius;
            tick.css('font-size', '140%');
            tick.css({
                left: dialRadius + Math.sin(radian) * radius - tickRadius,
                top: dialRadius - Math.cos(radian) * radius - tickRadius
            });
            tick.html(i === 0 ? 12 : i);
            hoursView.append(tick);
            tick.on(mousedownEvent, mousedown);
        }
  		} else {
        for (i = 0; i < 24; i += options.hourstep) {
          tick = tickTpl.clone();
          radian = i / 6 * Math.PI;
          var inner = i > 0 && i < 13;
          radius = inner ? innerRadius : outerRadius;
          tick.css({
              left: dialRadius + Math.sin(radian) * radius - tickRadius,
              top: dialRadius - Math.cos(radian) * radius - tickRadius
          });
          if (inner) {
              tick.css('font-size', '120%');
          }
          tick.html(i === 0 ? '00' : i);
          hoursView.append(tick);
          tick.on(mousedownEvent, mousedown);
  			}
  		}
  
      // Minutes view
      var incrementValue = Math.max(options.minutestep, 5);
      for (i = 0; i < 60; i += incrementValue) {
        for (i = 0; i < 60; i += 5) {
          tick = tickTpl.clone();
          radian = i / 30 * Math.PI;
          tick.css({
            left: dialRadius + Math.sin(radian) * outerRadius - tickRadius,
            top: dialRadius - Math.cos(radian) * outerRadius - tickRadius
          });
          tick.css('font-size', '140%');
          tick.html(leadingZero(i));
          minutesView.append(tick);
          tick.on(mousedownEvent, mousedown);
        }
      }
  
  		// Clicking on minutes view space
  		plate.on(mousedownEvent, function(e) {
  			if ($(e.target).closest('.clockpicker-tick').length === 0)
  				mousedown(e, true);
  		});
  
  		// Mousedown or touchstart
  		function mousedown(e, space) {
  			var offset = plate.offset(),
  					isTouch = /^touch/.test(e.type),
  					x0 = offset.left + dialRadius,
  					y0 = offset.top + dialRadius,
  					dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
  					dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0,
  					z = Math.sqrt(dx * dx + dy * dy),
  					moved = false;
  
  			// When clicking on minutes view space, check the mouse position
  			if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius))
  				return;
  			e.preventDefault();
  
  			// Set cursor style of body after 200ms
  			var movingTimer = setTimeout(function(){
  				self.popover.addClass('clockpicker-moving');
  			}, 200);
  
  			// Place the canvas to top
  			if (svgSupported)
  				plate.append(self.canvas);
  
  			// Clock
  			self.setHand(dx, dy, !space, true);
  
  			// Mousemove on document
  			$doc.off(mousemoveEvent).on(mousemoveEvent, function(e){
  				e.preventDefault();
  				var isTouch = /^touch/.test(e.type),
  						x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
  						y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0;
  				if (! moved && x === dx && y === dy)
  					// Clicking in chrome on windows will trigger a mousemove event
  					return;
  				moved = true;
  				self.setHand(x, y, false, true);
  			});
  
  			// Mouseup on document
  			$doc.off(mouseupEvent).on(mouseupEvent, function(e) {
  				$doc.off(mouseupEvent);
  				e.preventDefault();
  				var isTouch = /^touch/.test(e.type),
  						x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0,
  						y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0;
  				if ((space || moved) && x === dx && y === dy)
  					self.setHand(x, y);
  				if (self.currentView === 'hours')
  					self.toggleView('minutes', duration / 2);
  				else
  					if (options.autoclose) {
  						self.minutesView.addClass('clockpicker-dial-out');
  						setTimeout(function(){
  							self.done();
  						}, duration / 2);
  					}
  				plate.prepend(canvas);
  
  				// Reset cursor style of body
  				clearTimeout(movingTimer);
  				self.popover.removeClass('clockpicker-moving');
  
  				// Unbind mousemove event
  				$doc.off(mousemoveEvent);
  			});
  		}
  
  		if (svgSupported) {
  			// Draw clock hands and others
  			var canvas = popover.find('.clockpicker-canvas'),
  					svg = createSvgElement('svg');
  			svg.setAttribute('class', 'clockpicker-svg');
  			svg.setAttribute('width', diameter);
  			svg.setAttribute('height', diameter);
  			var g = createSvgElement('g');
  			g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')');
  			var bearing = createSvgElement('circle');
  			bearing.setAttribute('class', 'clockpicker-canvas-bearing');
  			bearing.setAttribute('cx', 0);
  			bearing.setAttribute('cy', 0);
  			bearing.setAttribute('r', 2);
  			var hand = createSvgElement('line');
  			hand.setAttribute('x1', 0);
        hand.setAttribute('y1', 0);
  			var bg = createSvgElement('circle');
  			bg.setAttribute('class', 'clockpicker-canvas-bg');
  			bg.setAttribute('r', tickRadius);
  			var fg = createSvgElement('circle');
  			fg.setAttribute('class', 'clockpicker-canvas-fg');
  			fg.setAttribute('r', 5);
  			g.appendChild(hand);
  			g.appendChild(bg);
  			g.appendChild(fg);
  			g.appendChild(bearing);
  			svg.appendChild(g);
  			canvas.append(svg);
  
  			this.hand = hand;
  			this.bg = bg;
  			this.fg = fg;
  			this.bearing = bearing;
  			this.g = g;
  			this.canvas = canvas;
  		}
  
  		raiseCallback(this.options.init);
  	}
  
  	function raiseCallback(callbackFunction) {
  		if(callbackFunction && typeof callbackFunction === "function")
  			callbackFunction();
  	}
  
  	// Default options
  	ClockPicker.DEFAULTS = {
  		'default': '',         // default time, 'now' or '13:14' e.g.
  		fromnow: 0,            // set default time to * milliseconds from now (using with default = 'now')
      donetext: 'Done',      // done button text
      cleartext: 'Clear',    // clear button text
  		autoclose: false,      // auto close when minute is selected
  		ampmclickable: false,  // set am/pm button on itself
  		darktheme: false,			 // set to dark theme
  		twelvehour: false,     // change to 12 hour AM/PM clock from 24 hour
      vibrate: true,         // vibrate the device when dragging clock hand
      hourstep: 1,           // allow to multi increment the hour
      minutestep: 1,         // allow to multi increment the minute
      ampmSubmit: false,     // allow submit with AM and PM buttons instead of the minute selection/picker
  	};
  
  	// Show or hide popover
  	ClockPicker.prototype.toggle = function() {
  		this[this.isShown ? 'hide' : 'show']();
  	};
  
  	// Set popover position
  	ClockPicker.prototype.locate = function() {
  		var element = this.element,
  				popover = this.popover,
  				offset = element.offset(),
  				width = element.outerWidth(),
  				height = element.outerHeight(),
  				align = this.options.align,
  				self = this;
  
  		popover.show();
    };
  
      // The input can be changed by the user
      // So before we can use this.hours/this.minutes we must update it
  ClockPicker.prototype.parseInputValue = function(){
    var value = this.input.prop('value') || this.options['default'] || '';
  
    if (value === 'now') {
        value = new Date(+ new Date() + this.options.fromnow);
    }
    if (value instanceof Date) {
        value = value.getHours() + ':' + value.getMinutes();
    }
  
    value = value.split(':');
  
    // Minutes can have AM/PM that needs to be removed
    this.hours = + value[0] || 0;
    this.minutes = + (value[1] + '').replace(/\D/g, '') || 0;
  
    this.hours = Math.round(this.hours / this.options.hourstep) * this.options.hourstep;
    this.minutes = Math.round(this.minutes / this.options.minutestep) * this.options.minutestep;
  
    if (this.options.twelvehour) {
        var period = (value[1] + '').replace(/\d+/g, '').toLowerCase();
        this.amOrPm = this.hours > 12 || period === 'pm' ? 'PM' : 'AM';
    }
  };
  
  	// Show popover
  	ClockPicker.prototype.show = function(e){
  		// Not show again
  		if (this.isShown) {
  			return;
  		}
  		raiseCallback(this.options.beforeShow);
  		$(':input').each(function() {
  			$(this).attr('tabindex', -1);
  		})
  		var self = this;
  		// Initialize
  		this.input.blur();
  		this.popover.addClass('picker--opened');
  		this.input.addClass('picker__input picker__input--active');
  		$(document.body).css('overflow', 'hidden');
  		if (!this.isAppended) {
  			// Append popover to body
  			this.popover.insertAfter(this.input);
  			if(this.options.twelvehour) {
  				this.amOrPm = 'PM';
  				if(!this.options.ampmclickable) {
  					this.amPmBlock.children('.am-button').removeClass('active');
  					this.amPmBlock.children('.pm-button').addClass('active');
  					this.spanAmPm.empty().append('PM');
  				}
  				else {
  					this.spanAmPm.children('#click-pm').addClass("text-primary");
  					this.spanAmPm.children('#click-am').removeClass("text-primary");
  				}
  			}
  			// Reset position when resize
  			$win.on('resize.clockpicker' + this.id, function() {
  				if (self.isShown) {
  					self.locate();
  				}
  			});
  			this.isAppended = true;
  		}
  		// Get the time
  		this.parseInputValue();
  		this.spanHours.html(leadingZero(this.hours));
      this.spanMinutes.html(leadingZero(this.minutes));
  
      if (this.options.twelvehour) {
        this.spanAmPm.empty().append(this.amOrPm);
      }
  
  		// Toggle to hours view
  		this.toggleView('hours');
  		// Set position
  		this.locate();
  		this.isShown = true;
  		// Hide when clicking or tabbing on any element except the clock and input
  		$doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, debounce(function(e) {
  			var target = $(e.target);
  			if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0)
  				self.hide();
  		}, 100));
  		// Hide when ESC is pressed
  		$doc.on('keyup.clockpicker.' + this.id, debounce( function(e){
  			if (e.keyCode === 27)
  				self.hide();
  		},100));
  		raiseCallback(this.options.afterShow);
  	};
  	// Hide popover
  	ClockPicker.prototype.hide = function() {
  		raiseCallback(this.options.beforeHide);
  		this.input.removeClass('picker__input picker__input--active');
  		this.popover.removeClass('picker--opened');
  		$(document.body).css('overflow', 'visible');
  		this.isShown = false;
  		$(':input').each(function(index) {
  			$(this).attr('tabindex', index + 1);
  		});
  		// Unbinding events on document
  		$doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id);
  		$doc.off('keyup.clockpicker.' + this.id);
  		this.popover.hide();
  		raiseCallback(this.options.afterHide);
  	};
  	// Toggle to hours or minutes view
  	ClockPicker.prototype.toggleView = function(view, delay) {
  		var raiseAfterHourSelect = false;
  		if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") {
  			raiseCallback(this.options.beforeHourSelect);
  			raiseAfterHourSelect = true;
  		}
  		var isHours = view === 'hours',
  				nextView = isHours ? this.hoursView : this.minutesView,
  				hideView = isHours ? this.minutesView : this.hoursView;
  		this.currentView = view;
  
  		this.spanHours.toggleClass('text-primary', isHours);
  		this.spanMinutes.toggleClass('text-primary', ! isHours);
  
  		// Let's make transitions
  		hideView.addClass('clockpicker-dial-out');
  		nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out');
  
  		// Reset clock hand
  		this.resetClock(delay);
  
  		// After transitions ended
  		clearTimeout(this.toggleViewTimer);
  		this.toggleViewTimer = setTimeout(function() {
  			hideView.css('visibility', 'hidden');
  		}, duration);
  
  		if (raiseAfterHourSelect)
  			raiseCallback(this.options.afterHourSelect);
  	};
  
  	// Reset clock hand
  	ClockPicker.prototype.resetClock = function(delay) {
  		var view = this.currentView,
  				value = this[view],
  				isHours = view === 'hours',
  				unit = Math.PI / (isHours ? 6 : 30),
  				radian = value * unit,
  				radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius,
  				x = Math.sin(radian) * radius,
  				y = - Math.cos(radian) * radius,
  				self = this;
  
  		if(svgSupported && delay) {
  			self.canvas.addClass('clockpicker-canvas-out');
  			setTimeout(function(){
  				self.canvas.removeClass('clockpicker-canvas-out');
  				self.setHand(x, y);
  			}, delay);
  		} else
  			this.setHand(x, y);
  	};
  
  	// Set clock hand to (x, y)
  	ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging) {
  		var radian = Math.atan2(x, - y),
  				isHours = this.currentView === 'hours',
  				z = Math.sqrt(x * x + y * y),
  				options = this.options,
  				inner = isHours && z < (outerRadius + innerRadius) / 2,
  				radius = inner ? innerRadius : outerRadius,
  				unit,
          value;
  
          // Calculate the unit
          if (isHours) {
              unit = options.hourstep / 6 * Math.PI
          } else {
              unit = options.minutestep / 30 * Math.PI
          }
  
  		if (options.twelvehour)
  			radius = outerRadius;
  
  		// Radian should in range [0, 2PI]
  		if (radian < 0)
  			radian = Math.PI * 2 + radian;
  
  		// Get the round value
  		value = Math.round(radian / unit);
  
  		// Get the round radian
  		radian = value * unit;
  
  		// Correct the hours or minutes
      if (isHours) {
        value *= options.hourstep;
        if (! options.twelvehour && (!inner)==(value>0)) {
            value += 12;
        }
        if (options.twelvehour && value === 0) {
            value = 12;
        }
        if (value === 24) {
            value = 0;
        }
      } else {
        value *= options.minutestep;
        if (value === 60) {
            value = 0;
        }
      }
  		if (isHours)
  			this.fg.setAttribute('class', 'clockpicker-canvas-fg');
  		else {
  			if(value % 5 == 0)
  				this.fg.setAttribute('class', 'clockpicker-canvas-fg');
  			else
  				this.fg.setAttribute('class', 'clockpicker-canvas-fg active');
  		}
  
  		// Once hours or minutes changed, vibrate the device
  		if (this[this.currentView] !== value)
  			if (vibrate && this.options.vibrate)
  				// Do not vibrate too frequently
  				if (! this.vibrateTimer) {
  					navigator[vibrate](10);
  					this.vibrateTimer = setTimeout($.proxy(function(){
  						this.vibrateTimer = null;
  					}, this), 100);
  				}
  
  		this[this.currentView] = value;
  		this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value));
  
  		// If svg is not supported, just add an active class to the tick
  		if (! svgSupported) {
  			this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){
  				var tick = $(this);
  				tick.toggleClass('active', value === + tick.html());
  			});
  			return;
  		}
  
  		// Place clock hand at the top when dragging
  		if (dragging || (! isHours && value % 5)) {
  			this.g.insertBefore(this.hand, this.bearing);
  			this.g.insertBefore(this.bg, this.fg);
  			this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans');
  		} else {
  			// Or place it at the bottom
  			this.g.insertBefore(this.hand, this.bg);
  			this.g.insertBefore(this.fg, this.bg);
  			this.bg.setAttribute('class', 'clockpicker-canvas-bg');
  		}
  
  		// Set clock hand and others' position
      var cx = Math.sin(radian) * radius,
        cy = - Math.cos(radian) * radius;
      this.hand.setAttribute('x2', cx);
      this.hand.setAttribute('y2', cy);
      this.bg.setAttribute('cx', cx);
      this.bg.setAttribute('cy', cy);
      this.fg.setAttribute('cx', cx);
      this.fg.setAttribute('cy', cy);
    };
  
    	// Clear clock text
    ClockPicker.prototype.clearInput = function() {
  		this.input.val('');
  		this.hide();
  
  		if(this.options.afterDone && typeof this.options.afterDone === 'function')
  			this.options.afterDone(this.input, null);
  	};
  
      // Allow user to get time as Date object
      ClockPicker.prototype.getTime = function(callback) {
        this.parseInputValue();
  
        var hours = this.hours;
        if (this.options.twelvehour && hours < 12 && this.amOrPm === 'PM') {
            hours += 12;
        }
  
        var selectedTime = new Date();
        selectedTime.setMinutes(this.minutes)
        selectedTime.setHours(hours);
        selectedTime.setSeconds(0);
  
        return callback && callback.apply(this.element, selectedTime) || selectedTime;
    }
  
  	// Hours and minutes are selected
  	ClockPicker.prototype.done = function() {
  		raiseCallback(this.options.beforeDone);
  		this.hide();
  		this.label.addClass('active');
  
  		var last = this.input.prop('value'),
        outHours = this.hours,
        value = ':' + leadingZero(this.minutes);
  
      if (this.isHTML5 && this.options.twelvehour) {
          if (this.hours < 12 && this.amOrPm === 'PM') {
              outHours += 12;
          }
          if (this.hours === 12 && this.amOrPm === 'AM') {
              outHours = 0;
          }
      }
  
      value = leadingZero(outHours) + value;
  
      if (!this.isHTML5 && this.options.twelvehour) {
            value = value + this.amOrPm;
      }
  
  		this.input.prop('value', value);
  		if(value !== last) {
  			this.input.trigger('change');
  			if(!this.isInput)
  				this.element.trigger('change');
  		}
  
  		if(this.options.autoclose)
  			this.input.trigger('blur');
  
  		raiseCallback(this.options.afterDone);
  	};
  
  	// Remove clockpicker from input
  	ClockPicker.prototype.remove = function() {
  		this.element.removeData('clockpicker');
  		this.input.off('focus.clockpicker click.clockpicker');
  		if (this.isShown)
  			this.hide();
  		if (this.isAppended) {
  			$win.off('resize.clockpicker' + this.id);
  			this.popover.remove();
  		}
  	};
  
  	// Extends $.fn.clockpicker
  	$.fn.pickatime = function(option){
  		var args = Array.prototype.slice.call(arguments, 1);
  		function handleClockPickerRequest(){
  			var $this = $(this),
  					data = $this.data('clockpicker');
  			if (!data) {
  				var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option);
  				$this.data('clockpicker', new ClockPicker($this, options));
  			} else {
  				// Manual operations. show, hide, remove, e.g.
  				if (typeof data[option] === 'function')
  					data[option].apply(data, args);
  			}
      }
      // If we explicitly do a call on a single element then we can return the value (if needed)
      // This allows us, for example, to return the value of getTime
      if (this.length == 1) {
        var returnValue = handleClockPickerRequest.apply(this[0]);
  
        // If we do not have any return value then return the object itself so you can chain
        return returnValue !== undefined ? returnValue : this;
      }
  
      // If we do have a list then we do not care about return values
      return this.each(handleClockPickerRequest);
      };
  }());
  
  /*! PhotoSwipe - v4.1.1 - 2015-12-24
   * http://photoswipe.com
   * Copyright (c) 2015 Dmitry Semenov; */
  ! function (a, b) {
      "function" == typeof define && define.amd ? define(b) : "object" == typeof exports ? module.exports = b() : a.PhotoSwipe = b()
  }(this, function () {
      "use strict";
      var a = function (a, b, c, d) {
          var e = {
              features: null,
              bind: function (a, b, c, d) {
                  var e = (d ? "remove" : "add") + "EventListener";
                  b = b.split(" ");
                  for (var f = 0; f < b.length; f++) b[f] && a[e](b[f], c, !1)
              },
              isArray: function (a) {
                  return a instanceof Array
              },
              createEl: function (a, b) {
                  var c = document.createElement(b || "div");
                  return a && (c.className = a), c
              },
              getScrollY: function () {
                  var a = window.pageYOffset;
                  return void 0 !== a ? a : document.documentElement.scrollTop
              },
              unbind: function (a, b, c) {
                  e.bind(a, b, c, !0)
              },
              removeClass: function (a, b) {
                  var c = new RegExp("(\\s|^)" + b + "(\\s|$)");
                  a.className = a.className.replace(c, " ").replace(/^\s\s*/, "").replace(/\s\s*$/, "")
              },
              addClass: function (a, b) {
                  e.hasClass(a, b) || (a.className += (a.className ? " " : "") + b)
              },
              hasClass: function (a, b) {
                  return a.className && new RegExp("(^|\\s)" + b + "(\\s|$)").test(a.className)
              },
              getChildByClass: function (a, b) {
                  for (var c = a.firstChild; c;) {
                      if (e.hasClass(c, b)) return c;
                      c = c.nextSibling
                  }
              },
              arraySearch: function (a, b, c) {
                  for (var d = a.length; d--;)
                      if (a[d][c] === b) return d;
                  return -1
              },
              extend: function (a, b, c) {
                  for (var d in b)
                      if (b.hasOwnProperty(d)) {
                          if (c && a.hasOwnProperty(d)) continue;
                          a[d] = b[d]
                      }
              },
              easing: {
                  sine: {
                      out: function (a) {
                          return Math.sin(a * (Math.PI / 2))
                      },
                      inOut: function (a) {
                          return -(Math.cos(Math.PI * a) - 1) / 2
                      }
                  },
                  cubic: {
                      out: function (a) {
                          return --a * a * a + 1
                      }
                  }
              },
              detectFeatures: function () {
                  if (e.features) return e.features;
                  var a = e.createEl(),
                      b = a.style,
                      c = "",
                      d = {};
                  if (d.oldIE = document.all && !document.addEventListener, d.touch = "ontouchstart" in window, window.requestAnimationFrame && (d.raf = window.requestAnimationFrame, d.caf = window.cancelAnimationFrame), d.pointerEvent = navigator.pointerEnabled || navigator.msPointerEnabled, !d.pointerEvent) {
                      var f = navigator.userAgent;
                      if (/iP(hone|od)/.test(navigator.platform)) {
                          var g = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
                          g && g.length > 0 && (g = parseInt(g[1], 10), g >= 1 && 8 > g && (d.isOldIOSPhone = !0))
                      }
                      var h = f.match(/Android\s([0-9\.]*)/),
                          i = h ? h[1] : 0;
                      i = parseFloat(i), i >= 1 && (4.4 > i && (d.isOldAndroid = !0), d.androidVersion = i), d.isMobileOpera = /opera mini|opera mobi/i.test(f)
                  }
                  for (var j, k, l = ["transform", "perspective", "animationName"], m = ["", "webkit", "Moz", "ms", "O"], n = 0; 4 > n; n++) {
                      c = m[n];
                      for (var o = 0; 3 > o; o++) j = l[o], k = c + (c ? j.charAt(0).toUpperCase() + j.slice(1) : j), !d[j] && k in b && (d[j] = k);
                      c && !d.raf && (c = c.toLowerCase(), d.raf = window[c + "RequestAnimationFrame"], d.raf && (d.caf = window[c + "CancelAnimationFrame"] || window[c + "CancelRequestAnimationFrame"]))
                  }
                  if (!d.raf) {
                      var p = 0;
                      d.raf = function (a) {
                          var b = (new Date).getTime(),
                              c = Math.max(0, 16 - (b - p)),
                              d = window.setTimeout(function () {
                                  a(b + c)
                              }, c);
                          return p = b + c, d
                      }, d.caf = function (a) {
                          clearTimeout(a)
                      }
                  }
                  return d.svg = !!document.createElementNS && !!document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect, e.features = d, d
              }
          };
          e.detectFeatures(), e.features.oldIE && (e.bind = function (a, b, c, d) {
              b = b.split(" ");
              for (var e, f = (d ? "detach" : "attach") + "Event", g = function () {
                      c.handleEvent.call(c)
                  }, h = 0; h < b.length; h++)
                  if (e = b[h])
                      if ("object" == typeof c && c.handleEvent) {
                          if (d) {
                              if (!c["oldIE" + e]) return !1
                          } else c["oldIE" + e] = g;
                          a[f]("on" + e, c["oldIE" + e])
                      } else a[f]("on" + e, c)
          });
          var f = this,
              g = 25,
              h = 3,
              i = {
                  allowPanToNext: !0,
                  spacing: .12,
                  bgOpacity: 1,
                  mouseUsed: !1,
                  loop: !0,
                  pinchToClose: !0,
                  closeOnScroll: !0,
                  closeOnVerticalDrag: !0,
                  verticalDragRange: .75,
                  hideAnimationDuration: 333,
                  showAnimationDuration: 333,
                  showHideOpacity: !1,
                  focus: !0,
                  escKey: !0,
                  arrowKeys: !0,
                  mainScrollEndFriction: .35,
                  panEndFriction: .35,
                  isClickableElement: function (a) {
                      return "A" === a.tagName
                  },
                  getDoubleTapZoom: function (a, b) {
                      return a ? 1 : b.initialZoomLevel < .7 ? 1 : 1.33
                  },
                  maxSpreadZoom: 1.33,
                  modal: !0,
                  scaleMode: "fit"
              };
          e.extend(i, d);
          var j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, $, _, aa, ba, ca, da, ea, fa, ga, ha, ia, ja, ka, la = function () {
                  return {
                      x: 0,
                      y: 0
                  }
              },
              ma = la(),
              na = la(),
              oa = la(),
              pa = {},
              qa = 0,
              ra = {},
              sa = la(),
              ta = 0,
              ua = !0,
              va = [],
              wa = {},
              xa = !1,
              ya = function (a, b) {
                  e.extend(f, b.publicMethods), va.push(a)
              },
              za = function (a) {
                  var b = _b();
                  return a > b - 1 ? a - b : 0 > a ? b + a : a
              },
              Aa = {},
              Ba = function (a, b) {
                  return Aa[a] || (Aa[a] = []), Aa[a].push(b)
              },
              Ca = function (a) {
                  var b = Aa[a];
                  if (b) {
                      var c = Array.prototype.slice.call(arguments);
                      c.shift();
                      for (var d = 0; d < b.length; d++) b[d].apply(f, c)
                  }
              },
              Da = function () {
                  return (new Date).getTime()
              },
              Ea = function (a) {
                  ia = a, f.bg.style.opacity = a * i.bgOpacity
              },
              Fa = function (a, b, c, d, e) {
                  (!xa || e && e !== f.currItem) && (d /= e ? e.fitRatio : f.currItem.fitRatio), a[E] = u + b + "px, " + c + "px" + v + " scale(" + d + ")"
              },
              Ga = function (a) {
                  da && (a && (s > f.currItem.fitRatio ? xa || (lc(f.currItem, !1, !0), xa = !0) : xa && (lc(f.currItem), xa = !1)), Fa(da, oa.x, oa.y, s))
              },
              Ha = function (a) {
                  a.container && Fa(a.container.style, a.initialPosition.x, a.initialPosition.y, a.initialZoomLevel, a)
              },
              Ia = function (a, b) {
                  b[E] = u + a + "px, 0px" + v
              },
              Ja = function (a, b) {
                  if (!i.loop && b) {
                      var c = m + (sa.x * qa - a) / sa.x,
                          d = Math.round(a - sb.x);
                      (0 > c && d > 0 || c >= _b() - 1 && 0 > d) && (a = sb.x + d * i.mainScrollEndFriction)
                  }
                  sb.x = a, Ia(a, n)
              },
              Ka = function (a, b) {
                  var c = tb[a] - ra[a];
                  return na[a] + ma[a] + c - c * (b / t)
              },
              La = function (a, b) {
                  a.x = b.x, a.y = b.y, b.id && (a.id = b.id)
              },
              Ma = function (a) {
                  a.x = Math.round(a.x), a.y = Math.round(a.y)
              },
              Na = null,
              Oa = function () {
                  Na && (e.unbind(document, "mousemove", Oa), e.addClass(a, "pswp--has_mouse"), i.mouseUsed = !0, Ca("mouseUsed")), Na = setTimeout(function () {
                      Na = null
                  }, 100)
              },
              Pa = function () {
                  e.bind(document, "keydown", f), N.transform && e.bind(f.scrollWrap, "click", f), i.mouseUsed || e.bind(document, "mousemove", Oa), e.bind(window, "resize scroll", f), Ca("bindEvents")
              },
              Qa = function () {
                  e.unbind(window, "resize", f), e.unbind(window, "scroll", r.scroll), e.unbind(document, "keydown", f), e.unbind(document, "mousemove", Oa), N.transform && e.unbind(f.scrollWrap, "click", f), U && e.unbind(window, p, f), Ca("unbindEvents")
              },
              Ra = function (a, b) {
                  var c = hc(f.currItem, pa, a);
                  return b && (ca = c), c
              },
              Sa = function (a) {
                  return a || (a = f.currItem), a.initialZoomLevel
              },
              Ta = function (a) {
                  return a || (a = f.currItem), a.w > 0 ? i.maxSpreadZoom : 1
              },
              Ua = function (a, b, c, d) {
                  return d === f.currItem.initialZoomLevel ? (c[a] = f.currItem.initialPosition[a], !0) : (c[a] = Ka(a, d), c[a] > b.min[a] ? (c[a] = b.min[a], !0) : c[a] < b.max[a] ? (c[a] = b.max[a], !0) : !1)
              },
              Va = function () {
                  if (E) {
                      var b = N.perspective && !G;
                      return u = "translate" + (b ? "3d(" : "("), void(v = N.perspective ? ", 0px)" : ")")
                  }
                  E = "left", e.addClass(a, "pswp--ie"), Ia = function (a, b) {
                      b.left = a + "px"
                  }, Ha = function (a) {
                      var b = a.fitRatio > 1 ? 1 : a.fitRatio,
                          c = a.container.style,
                          d = b * a.w,
                          e = b * a.h;
                      c.width = d + "px", c.height = e + "px", c.left = a.initialPosition.x + "px", c.top = a.initialPosition.y + "px"
                  }, Ga = function () {
                      if (da) {
                          var a = da,
                              b = f.currItem,
                              c = b.fitRatio > 1 ? 1 : b.fitRatio,
                              d = c * b.w,
                              e = c * b.h;
                          a.width = d + "px", a.height = e + "px", a.left = oa.x + "px", a.top = oa.y + "px"
                      }
                  }
              },
              Wa = function (a) {
                  var b = "";
                  i.escKey && 27 === a.keyCode ? b = "close" : i.arrowKeys && (37 === a.keyCode ? b = "prev" : 39 === a.keyCode && (b = "next")), b && (a.ctrlKey || a.altKey || a.shiftKey || a.metaKey || (a.preventDefault ? a.preventDefault() : a.returnValue = !1, f[b]()))
              },
              Xa = function (a) {
                  a && (X || W || ea || S) && (a.preventDefault(), a.stopPropagation())
              },
              Ya = function () {
                  f.setScrollOffset(0, e.getScrollY())
              },
              Za = {},
              $a = 0,
              _a = function (a) {
                  Za[a] && (Za[a].raf && I(Za[a].raf), $a--, delete Za[a])
              },
              ab = function (a) {
                  Za[a] && _a(a), Za[a] || ($a++, Za[a] = {})
              },
              bb = function () {
                  for (var a in Za) Za.hasOwnProperty(a) && _a(a)
              },
              cb = function (a, b, c, d, e, f, g) {
                  var h, i = Da();
                  ab(a);
                  var j = function () {
                      if (Za[a]) {
                          if (h = Da() - i, h >= d) return _a(a), f(c), void(g && g());
                          f((c - b) * e(h / d) + b), Za[a].raf = H(j)
                      }
                  };
                  j()
              },
              db = {
                  shout: Ca,
                  listen: Ba,
                  viewportSize: pa,
                  options: i,
                  isMainScrollAnimating: function () {
                      return ea
                  },
                  getZoomLevel: function () {
                      return s
                  },
                  getCurrentIndex: function () {
                      return m
                  },
                  isDragging: function () {
                      return U
                  },
                  isZooming: function () {
                      return _
                  },
                  setScrollOffset: function (a, b) {
                      ra.x = a, M = ra.y = b, Ca("updateScrollOffset", ra)
                  },
                  applyZoomPan: function (a, b, c, d) {
                      oa.x = b, oa.y = c, s = a, Ga(d)
                  },
                  init: function () {
                      if (!j && !k) {
                          var c;
                          f.framework = e, f.template = a, f.bg = e.getChildByClass(a, "pswp__bg"), J = a.className, j = !0, N = e.detectFeatures(), H = N.raf, I = N.caf, E = N.transform, L = N.oldIE, f.scrollWrap = e.getChildByClass(a, "pswp__scroll-wrap"), f.container = e.getChildByClass(f.scrollWrap, "pswp__container"), n = f.container.style, f.itemHolders = y = [{
                              el: f.container.children[0],
                              wrap: 0,
                              index: -1
                          }, {
                              el: f.container.children[1],
                              wrap: 0,
                              index: -1
                          }, {
                              el: f.container.children[2],
                              wrap: 0,
                              index: -1
                          }], y[0].el.style.display = y[2].el.style.display = "none", Va(), r = {
                              resize: f.updateSize,
                              scroll: Ya,
                              keydown: Wa,
                              click: Xa
                          };
                          var d = N.isOldIOSPhone || N.isOldAndroid || N.isMobileOpera;
                          for (N.animationName && N.transform && !d || (i.showAnimationDuration = i.hideAnimationDuration = 0), c = 0; c < va.length; c++) f["init" + va[c]]();
                          if (b) {
                              var g = f.ui = new b(f, e);
                              g.init()
                          }
                          Ca("firstUpdate"), m = m || i.index || 0, (isNaN(m) || 0 > m || m >= _b()) && (m = 0), f.currItem = $b(m), (N.isOldIOSPhone || N.isOldAndroid) && (ua = !1), a.setAttribute("aria-hidden", "false"), i.modal && (ua ? a.style.position = "fixed" : (a.style.position = "absolute", a.style.top = e.getScrollY() + "px")), void 0 === M && (Ca("initialLayout"), M = K = e.getScrollY());
                          var l = "pswp--open ";
                          for (i.mainClass && (l += i.mainClass + " "), i.showHideOpacity && (l += "pswp--animate_opacity "), l += G ? "pswp--touch" : "pswp--notouch", l += N.animationName ? " pswp--css_animation" : "", l += N.svg ? " pswp--svg" : "", e.addClass(a, l), f.updateSize(), o = -1, ta = null, c = 0; h > c; c++) Ia((c + o) * sa.x, y[c].el.style);
                          L || e.bind(f.scrollWrap, q, f), Ba("initialZoomInEnd", function () {
                              f.setContent(y[0], m - 1), f.setContent(y[2], m + 1), y[0].el.style.display = y[2].el.style.display = "block", i.focus && a.focus(), Pa()
                          }), f.setContent(y[1], m), f.updateCurrItem(), Ca("afterInit"), ua || (w = setInterval(function () {
                              $a || U || _ || s !== f.currItem.initialZoomLevel || f.updateSize()
                          }, 1e3)), e.addClass(a, "pswp--visible")
                      }
                  },
                  close: function () {
                      j && (j = !1, k = !0, Ca("close"), Qa(), bc(f.currItem, null, !0, f.destroy))
                  },
                  destroy: function () {
                      Ca("destroy"), Wb && clearTimeout(Wb), a.setAttribute("aria-hidden", "true"), a.className = J, w && clearInterval(w), e.unbind(f.scrollWrap, q, f), e.unbind(window, "scroll", f), yb(), bb(), Aa = null
                  },
                  panTo: function (a, b, c) {
                      c || (a > ca.min.x ? a = ca.min.x : a < ca.max.x && (a = ca.max.x), b > ca.min.y ? b = ca.min.y : b < ca.max.y && (b = ca.max.y)), oa.x = a, oa.y = b, Ga()
                  },
                  handleEvent: function (a) {
                      a = a || window.event, r[a.type] && r[a.type](a)
                  },
                  goTo: function (a) {
                      a = za(a);
                      var b = a - m;
                      ta = b, m = a, f.currItem = $b(m), qa -= b, Ja(sa.x * qa), bb(), ea = !1, f.updateCurrItem()
                  },
                  next: function () {
                      f.goTo(m + 1)
                  },
                  prev: function () {
                      f.goTo(m - 1)
                  },
                  updateCurrZoomItem: function (a) {
                      if (a && Ca("beforeChange", 0), y[1].el.children.length) {
                          var b = y[1].el.children[0];
                          da = e.hasClass(b, "pswp__zoom-wrap") ? b.style : null
                      } else da = null;
                      ca = f.currItem.bounds, t = s = f.currItem.initialZoomLevel, oa.x = ca.center.x, oa.y = ca.center.y, a && Ca("afterChange")
                  },
                  invalidateCurrItems: function () {
                      x = !0;
                      for (var a = 0; h > a; a++) y[a].item && (y[a].item.needsUpdate = !0)
                  },
                  updateCurrItem: function (a) {
                      if (0 !== ta) {
                          var b, c = Math.abs(ta);
                          if (!(a && 2 > c)) {
                              f.currItem = $b(m), xa = !1, Ca("beforeChange", ta), c >= h && (o += ta + (ta > 0 ? -h : h), c = h);
                              for (var d = 0; c > d; d++) ta > 0 ? (b = y.shift(), y[h - 1] = b, o++, Ia((o + 2) * sa.x, b.el.style), f.setContent(b, m - c + d + 1 + 1)) : (b = y.pop(), y.unshift(b), o--, Ia(o * sa.x, b.el.style), f.setContent(b, m + c - d - 1 - 1));
                              if (da && 1 === Math.abs(ta)) {
                                  var e = $b(z);
                                  e.initialZoomLevel !== s && (hc(e, pa), lc(e), Ha(e))
                              }
                              ta = 0, f.updateCurrZoomItem(), z = m, Ca("afterChange")
                          }
                      }
                  },
                  updateSize: function (b) {
                      if (!ua && i.modal) {
                          var c = e.getScrollY();
                          if (M !== c && (a.style.top = c + "px", M = c), !b && wa.x === window.innerWidth && wa.y === window.innerHeight) return;
                          wa.x = window.innerWidth, wa.y = window.innerHeight, a.style.height = wa.y + "px"
                      }
                      if (pa.x = f.scrollWrap.clientWidth, pa.y = f.scrollWrap.clientHeight, Ya(), sa.x = pa.x + Math.round(pa.x * i.spacing), sa.y = pa.y, Ja(sa.x * qa), Ca("beforeResize"), void 0 !== o) {
                          for (var d, g, j, k = 0; h > k; k++) d = y[k], Ia((k + o) * sa.x, d.el.style), j = m + k - 1, i.loop && _b() > 2 && (j = za(j)), g = $b(j), g && (x || g.needsUpdate || !g.bounds) ? (f.cleanSlide(g), f.setContent(d, j), 1 === k && (f.currItem = g, f.updateCurrZoomItem(!0)), g.needsUpdate = !1) : -1 === d.index && j >= 0 && f.setContent(d, j), g && g.container && (hc(g, pa), lc(g), Ha(g));
                          x = !1
                      }
                      t = s = f.currItem.initialZoomLevel, ca = f.currItem.bounds, ca && (oa.x = ca.center.x, oa.y = ca.center.y, Ga(!0)), Ca("resize")
                  },
                  zoomTo: function (a, b, c, d, f) {
                      b && (t = s, tb.x = Math.abs(b.x) - oa.x, tb.y = Math.abs(b.y) - oa.y, La(na, oa));
                      var g = Ra(a, !1),
                          h = {};
                      Ua("x", g, h, a), Ua("y", g, h, a);
                      var i = s,
                          j = {
                              x: oa.x,
                              y: oa.y
                          };
                      Ma(h);
                      var k = function (b) {
                          1 === b ? (s = a, oa.x = h.x, oa.y = h.y) : (s = (a - i) * b + i, oa.x = (h.x - j.x) * b + j.x, oa.y = (h.y - j.y) * b + j.y), f && f(b), Ga(1 === b)
                      };
                      c ? cb("customZoomTo", 0, 1, c, d || e.easing.sine.inOut, k) : k(1)
                  }
              },
              eb = 30,
              fb = 10,
              gb = {},
              hb = {},
              ib = {},
              jb = {},
              kb = {},
              lb = [],
              mb = {},
              nb = [],
              ob = {},
              pb = 0,
              qb = la(),
              rb = 0,
              sb = la(),
              tb = la(),
              ub = la(),
              vb = function (a, b) {
                  return a.x === b.x && a.y === b.y
              },
              wb = function (a, b) {
                  return Math.abs(a.x - b.x) < g && Math.abs(a.y - b.y) < g
              },
              xb = function (a, b) {
                  return ob.x = Math.abs(a.x - b.x), ob.y = Math.abs(a.y - b.y), Math.sqrt(ob.x * ob.x + ob.y * ob.y)
              },
              yb = function () {
                  Y && (I(Y), Y = null)
              },
              zb = function () {
                  U && (Y = H(zb), Pb())
              },
              Ab = function () {
                  return !("fit" === i.scaleMode && s === f.currItem.initialZoomLevel)
              },
              Bb = function (a, b) {
                  return a && a !== document ? a.getAttribute("class") && a.getAttribute("class").indexOf("pswp__scroll-wrap") > -1 ? !1 : b(a) ? a : Bb(a.parentNode, b) : !1
              },
              Cb = {},
              Db = function (a, b) {
                  return Cb.prevent = !Bb(a.target, i.isClickableElement), Ca("preventDragEvent", a, b, Cb), Cb.prevent
              },
              Eb = function (a, b) {
                  return b.x = a.pageX, b.y = a.pageY, b.id = a.identifier, b
              },
              Fb = function (a, b, c) {
                  c.x = .5 * (a.x + b.x), c.y = .5 * (a.y + b.y)
              },
              Gb = function (a, b, c) {
                  if (a - P > 50) {
                      var d = nb.length > 2 ? nb.shift() : {};
                      d.x = b, d.y = c, nb.push(d), P = a
                  }
              },
              Hb = function () {
                  var a = oa.y - f.currItem.initialPosition.y;
                  return 1 - Math.abs(a / (pa.y / 2))
              },
              Ib = {},
              Jb = {},
              Kb = [],
              Lb = function (a) {
                  for (; Kb.length > 0;) Kb.pop();
                  return F ? (ka = 0, lb.forEach(function (a) {
                      0 === ka ? Kb[0] = a : 1 === ka && (Kb[1] = a), ka++
                  })) : a.type.indexOf("touch") > -1 ? a.touches && a.touches.length > 0 && (Kb[0] = Eb(a.touches[0], Ib), a.touches.length > 1 && (Kb[1] = Eb(a.touches[1], Jb))) : (Ib.x = a.pageX, Ib.y = a.pageY, Ib.id = "", Kb[0] = Ib), Kb
              },
              Mb = function (a, b) {
                  var c, d, e, g, h = 0,
                      j = oa[a] + b[a],
                      k = b[a] > 0,
                      l = sb.x + b.x,
                      m = sb.x - mb.x;
                  return c = j > ca.min[a] || j < ca.max[a] ? i.panEndFriction : 1, j = oa[a] + b[a] * c, !i.allowPanToNext && s !== f.currItem.initialZoomLevel || (da ? "h" !== fa || "x" !== a || W || (k ? (j > ca.min[a] && (c = i.panEndFriction, h = ca.min[a] - j, d = ca.min[a] - na[a]), (0 >= d || 0 > m) && _b() > 1 ? (g = l, 0 > m && l > mb.x && (g = mb.x)) : ca.min.x !== ca.max.x && (e = j)) : (j < ca.max[a] && (c = i.panEndFriction, h = j - ca.max[a], d = na[a] - ca.max[a]), (0 >= d || m > 0) && _b() > 1 ? (g = l, m > 0 && l < mb.x && (g = mb.x)) : ca.min.x !== ca.max.x && (e = j))) : g = l, "x" !== a) ? void(ea || Z || s > f.currItem.fitRatio && (oa[a] += b[a] * c)) : (void 0 !== g && (Ja(g, !0), Z = g === mb.x ? !1 : !0), ca.min.x !== ca.max.x && (void 0 !== e ? oa.x = e : Z || (oa.x += b.x * c)), void 0 !== g)
              },
              Nb = function (a) {
                  if (!("mousedown" === a.type && a.button > 0)) {
                      if (Zb) return void a.preventDefault();
                      if (!T || "mousedown" !== a.type) {
                          if (Db(a, !0) && a.preventDefault(), Ca("pointerDown"), F) {
                              var b = e.arraySearch(lb, a.pointerId, "id");
                              0 > b && (b = lb.length), lb[b] = {
                                  x: a.pageX,
                                  y: a.pageY,
                                  id: a.pointerId
                              }
                          }
                          var c = Lb(a),
                              d = c.length;
                          $ = null, bb(), U && 1 !== d || (U = ga = !0, e.bind(window, p, f), R = ja = ha = S = Z = X = V = W = !1, fa = null, Ca("firstTouchStart", c), La(na, oa), ma.x = ma.y = 0, La(jb, c[0]), La(kb, jb), mb.x = sa.x * qa, nb = [{
                              x: jb.x,
                              y: jb.y
                          }], P = O = Da(), Ra(s, !0), yb(), zb()), !_ && d > 1 && !ea && !Z && (t = s, W = !1, _ = V = !0, ma.y = ma.x = 0, La(na, oa), La(gb, c[0]), La(hb, c[1]), Fb(gb, hb, ub), tb.x = Math.abs(ub.x) - oa.x, tb.y = Math.abs(ub.y) - oa.y, aa = ba = xb(gb, hb))
                      }
                  }
              },
              Ob = function (a) {
                  if (a.preventDefault(), F) {
                      var b = e.arraySearch(lb, a.pointerId, "id");
                      if (b > -1) {
                          var c = lb[b];
                          c.x = a.pageX, c.y = a.pageY
                      }
                  }
                  if (U) {
                      var d = Lb(a);
                      if (fa || X || _) $ = d;
                      else if (sb.x !== sa.x * qa) fa = "h";
                      else {
                          var f = Math.abs(d[0].x - jb.x) - Math.abs(d[0].y - jb.y);
                          Math.abs(f) >= fb && (fa = f > 0 ? "h" : "v", $ = d)
                      }
                  }
              },
              Pb = function () {
                  if ($) {
                      var a = $.length;
                      if (0 !== a)
                          if (La(gb, $[0]), ib.x = gb.x - jb.x, ib.y = gb.y - jb.y, _ && a > 1) {
                              if (jb.x = gb.x, jb.y = gb.y, !ib.x && !ib.y && vb($[1], hb)) return;
                              La(hb, $[1]), W || (W = !0, Ca("zoomGestureStarted"));
                              var b = xb(gb, hb),
                                  c = Ub(b);
                              c > f.currItem.initialZoomLevel + f.currItem.initialZoomLevel / 15 && (ja = !0);
                              var d = 1,
                                  e = Sa(),
                                  g = Ta();
                              if (e > c)
                                  if (i.pinchToClose && !ja && t <= f.currItem.initialZoomLevel) {
                                      var h = e - c,
                                          j = 1 - h / (e / 1.2);
                                      Ea(j), Ca("onPinchClose", j), ha = !0
                                  } else d = (e - c) / e, d > 1 && (d = 1), c = e - d * (e / 3);
                              else c > g && (d = (c - g) / (6 * e), d > 1 && (d = 1), c = g + d * e);
                              0 > d && (d = 0), aa = b, Fb(gb, hb, qb), ma.x += qb.x - ub.x, ma.y += qb.y - ub.y, La(ub, qb), oa.x = Ka("x", c), oa.y = Ka("y", c), R = c > s, s = c, Ga()
                          } else {
                              if (!fa) return;
                              if (ga && (ga = !1, Math.abs(ib.x) >= fb && (ib.x -= $[0].x - kb.x), Math.abs(ib.y) >= fb && (ib.y -= $[0].y - kb.y)), jb.x = gb.x, jb.y = gb.y, 0 === ib.x && 0 === ib.y) return;
                              if ("v" === fa && i.closeOnVerticalDrag && !Ab()) {
                                  ma.y += ib.y, oa.y += ib.y;
                                  var k = Hb();
                                  return S = !0, Ca("onVerticalDrag", k), Ea(k), void Ga()
                              }
                              Gb(Da(), gb.x, gb.y), X = !0, ca = f.currItem.bounds;
                              var l = Mb("x", ib);
                              l || (Mb("y", ib), Ma(oa), Ga())
                          }
                  }
              },
              Qb = function (a) {
                  if (N.isOldAndroid) {
                      if (T && "mouseup" === a.type) return;
                      a.type.indexOf("touch") > -1 && (clearTimeout(T), T = setTimeout(function () {
                          T = 0
                      }, 600))
                  }
                  Ca("pointerUp"), Db(a, !1) && a.preventDefault();
                  var b;
                  if (F) {
                      var c = e.arraySearch(lb, a.pointerId, "id");
                      if (c > -1)
                          if (b = lb.splice(c, 1)[0], navigator.pointerEnabled) b.type = a.pointerType || "mouse";
                          else {
                              var d = {
                                  4: "mouse",
                                  2: "touch",
                                  3: "pen"
                              };
                              b.type = d[a.pointerType], b.type || (b.type = a.pointerType || "mouse")
                          }
                  }
                  var g, h = Lb(a),
                      j = h.length;
                  if ("mouseup" === a.type && (j = 0), 2 === j) return $ = null, !0;
                  1 === j && La(kb, h[0]), 0 !== j || fa || ea || (b || ("mouseup" === a.type ? b = {
                      x: a.pageX,
                      y: a.pageY,
                      type: "mouse"
                  } : a.changedTouches && a.changedTouches[0] && (b = {
                      x: a.changedTouches[0].pageX,
                      y: a.changedTouches[0].pageY,
                      type: "touch"
                  })), Ca("touchRelease", a, b));
                  var k = -1;
                  if (0 === j && (U = !1, e.unbind(window, p, f), yb(), _ ? k = 0 : -1 !== rb && (k = Da() - rb)), rb = 1 === j ? Da() : -1, g = -1 !== k && 150 > k ? "zoom" : "swipe", _ && 2 > j && (_ = !1, 1 === j && (g = "zoomPointerUp"), Ca("zoomGestureEnded")), $ = null, X || W || ea || S)
                      if (bb(), Q || (Q = Rb()), Q.calculateSwipeSpeed("x"), S) {
                          var l = Hb();
                          if (l < i.verticalDragRange) f.close();
                          else {
                              var m = oa.y,
                                  n = ia;
                              cb("verticalDrag", 0, 1, 300, e.easing.cubic.out, function (a) {
                                  oa.y = (f.currItem.initialPosition.y - m) * a + m, Ea((1 - n) * a + n), Ga()
                              }), Ca("onVerticalDrag", 1)
                          }
                      } else {
                          if ((Z || ea) && 0 === j) {
                              var o = Tb(g, Q);
                              if (o) return;
                              g = "zoomPointerUp"
                          }
                          if (!ea) return "swipe" !== g ? void Vb() : void(!Z && s > f.currItem.fitRatio && Sb(Q))
                      }
              },
              Rb = function () {
                  var a, b, c = {
                      lastFlickOffset: {},
                      lastFlickDist: {},
                      lastFlickSpeed: {},
                      slowDownRatio: {},
                      slowDownRatioReverse: {},
                      speedDecelerationRatio: {},
                      speedDecelerationRatioAbs: {},
                      distanceOffset: {},
                      backAnimDestination: {},
                      backAnimStarted: {},
                      calculateSwipeSpeed: function (d) {
                          nb.length > 1 ? (a = Da() - P + 50, b = nb[nb.length - 2][d]) : (a = Da() - O, b = kb[d]), c.lastFlickOffset[d] = jb[d] - b, c.lastFlickDist[d] = Math.abs(c.lastFlickOffset[d]), c.lastFlickDist[d] > 20 ? c.lastFlickSpeed[d] = c.lastFlickOffset[d] / a : c.lastFlickSpeed[d] = 0, Math.abs(c.lastFlickSpeed[d]) < .1 && (c.lastFlickSpeed[d] = 0), c.slowDownRatio[d] = .95, c.slowDownRatioReverse[d] = 1 - c.slowDownRatio[d], c.speedDecelerationRatio[d] = 1
                      },
                      calculateOverBoundsAnimOffset: function (a, b) {
                          c.backAnimStarted[a] || (oa[a] > ca.min[a] ? c.backAnimDestination[a] = ca.min[a] : oa[a] < ca.max[a] && (c.backAnimDestination[a] = ca.max[a]), void 0 !== c.backAnimDestination[a] && (c.slowDownRatio[a] = .7, c.slowDownRatioReverse[a] = 1 - c.slowDownRatio[a], c.speedDecelerationRatioAbs[a] < .05 && (c.lastFlickSpeed[a] = 0, c.backAnimStarted[a] = !0, cb("bounceZoomPan" + a, oa[a], c.backAnimDestination[a], b || 300, e.easing.sine.out, function (b) {
                              oa[a] = b, Ga()
                          }))))
                      },
                      calculateAnimOffset: function (a) {
                          c.backAnimStarted[a] || (c.speedDecelerationRatio[a] = c.speedDecelerationRatio[a] * (c.slowDownRatio[a] + c.slowDownRatioReverse[a] - c.slowDownRatioReverse[a] * c.timeDiff / 10), c.speedDecelerationRatioAbs[a] = Math.abs(c.lastFlickSpeed[a] * c.speedDecelerationRatio[a]), c.distanceOffset[a] = c.lastFlickSpeed[a] * c.speedDecelerationRatio[a] * c.timeDiff, oa[a] += c.distanceOffset[a])
                      },
                      panAnimLoop: function () {
                          return Za.zoomPan && (Za.zoomPan.raf = H(c.panAnimLoop), c.now = Da(), c.timeDiff = c.now - c.lastNow, c.lastNow = c.now, c.calculateAnimOffset("x"), c.calculateAnimOffset("y"), Ga(), c.calculateOverBoundsAnimOffset("x"), c.calculateOverBoundsAnimOffset("y"), c.speedDecelerationRatioAbs.x < .05 && c.speedDecelerationRatioAbs.y < .05) ? (oa.x = Math.round(oa.x), oa.y = Math.round(oa.y), Ga(), void _a("zoomPan")) : void 0
                      }
                  };
                  return c
              },
              Sb = function (a) {
                  return a.calculateSwipeSpeed("y"), ca = f.currItem.bounds, a.backAnimDestination = {}, a.backAnimStarted = {}, Math.abs(a.lastFlickSpeed.x) <= .05 && Math.abs(a.lastFlickSpeed.y) <= .05 ? (a.speedDecelerationRatioAbs.x = a.speedDecelerationRatioAbs.y = 0, a.calculateOverBoundsAnimOffset("x"), a.calculateOverBoundsAnimOffset("y"), !0) : (ab("zoomPan"), a.lastNow = Da(), void a.panAnimLoop())
              },
              Tb = function (a, b) {
                  var c;
                  ea || (pb = m);
                  var d;
                  if ("swipe" === a) {
                      var g = jb.x - kb.x,
                          h = b.lastFlickDist.x < 10;
                      g > eb && (h || b.lastFlickOffset.x > 20) ? d = -1 : -eb > g && (h || b.lastFlickOffset.x < -20) && (d = 1)
                  }
                  var j;
                  d && (m += d, 0 > m ? (m = i.loop ? _b() - 1 : 0, j = !0) : m >= _b() && (m = i.loop ? 0 : _b() - 1, j = !0), (!j || i.loop) && (ta += d, qa -= d, c = !0));
                  var k, l = sa.x * qa,
                      n = Math.abs(l - sb.x);
                  return c || l > sb.x == b.lastFlickSpeed.x > 0 ? (k = Math.abs(b.lastFlickSpeed.x) > 0 ? n / Math.abs(b.lastFlickSpeed.x) : 333, k = Math.min(k, 400), k = Math.max(k, 250)) : k = 333, pb === m && (c = !1), ea = !0, Ca("mainScrollAnimStart"), cb("mainScroll", sb.x, l, k, e.easing.cubic.out, Ja, function () {
                      bb(), ea = !1, pb = -1, (c || pb !== m) && f.updateCurrItem(), Ca("mainScrollAnimComplete")
                  }), c && f.updateCurrItem(!0), c
              },
              Ub = function (a) {
                  return 1 / ba * a * t
              },
              Vb = function () {
                  var a = s,
                      b = Sa(),
                      c = Ta();
                  b > s ? a = b : s > c && (a = c);
                  var d, g = 1,
                      h = ia;
                  return ha && !R && !ja && b > s ? (f.close(), !0) : (ha && (d = function (a) {
                      Ea((g - h) * a + h)
                  }), f.zoomTo(a, 0, 200, e.easing.cubic.out, d), !0)
              };
          ya("Gestures", {
              publicMethods: {
                  initGestures: function () {
                      var a = function (a, b, c, d, e) {
                          A = a + b, B = a + c, C = a + d, D = e ? a + e : ""
                      };
                      F = N.pointerEvent, F && N.touch && (N.touch = !1), F ? navigator.pointerEnabled ? a("pointer", "down", "move", "up", "cancel") : a("MSPointer", "Down", "Move", "Up", "Cancel") : N.touch ? (a("touch", "start", "move", "end", "cancel"), G = !0) : a("mouse", "down", "move", "up"), p = B + " " + C + " " + D, q = A, F && !G && (G = navigator.maxTouchPoints > 1 || navigator.msMaxTouchPoints > 1), f.likelyTouchDevice = G, r[A] = Nb, r[B] = Ob, r[C] = Qb, D && (r[D] = r[C]), N.touch && (q += " mousedown", p += " mousemove mouseup", r.mousedown = r[A], r.mousemove = r[B], r.mouseup = r[C]), G || (i.allowPanToNext = !1)
                  }
              }
          });
          var Wb, Xb, Yb, Zb, $b, _b, ac, bc = function (b, c, d, g) {
                  Wb && clearTimeout(Wb), Zb = !0, Yb = !0;
                  var h;
                  b.initialLayout ? (h = b.initialLayout, b.initialLayout = null) : h = i.getThumbBoundsFn && i.getThumbBoundsFn(m);
                  var j = d ? i.hideAnimationDuration : i.showAnimationDuration,
                      k = function () {
                          _a("initialZoom"), d ? (f.template.removeAttribute("style"), f.bg.removeAttribute("style")) : (Ea(1), c && (c.style.display = "block"), e.addClass(a, "pswp--animated-in"), Ca("initialZoom" + (d ? "OutEnd" : "InEnd"))), g && g(), Zb = !1
                      };
                  if (!j || !h || void 0 === h.x) return Ca("initialZoom" + (d ? "Out" : "In")), s = b.initialZoomLevel, La(oa, b.initialPosition), Ga(), a.style.opacity = d ? 0 : 1, Ea(1), void(j ? setTimeout(function () {
                      k()
                  }, j) : k());
                  var n = function () {
                      var c = l,
                          g = !f.currItem.src || f.currItem.loadError || i.showHideOpacity;
                      b.miniImg && (b.miniImg.style.webkitBackfaceVisibility = "hidden"), d || (s = h.w / b.w, oa.x = h.x, oa.y = h.y - K, f[g ? "template" : "bg"].style.opacity = .001, Ga()), ab("initialZoom"), d && !c && e.removeClass(a, "pswp--animated-in"), g && (d ? e[(c ? "remove" : "add") + "Class"](a, "pswp--animate_opacity") : setTimeout(function () {
                          e.addClass(a, "pswp--animate_opacity")
                      }, 30)), Wb = setTimeout(function () {
                          if (Ca("initialZoom" + (d ? "Out" : "In")), d) {
                              var f = h.w / b.w,
                                  i = {
                                      x: oa.x,
                                      y: oa.y
                                  },
                                  l = s,
                                  m = ia,
                                  n = function (b) {
                                      1 === b ? (s = f, oa.x = h.x, oa.y = h.y - M) : (s = (f - l) * b + l, oa.x = (h.x - i.x) * b + i.x, oa.y = (h.y - M - i.y) * b + i.y), Ga(), g ? a.style.opacity = 1 - b : Ea(m - b * m)
                                  };
                              c ? cb("initialZoom", 0, 1, j, e.easing.cubic.out, n, k) : (n(1), Wb = setTimeout(k, j + 20))
                          } else s = b.initialZoomLevel, La(oa, b.initialPosition), Ga(), Ea(1), g ? a.style.opacity = 1 : Ea(1), Wb = setTimeout(k, j + 20)
                      }, d ? 25 : 90)
                  };
                  n()
              },
              cc = {},
              dc = [],
              ec = {
                  index: 0,
                  errorMsg: '<div class="pswp__error-msg"><a href="%url%" target="_blank">The image</a> could not be loaded.</div>',
                  forceProgressiveLoading: !1,
                  preload: [1, 1],
                  getNumItemsFn: function () {
                      return Xb.length
                  }
              },
              fc = function () {
                  return {
                      center: {
                          x: 0,
                          y: 0
                      },
                      max: {
                          x: 0,
                          y: 0
                      },
                      min: {
                          x: 0,
                          y: 0
                      }
                  }
              },
              gc = function (a, b, c) {
                  var d = a.bounds;
                  d.center.x = Math.round((cc.x - b) / 2), d.center.y = Math.round((cc.y - c) / 2) + a.vGap.top, d.max.x = b > cc.x ? Math.round(cc.x - b) : d.center.x, d.max.y = c > cc.y ? Math.round(cc.y - c) + a.vGap.top : d.center.y, d.min.x = b > cc.x ? 0 : d.center.x, d.min.y = c > cc.y ? a.vGap.top : d.center.y
              },
              hc = function (a, b, c) {
                  if (a.src && !a.loadError) {
                      var d = !c;
                      if (d && (a.vGap || (a.vGap = {
                              top: 0,
                              bottom: 0
                          }), Ca("parseVerticalMargin", a)), cc.x = b.x, cc.y = b.y - a.vGap.top - a.vGap.bottom, d) {
                          var e = cc.x / a.w,
                              f = cc.y / a.h;
                          a.fitRatio = f > e ? e : f;
                          var g = i.scaleMode;
                          "orig" === g ? c = 1 : "fit" === g && (c = a.fitRatio), c > 1 && (c = 1), a.initialZoomLevel = c, a.bounds || (a.bounds = fc())
                      }
                      if (!c) return;
                      return gc(a, a.w * c, a.h * c), d && c === a.initialZoomLevel && (a.initialPosition = a.bounds.center), a.bounds
                  }
                  return a.w = a.h = 0, a.initialZoomLevel = a.fitRatio = 1, a.bounds = fc(), a.initialPosition = a.bounds.center, a.bounds
              },
              ic = function (a, b, c, d, e, g) {
                  b.loadError || d && (b.imageAppended = !0, lc(b, d, b === f.currItem && xa), c.appendChild(d), g && setTimeout(function () {
                      b && b.loaded && b.placeholder && (b.placeholder.style.display = "none", b.placeholder = null)
                  }, 500))
              },
              jc = function (a) {
                  a.loading = !0, a.loaded = !1;
                  var b = a.img = e.createEl("pswp__img", "img"),
                      c = function () {
                          a.loading = !1, a.loaded = !0, a.loadComplete ? a.loadComplete(a) : a.img = null, b.onload = b.onerror = null, b = null
                      };
                  return b.onload = c, b.onerror = function () {
                      a.loadError = !0, c()
                  }, b.src = a.src, b
              },
              kc = function (a, b) {
                  return a.src && a.loadError && a.container ? (b && (a.container.innerHTML = ""), a.container.innerHTML = i.errorMsg.replace("%url%", a.src), !0) : void 0
              },
              lc = function (a, b, c) {
                  if (a.src) {
                      b || (b = a.container.lastChild);
                      var d = c ? a.w : Math.round(a.w * a.fitRatio),
                          e = c ? a.h : Math.round(a.h * a.fitRatio);
                      a.placeholder && !a.loaded && (a.placeholder.style.width = d + "px", a.placeholder.style.height = e + "px"), b.style.width = d + "px", b.style.height = e + "px"
                  }
              },
              mc = function () {
                  if (dc.length) {
                      for (var a, b = 0; b < dc.length; b++) a = dc[b], a.holder.index === a.index && ic(a.index, a.item, a.baseDiv, a.img, !1, a.clearPlaceholder);
                      dc = []
                  }
              };
          ya("Controller", {
              publicMethods: {
                  lazyLoadItem: function (a) {
                      a = za(a);
                      var b = $b(a);
                      b && (!b.loaded && !b.loading || x) && (Ca("gettingData", a, b), b.src && jc(b))
                  },
                  initController: function () {
                      e.extend(i, ec, !0), f.items = Xb = c, $b = f.getItemAt, _b = i.getNumItemsFn, ac = i.loop, _b() < 3 && (i.loop = !1), Ba("beforeChange", function (a) {
                          var b, c = i.preload,
                              d = null === a ? !0 : a >= 0,
                              e = Math.min(c[0], _b()),
                              g = Math.min(c[1], _b());
                          for (b = 1;
                              (d ? g : e) >= b; b++) f.lazyLoadItem(m + b);
                          for (b = 1;
                              (d ? e : g) >= b; b++) f.lazyLoadItem(m - b)
                      }), Ba("initialLayout", function () {
                          f.currItem.initialLayout = i.getThumbBoundsFn && i.getThumbBoundsFn(m)
                      }), Ba("mainScrollAnimComplete", mc), Ba("initialZoomInEnd", mc), Ba("destroy", function () {
                          for (var a, b = 0; b < Xb.length; b++) a = Xb[b], a.container && (a.container = null), a.placeholder && (a.placeholder = null), a.img && (a.img = null), a.preloader && (a.preloader = null), a.loadError && (a.loaded = a.loadError = !1);
                          dc = null
                      })
                  },
                  getItemAt: function (a) {
                      return a >= 0 && void 0 !== Xb[a] ? Xb[a] : !1
                  },
                  allowProgressiveImg: function () {
                      return i.forceProgressiveLoading || !G || i.mouseUsed || screen.width > 1200
                  },
                  setContent: function (a, b) {
                      i.loop && (b = za(b));
                      var c = f.getItemAt(a.index);
                      c && (c.container = null);
                      var d, g = f.getItemAt(b);
                      if (!g) return void(a.el.innerHTML = "");
                      Ca("gettingData", b, g), a.index = b, a.item = g;
                      var h = g.container = e.createEl("pswp__zoom-wrap");
                      if (!g.src && g.html && (g.html.tagName ? h.appendChild(g.html) : h.innerHTML = g.html), kc(g), hc(g, pa), !g.src || g.loadError || g.loaded) g.src && !g.loadError && (d = e.createEl("pswp__img", "img"), d.style.opacity = 1, d.src = g.src, lc(g, d), ic(b, g, h, d, !0));
                      else {
                          if (g.loadComplete = function (c) {
                                  if (j) {
                                      if (a && a.index === b) {
                                          if (kc(c, !0)) return c.loadComplete = c.img = null, hc(c, pa), Ha(c), void(a.index === m && f.updateCurrZoomItem());
                                          c.imageAppended ? !Zb && c.placeholder && (c.placeholder.style.display = "none", c.placeholder = null) : N.transform && (ea || Zb) ? dc.push({
                                              item: c,
                                              baseDiv: h,
                                              img: c.img,
                                              index: b,
                                              holder: a,
                                              clearPlaceholder: !0
                                          }) : ic(b, c, h, c.img, ea || Zb, !0)
                                      }
                                      c.loadComplete = null, c.img = null, Ca("imageLoadComplete", b, c)
                                  }
                              }, e.features.transform) {
                              var k = "pswp__img pswp__img--placeholder";
                              k += g.msrc ? "" : " pswp__img--placeholder--blank";
                              var l = e.createEl(k, g.msrc ? "img" : "");
                              g.msrc && (l.src = g.msrc), lc(g, l), h.appendChild(l), g.placeholder = l
                          }
                          g.loading || jc(g), f.allowProgressiveImg() && (!Yb && N.transform ? dc.push({
                              item: g,
                              baseDiv: h,
                              img: g.img,
                              index: b,
                              holder: a
                          }) : ic(b, g, h, g.img, !0, !0))
                      }
                      Yb || b !== m ? Ha(g) : (da = h.style, bc(g, d || g.img)), a.el.innerHTML = "", a.el.appendChild(h)
                  },
                  cleanSlide: function (a) {
                      a.img && (a.img.onload = a.img.onerror = null), a.loaded = a.loading = a.img = a.imageAppended = !1
                  }
              }
          });
          var nc, oc = {},
              pc = function (a, b, c) {
                  var d = document.createEvent("CustomEvent"),
                      e = {
                          origEvent: a,
                          target: a.target,
                          releasePoint: b,
                          pointerType: c || "touch"
                      };
                  d.initCustomEvent("pswpTap", !0, !0, e), a.target.dispatchEvent(d)
              };
          ya("Tap", {
              publicMethods: {
                  initTap: function () {
                      Ba("firstTouchStart", f.onTapStart), Ba("touchRelease", f.onTapRelease), Ba("destroy", function () {
                          oc = {}, nc = null
                      })
                  },
                  onTapStart: function (a) {
                      a.length > 1 && (clearTimeout(nc), nc = null)
                  },
                  onTapRelease: function (a, b) {
                      if (b && !X && !V && !$a) {
                          var c = b;
                          if (nc && (clearTimeout(nc), nc = null, wb(c, oc))) return void Ca("doubleTap", c);
                          if ("mouse" === b.type) return void pc(a, b, "mouse");
                          var d = a.target.tagName.toUpperCase();
                          if ("BUTTON" === d || e.hasClass(a.target, "pswp__single-tap")) return void pc(a, b);
                          La(oc, c), nc = setTimeout(function () {
                              pc(a, b), nc = null
                          }, 300)
                      }
                  }
              }
          });
          var qc;
          ya("DesktopZoom", {
              publicMethods: {
                  initDesktopZoom: function () {
                      L || (G ? Ba("mouseUsed", function () {
                          f.setupDesktopZoom()
                      }) : f.setupDesktopZoom(!0))
                  },
                  setupDesktopZoom: function (b) {
                      qc = {};
                      var c = "wheel mousewheel DOMMouseScroll";
                      Ba("bindEvents", function () {
                          e.bind(a, c, f.handleMouseWheel)
                      }), Ba("unbindEvents", function () {
                          qc && e.unbind(a, c, f.handleMouseWheel)
                      }), f.mouseZoomedIn = !1;
                      var d, g = function () {
                              f.mouseZoomedIn && (e.removeClass(a, "pswp--zoomed-in"), f.mouseZoomedIn = !1), 1 > s ? e.addClass(a, "pswp--zoom-allowed") : e.removeClass(a, "pswp--zoom-allowed"), h()
                          },
                          h = function () {
                              d && (e.removeClass(a, "pswp--dragging"), d = !1)
                          };
                      Ba("resize", g), Ba("afterChange", g), Ba("pointerDown", function () {
                          f.mouseZoomedIn && (d = !0, e.addClass(a, "pswp--dragging"))
                      }), Ba("pointerUp", h), b || g()
                  },
                  handleMouseWheel: function (a) {
                      if (s <= f.currItem.fitRatio) return i.modal && (!i.closeOnScroll || $a || U ? a.preventDefault() : E && Math.abs(a.deltaY) > 2 && (l = !0, f.close())), !0;
                      if (a.stopPropagation(), qc.x = 0, "deltaX" in a) 1 === a.deltaMode ? (qc.x = 18 * a.deltaX, qc.y = 18 * a.deltaY) : (qc.x = a.deltaX, qc.y = a.deltaY);
                      else if ("wheelDelta" in a) a.wheelDeltaX && (qc.x = -.16 * a.wheelDeltaX), a.wheelDeltaY ? qc.y = -.16 * a.wheelDeltaY : qc.y = -.16 * a.wheelDelta;
                      else {
                          if (!("detail" in a)) return;
                          qc.y = a.detail
                      }
                      Ra(s, !0);
                      var b = oa.x - qc.x,
                          c = oa.y - qc.y;
                      (i.modal || b <= ca.min.x && b >= ca.max.x && c <= ca.min.y && c >= ca.max.y) && a.preventDefault(), f.panTo(b, c)
                  },
                  toggleDesktopZoom: function (b) {
                      b = b || {
                          x: pa.x / 2 + ra.x,
                          y: pa.y / 2 + ra.y
                      };
                      var c = i.getDoubleTapZoom(!0, f.currItem),
                          d = s === c;
                      f.mouseZoomedIn = !d, f.zoomTo(d ? f.currItem.initialZoomLevel : c, b, 333), e[(d ? "remove" : "add") + "Class"](a, "pswp--zoomed-in")
                  }
              }
          });
          var rc, sc, tc, uc, vc, wc, xc, yc, zc, Ac, Bc, Cc, Dc = {
                  history: !0,
                  galleryUID: 1
              },
              Ec = function () {
                  return Bc.hash.substring(1)
              },
              Fc = function () {
                  rc && clearTimeout(rc), tc && clearTimeout(tc)
              },
              Gc = function () {
                  var a = Ec(),
                      b = {};
                  if (a.length < 5) return b;
                  var c, d = a.split("&");
                  for (c = 0; c < d.length; c++)
                      if (d[c]) {
                          var e = d[c].split("=");
                          e.length < 2 || (b[e[0]] = e[1])
                      }
                  if (i.galleryPIDs) {
                      var f = b.pid;
                      for (b.pid = 0, c = 0; c < Xb.length; c++)
                          if (Xb[c].pid === f) {
                              b.pid = c;
                              break
                          }
                  } else b.pid = parseInt(b.pid, 10) - 1;
                  return b.pid < 0 && (b.pid = 0), b
              },
              Hc = function () {
                  if (tc && clearTimeout(tc), $a || U) return void(tc = setTimeout(Hc, 500));
                  uc ? clearTimeout(sc) : uc = !0;
                  var a = m + 1,
                      b = $b(m);
                  b.hasOwnProperty("pid") && (a = b.pid);
                  var c = xc + "&gid=" + i.galleryUID + "&pid=" + a;
                  yc || -1 === Bc.hash.indexOf(c) && (Ac = !0);
                  var d = Bc.href.split("#")[0] + "#" + c;
                  Cc ? "#" + c !== window.location.hash && history[yc ? "replaceState" : "pushState"]("", document.title, d) : yc ? Bc.replace(d) : Bc.hash = c, yc = !0, sc = setTimeout(function () {
                      uc = !1
                  }, 60)
              };
          ya("History", {
              publicMethods: {
                  initHistory: function () {
                      if (e.extend(i, Dc, !0), i.history) {
                          Bc = window.location, Ac = !1, zc = !1, yc = !1, xc = Ec(), Cc = "pushState" in history, xc.indexOf("gid=") > -1 && (xc = xc.split("&gid=")[0], xc = xc.split("?gid=")[0]), Ba("afterChange", f.updateURL), Ba("unbindEvents", function () {
                              e.unbind(window, "hashchange", f.onHashChange)
                          });
                          var a = function () {
                              wc = !0, zc || (Ac ? history.back() : xc ? Bc.hash = xc : Cc ? history.pushState("", document.title, Bc.pathname + Bc.search) : Bc.hash = ""), Fc()
                          };
                          Ba("unbindEvents", function () {
                              l && a()
                          }), Ba("destroy", function () {
                              wc || a()
                          }), Ba("firstUpdate", function () {
                              m = Gc().pid
                          });
                          var b = xc.indexOf("pid=");
                          b > -1 && (xc = xc.substring(0, b), "&" === xc.slice(-1) && (xc = xc.slice(0, -1))), setTimeout(function () {
                              j && e.bind(window, "hashchange", f.onHashChange)
                          }, 40)
                      }
                  },
                  onHashChange: function () {
                      return Ec() === xc ? (zc = !0, void f.close()) : void(uc || (vc = !0, f.goTo(Gc().pid), vc = !1))
                  },
                  updateURL: function () {
                      Fc(), vc || (yc ? rc = setTimeout(Hc, 800) : Hc())
                  }
              }
          }), e.extend(f, db)
      };
      return a
  });
  
  /*! PhotoSwipe Default UI - 4.1.1 - 2015-12-24
   * http://photoswipe.com
   * Copyright (c) 2015 Dmitry Semenov; */
  ! function (a, b) {
      "function" == typeof define && define.amd ? define(b) : "object" == typeof exports ? module.exports = b() : a.PhotoSwipeUI_Default = b()
  }(this, function () {
      "use strict";
      var a = function (a, b) {
          var c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v = this,
              w = !1,
              x = !0,
              y = !0,
              z = {
                  barsSize: {
                      top: 44,
                      bottom: "auto"
                  },
                  closeElClasses: ["item", "caption", "zoom-wrap", "ui", "top-bar"],
                  timeToIdle: 4e3,
                  timeToIdleOutside: 1e3,
                  loadingIndicatorDelay: 1e3,
                  addCaptionHTMLFn: function (a, b) {
                      return a.title ? (b.children[0].innerHTML = a.title, !0) : (b.children[0].innerHTML = "", !1)
                  },
                  closeEl: !0,
                  captionEl: !0,
                  fullscreenEl: !0,
                  zoomEl: !0,
                  shareEl: !0,
                  counterEl: !0,
                  arrowEl: !0,
                  preloaderEl: !0,
                  tapToClose: !1,
                  tapToToggleControls: !0,
                  clickToCloseNonZoomable: !0,
                  shareButtons: [{
                      id: "facebook",
                      label: "Share on Facebook",
                      url: "https://www.facebook.com/sharer/sharer.php?u={{url}}"
                  }, {
                      id: "twitter",
                      label: "Tweet",
                      url: "https://twitter.com/intent/tweet?text={{text}}&url={{url}}"
                  }, {
                      id: "pinterest",
                      label: "Pin it",
                      url: "http://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}"
                  }, {
                      id: "download",
                      label: "Download image",
                      url: "{{raw_image_url}}",
                      download: !0
                  }],
                  getImageURLForShare: function () {
                      return a.currItem.src || ""
                  },
                  getPageURLForShare: function () {
                      return window.location.href
                  },
                  getTextForShare: function () {
                      return a.currItem.title || ""
                  },
                  indexIndicatorSep: " / ",
                  fitControlsWidth: 1200
              },
              A = function (a) {
                  if (r) return !0;
                  a = a || window.event, q.timeToIdle && q.mouseUsed && !k && K();
                  for (var c, d, e = a.target || a.srcElement, f = e.getAttribute("class") || "", g = 0; g < S.length; g++) c = S[g], c.onTap && f.indexOf("pswp__" + c.name) > -1 && (c.onTap(), d = !0);
                  if (d) {
                      a.stopPropagation && a.stopPropagation(), r = !0;
                      var h = b.features.isOldAndroid ? 600 : 30;
                      s = setTimeout(function () {
                          r = !1
                      }, h)
                  }
              },
              B = function () {
                  return !a.likelyTouchDevice || q.mouseUsed || screen.width > q.fitControlsWidth
              },
              C = function (a, c, d) {
                  b[(d ? "add" : "remove") + "Class"](a, "pswp__" + c)
              },
              D = function () {
                  var a = 1 === q.getNumItemsFn();
                  a !== p && (C(d, "ui--one-slide", a), p = a)
              },
              E = function () {
                  C(i, "share-modal--hidden", y)
              },
              F = function () {
                  return y = !y, y ? (b.removeClass(i, "pswp__share-modal--fade-in"), setTimeout(function () {
                      y && E()
                  }, 300)) : (E(), setTimeout(function () {
                      y || b.addClass(i, "pswp__share-modal--fade-in")
                  }, 30)), y || H(), !1
              },
              G = function (b) {
                  b = b || window.event;
                  var c = b.target || b.srcElement;
                  return a.shout("shareLinkClick", b, c), c.href ? c.hasAttribute("download") ? !0 : (window.open(c.href, "pswp_share", "scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left=" + (window.screen ? Math.round(screen.width / 2 - 275) : 100)), y || F(), !1) : !1
              },
              H = function () {
                  for (var a, b, c, d, e, f = "", g = 0; g < q.shareButtons.length; g++) a = q.shareButtons[g], c = q.getImageURLForShare(a), d = q.getPageURLForShare(a), e = q.getTextForShare(a), b = a.url.replace("{{url}}", encodeURIComponent(d)).replace("{{image_url}}", encodeURIComponent(c)).replace("{{raw_image_url}}", c).replace("{{text}}", encodeURIComponent(e)), f += '<a href="' + b + '" target="_blank" class="pswp__share--' + a.id + '"' + (a.download ? "download" : "") + ">" + a.label + "</a>", q.parseShareButtonOut && (f = q.parseShareButtonOut(a, f));
                  i.children[0].innerHTML = f, i.children[0].onclick = G
              },
              I = function (a) {
                  for (var c = 0; c < q.closeElClasses.length; c++)
                      if (b.hasClass(a, "pswp__" + q.closeElClasses[c])) return !0
              },
              J = 0,
              K = function () {
                  clearTimeout(u), J = 0, k && v.setIdle(!1)
              },
              L = function (a) {
                  a = a ? a : window.event;
                  var b = a.relatedTarget || a.toElement;
                  b && "HTML" !== b.nodeName || (clearTimeout(u), u = setTimeout(function () {
                      v.setIdle(!0)
                  }, q.timeToIdleOutside))
              },
              M = function () {
                  q.fullscreenEl && !b.features.isOldAndroid && (c || (c = v.getFullscreenAPI()), c ? (b.bind(document, c.eventK, v.updateFullscreen), v.updateFullscreen(), b.addClass(a.template, "pswp--supports-fs")) : b.removeClass(a.template, "pswp--supports-fs"))
              },
              N = function () {
                  q.preloaderEl && (O(!0), l("beforeChange", function () {
                      clearTimeout(o), o = setTimeout(function () {
                          a.currItem && a.currItem.loading ? (!a.allowProgressiveImg() || a.currItem.img && !a.currItem.img.naturalWidth) && O(!1) : O(!0)
                      }, q.loadingIndicatorDelay)
                  }), l("imageLoadComplete", function (b, c) {
                      a.currItem === c && O(!0)
                  }))
              },
              O = function (a) {
                  n !== a && (C(m, "preloader--active", !a), n = a)
              },
              P = function (a) {
                  var c = a.vGap;
                  if (B()) {
                      var g = q.barsSize;
                      if (q.captionEl && "auto" === g.bottom)
                          if (f || (f = b.createEl("pswp__caption pswp__caption--fake"), f.appendChild(b.createEl("pswp__caption__center")), d.insertBefore(f, e), b.addClass(d, "pswp__ui--fit")), q.addCaptionHTMLFn(a, f, !0)) {
                              var h = f.clientHeight;
                              c.bottom = parseInt(h, 10) || 44
                          } else c.bottom = g.top;
                      else c.bottom = "auto" === g.bottom ? 0 : g.bottom;
                      c.top = g.top
                  } else c.top = c.bottom = 0
              },
              Q = function () {
                  q.timeToIdle && l("mouseUsed", function () {
                      b.bind(document, "mousemove", K), b.bind(document, "mouseout", L), t = setInterval(function () {
                          J++, 2 === J && v.setIdle(!0)
                      }, q.timeToIdle / 2)
                  })
              },
              R = function () {
                  l("onVerticalDrag", function (a) {
                      x && .95 > a ? v.hideControls() : !x && a >= .95 && v.showControls()
                  });
                  var a;
                  l("onPinchClose", function (b) {
                      x && .9 > b ? (v.hideControls(), a = !0) : a && !x && b > .9 && v.showControls()
                  }), l("zoomGestureEnded", function () {
                      a = !1, a && !x && v.showControls()
                  })
              },
              S = [{
                  name: "caption",
                  option: "captionEl",
                  onInit: function (a) {
                      e = a
                  }
              }, {
                  name: "share-modal",
                  option: "shareEl",
                  onInit: function (a) {
                      i = a
                  },
                  onTap: function () {
                      F()
                  }
              }, {
                  name: "button--share",
                  option: "shareEl",
                  onInit: function (a) {
                      h = a
                  },
                  onTap: function () {
                      F()
                  }
              }, {
                  name: "button--zoom",
                  option: "zoomEl",
                  onTap: a.toggleDesktopZoom
              }, {
                  name: "counter",
                  option: "counterEl",
                  onInit: function (a) {
                      g = a
                  }
              }, {
                  name: "button--close",
                  option: "closeEl",
                  onTap: a.close
              }, {
                  name: "button--arrow--left",
                  option: "arrowEl",
                  onTap: a.prev
              }, {
                  name: "button--arrow--right",
                  option: "arrowEl",
                  onTap: a.next
              }, {
                  name: "button--fs",
                  option: "fullscreenEl",
                  onTap: function () {
                      c.isFullscreen() ? c.exit() : c.enter()
                  }
              }, {
                  name: "preloader",
                  option: "preloaderEl",
                  onInit: function (a) {
                      m = a
                  }
              }],
              T = function () {
                  var a, c, e, f = function (d) {
                      if (d)
                          for (var f = d.length, g = 0; f > g; g++) {
                              a = d[g], c = a.className;
                              for (var h = 0; h < S.length; h++) e = S[h], c.indexOf("pswp__" + e.name) > -1 && (q[e.option] ? (b.removeClass(a, "pswp__element--disabled"), e.onInit && e.onInit(a)) : b.addClass(a, "pswp__element--disabled"))
                          }
                  };
                  f(d.children);
                  var g = b.getChildByClass(d, "pswp__top-bar");
                  g && f(g.children)
              };
          v.init = function () {
              b.extend(a.options, z, !0), q = a.options, d = b.getChildByClass(a.scrollWrap, "pswp__ui"), l = a.listen, R(), l("beforeChange", v.update), l("doubleTap", function (b) {
                  var c = a.currItem.initialZoomLevel;
                  a.getZoomLevel() !== c ? a.zoomTo(c, b, 333) : a.zoomTo(q.getDoubleTapZoom(!1, a.currItem), b, 333)
              }), l("preventDragEvent", function (a, b, c) {
                  var d = a.target || a.srcElement;
                  d && d.getAttribute("class") && a.type.indexOf("mouse") > -1 && (d.getAttribute("class").indexOf("__caption") > 0 || /(SMALL|STRONG|EM)/i.test(d.tagName)) && (c.prevent = !1)
              }), l("bindEvents", function () {
                  b.bind(d, "pswpTap click", A), b.bind(a.scrollWrap, "pswpTap", v.onGlobalTap), a.likelyTouchDevice || b.bind(a.scrollWrap, "mouseover", v.onMouseOver)
              }), l("unbindEvents", function () {
                  y || F(), t && clearInterval(t), b.unbind(document, "mouseout", L), b.unbind(document, "mousemove", K), b.unbind(d, "pswpTap click", A), b.unbind(a.scrollWrap, "pswpTap", v.onGlobalTap), b.unbind(a.scrollWrap, "mouseover", v.onMouseOver), c && (b.unbind(document, c.eventK, v.updateFullscreen), c.isFullscreen() && (q.hideAnimationDuration = 0, c.exit()), c = null)
              }), l("destroy", function () {
                  q.captionEl && (f && d.removeChild(f), b.removeClass(e, "pswp__caption--empty")), i && (i.children[0].onclick = null), b.removeClass(d, "pswp__ui--over-close"), b.addClass(d, "pswp__ui--hidden"), v.setIdle(!1)
              }), q.showAnimationDuration || b.removeClass(d, "pswp__ui--hidden"), l("initialZoomIn", function () {
                  q.showAnimationDuration && b.removeClass(d, "pswp__ui--hidden")
              }), l("initialZoomOut", function () {
                  b.addClass(d, "pswp__ui--hidden")
              }), l("parseVerticalMargin", P), T(), q.shareEl && h && i && (y = !0), D(), Q(), M(), N()
          }, v.setIdle = function (a) {
              k = a, C(d, "ui--idle", a)
          }, v.update = function () {
              x && a.currItem ? (v.updateIndexIndicator(), q.captionEl && (q.addCaptionHTMLFn(a.currItem, e), C(e, "caption--empty", !a.currItem.title)), w = !0) : w = !1, y || F(), D()
          }, v.updateFullscreen = function (d) {
              d && setTimeout(function () {
                  a.setScrollOffset(0, b.getScrollY())
              }, 50), b[(c.isFullscreen() ? "add" : "remove") + "Class"](a.template, "pswp--fs")
          }, v.updateIndexIndicator = function () {
              q.counterEl && (g.innerHTML = a.getCurrentIndex() + 1 + q.indexIndicatorSep + q.getNumItemsFn())
          }, v.onGlobalTap = function (c) {
              c = c || window.event;
              var d = c.target || c.srcElement;
              if (!r)
                  if (c.detail && "mouse" === c.detail.pointerType) {
                      if (I(d)) return void a.close();
                      b.hasClass(d, "pswp__img") && (1 === a.getZoomLevel() && a.getZoomLevel() <= a.currItem.fitRatio ? q.clickToCloseNonZoomable && a.close() : a.toggleDesktopZoom(c.detail.releasePoint))
                  } else if (q.tapToToggleControls && (x ? v.hideControls() : v.showControls()), q.tapToClose && (b.hasClass(d, "pswp__img") || I(d))) return void a.close()
          }, v.onMouseOver = function (a) {
              a = a || window.event;
              var b = a.target || a.srcElement;
              C(d, "ui--over-close", I(b))
          }, v.hideControls = function () {
              b.addClass(d, "pswp__ui--hidden"), x = !1
          }, v.showControls = function () {
              x = !0, w || v.update(), b.removeClass(d, "pswp__ui--hidden")
          }, v.supportsFullscreen = function () {
              var a = document;
              return !!(a.exitFullscreen || a.mozCancelFullScreen || a.webkitExitFullscreen || a.msExitFullscreen)
          }, v.getFullscreenAPI = function () {
              var b, c = document.documentElement,
                  d = "fullscreenchange";
              return c.requestFullscreen ? b = {
                  enterK: "requestFullscreen",
                  exitK: "exitFullscreen",
                  elementK: "fullscreenElement",
                  eventK: d
              } : c.mozRequestFullScreen ? b = {
                  enterK: "mozRequestFullScreen",
                  exitK: "mozCancelFullScreen",
                  elementK: "mozFullScreenElement",
                  eventK: "moz" + d
              } : c.webkitRequestFullscreen ? b = {
                  enterK: "webkitRequestFullscreen",
                  exitK: "webkitExitFullscreen",
                  elementK: "webkitFullscreenElement",
                  eventK: "webkit" + d
              } : c.msRequestFullscreen && (b = {
                  enterK: "msRequestFullscreen",
                  exitK: "msExitFullscreen",
                  elementK: "msFullscreenElement",
                  eventK: "MSFullscreenChange"
              }), b && (b.enter = function () {
                  return j = q.closeOnScroll, q.closeOnScroll = !1, "webkitRequestFullscreen" !== this.enterK ? a.template[this.enterK]() : void a.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT)
              }, b.exit = function () {
                  return q.closeOnScroll = j, document[this.exitK]()
              }, b.isFullscreen = function () {
                  return document[this.elementK]
              }), b
          }
      };
      return a
  });
  
  var initPhotoSwipeFromDOM = function (gallerySelector) {
  
      // parse slide data (url, title, size ...) from DOM elements 
      // (children of gallerySelector)
      var parseThumbnailElements = function (el) {
          var thumbElements = el.childNodes,
              numNodes = thumbElements.length,
              items = [],
              figureEl,
              linkEl,
              size,
              item;
  
          for (var i = 0; i < numNodes; i++) {
  
              figureEl = thumbElements[i]; // <figure> element
  
              // include only element nodes 
              if (figureEl.nodeType !== 1) {
                  continue;
              }
  
              linkEl = figureEl.children[0]; // <a> element
  
              size = linkEl.getAttribute('data-size').split('x');
  
              // create slide object
              item = {
                  src: linkEl.getAttribute('href'),
                  w: parseInt(size[0], 10),
                  h: parseInt(size[1], 10)
              };
  
  
  
              if (figureEl.children.length > 1) {
                  // <figcaption> content
                  item.title = figureEl.children[1].innerHTML;
              }
  
              if (linkEl.children.length > 0) {
                  // <img> thumbnail element, retrieving thumbnail url
                  item.msrc = linkEl.children[0].getAttribute('src');
              }
  
              item.el = figureEl; // save link to element for getThumbBoundsFn
              items.push(item);
          }
  
          return items;
      };
  
      // find nearest parent element
      var closest = function closest(el, fn) {
          return el && (fn(el) ? el : closest(el.parentNode, fn));
      };
  
      // triggers when user clicks on thumbnail
      var onThumbnailsClick = function (e) {
          e = e || window.event;
          e.preventDefault ? e.preventDefault() : e.returnValue = false;
  
          var eTarget = e.target || e.srcElement;
  
          // find root element of slide
          var clickedListItem = closest(eTarget, function (el) {
              return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
          });
  
          if (!clickedListItem) {
              return;
          }
  
          // find index of clicked item by looping through all child nodes
          // alternatively, you may define index via data- attribute
          var clickedGallery = clickedListItem.parentNode,
              childNodes = clickedListItem.parentNode.childNodes,
              numChildNodes = childNodes.length,
              nodeIndex = 0,
              index;
  
          for (var i = 0; i < numChildNodes; i++) {
              if (childNodes[i].nodeType !== 1) {
                  continue;
              }
  
              if (childNodes[i] === clickedListItem) {
                  index = nodeIndex;
                  break;
              }
              nodeIndex++;
          }
  
  
  
          if (index >= 0) {
              // open PhotoSwipe if valid index found
              openPhotoSwipe(index, clickedGallery);
          }
          return false;
      };
  
      // parse picture index and gallery index from URL (#&pid=1&gid=2)
      var photoswipeParseHash = function () {
          var hash = window.location.hash.substring(1),
              params = {};
  
          if (hash.length < 5) {
              return params;
          }
  
          var vars = hash.split('&');
          for (var i = 0; i < vars.length; i++) {
              if (!vars[i]) {
                  continue;
              }
              var pair = vars[i].split('=');
              if (pair.length < 2) {
                  continue;
              }
              params[pair[0]] = pair[1];
          }
  
          if (params.gid) {
              params.gid = parseInt(params.gid, 10);
          }
  
          return params;
      };
  
      var openPhotoSwipe = function (index, galleryElement, disableAnimation, fromURL) {
          var pswpElement = document.querySelectorAll('.pswp')[0],
              gallery,
              options,
              items;
  
          items = parseThumbnailElements(galleryElement);
  
          // define options (if needed)
          options = {
  
              // define gallery index (for URL)
              galleryUID: galleryElement.getAttribute('data-pswp-uid'),
  
              getThumbBoundsFn: function (index) {
                  // See Options -> getThumbBoundsFn section of documentation for more info
                  var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
                      pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
                      rect = thumbnail.getBoundingClientRect();
  
                  return {
                      x: rect.left,
                      y: rect.top + pageYScroll,
                      w: rect.width
                  };
              }
  
          };
  
          // PhotoSwipe opened from URL
          if (fromURL) {
              if (options.galleryPIDs) {
                  // parse real index when custom PIDs are used 
                  // http://photoswipe.com/documentation/faq.html#custom-pid-in-url
                  for (var j = 0; j < items.length; j++) {
                      if (items[j].pid == index) {
                          options.index = j;
                          break;
                      }
                  }
              } else {
                  // in URL indexes start from 1
                  options.index = parseInt(index, 10) - 1;
              }
          } else {
              options.index = parseInt(index, 10);
          }
  
          // exit if index not found
          if (isNaN(options.index)) {
              return;
          }
  
          if (disableAnimation) {
              options.showAnimationDuration = 0;
          }
  
          // Pass data to PhotoSwipe and initialize it
          gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
          gallery.init();
      };
  
      // loop through all gallery elements and bind events
      var galleryElements = document.querySelectorAll(gallerySelector);
  
      for (var i = 0, l = galleryElements.length; i < l; i++) {
          galleryElements[i].setAttribute('data-pswp-uid', i + 1);
          galleryElements[i].onclick = onThumbnailsClick;
      }
  
      // Parse URL and open gallery if it contains #&pid=3&gid=1
      var hashData = photoswipeParseHash();
      if (hashData.pid && hashData.gid) {
          openPhotoSwipe(hashData.pid, galleryElements[hashData.gid - 1], true, true);
      }
  };
  
  // execute above function
  initPhotoSwipeFromDOM('.mdb-lightbox');
  /* jSticky Plugin
   * =============
   * Author: Andrew Henderson (@AndrewHenderson)
   * Contributor: Mike Street (@mikestreety)
   * Date: 9/7/2012
   * Update: 09/20/2016
   * Website: http://github.com/andrewhenderson/jsticky/
   * Description: A jQuery plugin that keeps select DOM
   * element(s) in view while scrolling the page.
   */
  
  ;(function($) {
  
    $.fn.sticky = function(options) {
      var defaults = {
        topSpacing: 0, // No spacing by default
        zIndex: '', // No default z-index
        stopper: '.sticky-stopper', // Default stopper class, also accepts number value
        stickyClass: false // Class applied to element when it's stuck
      };
      var settings = $.extend({}, defaults, options); // Accepts custom stopper id or class
  
      // Checks if custom z-index was defined
      function checkIndex() {
        if (typeof settings.zIndex == 'number') {
          return true;
        } else {
          return false;
        }
      }
  
      var hasIndex = checkIndex(); // True or false
  
      // Checks if a stopper exists in the DOM or number defined
      function checkStopper() {
        if (0 < $(settings.stopper).length || typeof settings.stopper === 'number') {
          return true;
        } else {
          return false;
        }
      }
      var hasStopper = checkStopper(); // True or false
  
      return this.each(function() {
  
        var $this = $(this);
        var thisHeight = $this.outerHeight();
        var thisWidth = $this.outerWidth();
        var topSpacing = settings.topSpacing;
        var zIndex = settings.zIndex;
        var pushPoint = $this.offset().top - topSpacing; // Point at which the sticky element starts pushing
        var placeholder = $('<div></div>').width(thisWidth).height(thisHeight).addClass('sticky-placeholder'); // Cache a clone sticky element
        var stopper = settings.stopper;
        var $window = $(window);
  
        function stickyScroll() {
  
          var windowTop  = $window.scrollTop(); // Check window's scroll position
          var stopPoint = stopper;
          var parentWidth = $this.parent().width();
  
          placeholder.width(parentWidth)
  
          if ( hasStopper && typeof stopper === 'string' ) {
            var stopperTop = $(stopper).offset().top;
            stopPoint  = (stopperTop - thisHeight) - topSpacing;
          }
  
          if (pushPoint < windowTop) {
            // Create a placeholder for sticky element to occupy vertical real estate
            if(settings.stickyClass)
              $this.addClass(settings.stickyClass);
  
            $this.after(placeholder).css({
              position: 'fixed',
              top: topSpacing,
              width: parentWidth
            });
  
            if (hasIndex) {
              $this.css({
                zIndex: zIndex
              });
            }
  
            if (hasStopper) {
              if (stopPoint < windowTop) {
                var diff = (stopPoint - windowTop) + topSpacing;
                $this.css({
                  top: diff
                });
              }
            }
          } else {
            if(settings.stickyClass)
              $this.removeClass(settings.stickyClass);
  
            $this.css({
              position: 'static',
              top: null,
              left: null,
              width: 'auto'
            });
  
            placeholder.remove();
          }
        }
  
        if($window.innerHeight() > thisHeight) {
  
          $window.bind('scroll', stickyScroll);
          $window.bind('load', stickyScroll);
          $window.bind('resize', stickyScroll);
        }
      });
    };
  })(jQuery);
  /*!
   * perfect-scrollbar v1.4.0
   * (c) 2018 Hyunje Jun
   * @license MIT
   */
  !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.PerfectScrollbar=e()}(this,function(){"use strict";function t(t){return getComputedStyle(t)}function e(t,e){for(var i in e){var r=e[i];"number"==typeof r&&(r+="px"),t.style[i]=r}return t}function i(t){var e=document.createElement("div");return e.className=t,e}function r(t,e){if(!v)throw new Error("No element matching method supported");return v.call(t,e)}function l(t){t.remove?t.remove():t.parentNode&&t.parentNode.removeChild(t)}function n(t,e){return Array.prototype.filter.call(t.children,function(t){return r(t,e)})}function o(t,e){var i=t.element.classList,r=m.state.scrolling(e);i.contains(r)?clearTimeout(Y[e]):i.add(r)}function s(t,e){Y[e]=setTimeout(function(){return t.isAlive&&t.element.classList.remove(m.state.scrolling(e))},t.settings.scrollingThreshold)}function a(t,e){o(t,e),s(t,e)}function c(t){if("function"==typeof window.CustomEvent)return new CustomEvent(t);var e=document.createEvent("CustomEvent");return e.initCustomEvent(t,!1,!1,void 0),e}function h(t,e,i,r,l){var n=i[0],o=i[1],s=i[2],h=i[3],u=i[4],d=i[5];void 0===r&&(r=!0),void 0===l&&(l=!1);var f=t.element;t.reach[h]=null,f[s]<1&&(t.reach[h]="start"),f[s]>t[n]-t[o]-1&&(t.reach[h]="end"),e&&(f.dispatchEvent(c("ps-scroll-"+h)),e<0?f.dispatchEvent(c("ps-scroll-"+u)):e>0&&f.dispatchEvent(c("ps-scroll-"+d)),r&&a(t,h)),t.reach[h]&&(e||l)&&f.dispatchEvent(c("ps-"+h+"-reach-"+t.reach[h]))}function u(t){return parseInt(t,10)||0}function d(t){return r(t,"input,[contenteditable]")||r(t,"select,[contenteditable]")||r(t,"textarea,[contenteditable]")||r(t,"button,[contenteditable]")}function f(e){var i=t(e);return u(i.width)+u(i.paddingLeft)+u(i.paddingRight)+u(i.borderLeftWidth)+u(i.borderRightWidth)}function p(t,e){return t.settings.minScrollbarLength&&(e=Math.max(e,t.settings.minScrollbarLength)),t.settings.maxScrollbarLength&&(e=Math.min(e,t.settings.maxScrollbarLength)),e}function b(t,i){var r={width:i.railXWidth},l=Math.floor(t.scrollTop);i.isRtl?r.left=i.negativeScrollAdjustment+t.scrollLeft+i.containerWidth-i.contentWidth:r.left=t.scrollLeft,i.isScrollbarXUsingBottom?r.bottom=i.scrollbarXBottom-l:r.top=i.scrollbarXTop+l,e(i.scrollbarXRail,r);var n={top:l,height:i.railYHeight};i.isScrollbarYUsingRight?i.isRtl?n.right=i.contentWidth-(i.negativeScrollAdjustment+t.scrollLeft)-i.scrollbarYRight-i.scrollbarYOuterWidth:n.right=i.scrollbarYRight-t.scrollLeft:i.isRtl?n.left=i.negativeScrollAdjustment+t.scrollLeft+2*i.containerWidth-i.contentWidth-i.scrollbarYLeft-i.scrollbarYOuterWidth:n.left=i.scrollbarYLeft+t.scrollLeft,e(i.scrollbarYRail,n),e(i.scrollbarX,{left:i.scrollbarXLeft,width:i.scrollbarXWidth-i.railBorderXWidth}),e(i.scrollbarY,{top:i.scrollbarYTop,height:i.scrollbarYHeight-i.railBorderYWidth})}function g(t,e){function i(e){b[d]=g+Y*(e[a]-v),o(t,f),R(t),e.stopPropagation(),e.preventDefault()}function r(){s(t,f),t[p].classList.remove(m.state.clicking),t.event.unbind(t.ownerDocument,"mousemove",i)}var l=e[0],n=e[1],a=e[2],c=e[3],h=e[4],u=e[5],d=e[6],f=e[7],p=e[8],b=t.element,g=null,v=null,Y=null;t.event.bind(t[h],"mousedown",function(e){g=b[d],v=e[a],Y=(t[n]-t[l])/(t[c]-t[u]),t.event.bind(t.ownerDocument,"mousemove",i),t.event.once(t.ownerDocument,"mouseup",r),t[p].classList.add(m.state.clicking),e.stopPropagation(),e.preventDefault()})}var v="undefined"!=typeof Element&&(Element.prototype.matches||Element.prototype.webkitMatchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector),m={main:"ps",element:{thumb:function(t){return"ps__thumb-"+t},rail:function(t){return"ps__rail-"+t},consuming:"ps__child--consume"},state:{focus:"ps--focus",clicking:"ps--clicking",active:function(t){return"ps--active-"+t},scrolling:function(t){return"ps--scrolling-"+t}}},Y={x:null,y:null},X=function(t){this.element=t,this.handlers={}},w={isEmpty:{configurable:!0}};X.prototype.bind=function(t,e){void 0===this.handlers[t]&&(this.handlers[t]=[]),this.handlers[t].push(e),this.element.addEventListener(t,e,!1)},X.prototype.unbind=function(t,e){var i=this;this.handlers[t]=this.handlers[t].filter(function(r){return!(!e||r===e)||(i.element.removeEventListener(t,r,!1),!1)})},X.prototype.unbindAll=function(){var t=this;for(var e in t.handlers)t.unbind(e)},w.isEmpty.get=function(){var t=this;return Object.keys(this.handlers).every(function(e){return 0===t.handlers[e].length})},Object.defineProperties(X.prototype,w);var y=function(){this.eventElements=[]};y.prototype.eventElement=function(t){var e=this.eventElements.filter(function(e){return e.element===t})[0];return e||(e=new X(t),this.eventElements.push(e)),e},y.prototype.bind=function(t,e,i){this.eventElement(t).bind(e,i)},y.prototype.unbind=function(t,e,i){var r=this.eventElement(t);r.unbind(e,i),r.isEmpty&&this.eventElements.splice(this.eventElements.indexOf(r),1)},y.prototype.unbindAll=function(){this.eventElements.forEach(function(t){return t.unbindAll()}),this.eventElements=[]},y.prototype.once=function(t,e,i){var r=this.eventElement(t),l=function(t){r.unbind(e,l),i(t)};r.bind(e,l)};var W=function(t,e,i,r,l){void 0===r&&(r=!0),void 0===l&&(l=!1);var n;if("top"===e)n=["contentHeight","containerHeight","scrollTop","y","up","down"];else{if("left"!==e)throw new Error("A proper axis should be provided");n=["contentWidth","containerWidth","scrollLeft","x","left","right"]}h(t,i,n,r,l)},L={isWebKit:"undefined"!=typeof document&&"WebkitAppearance"in document.documentElement.style,supportsTouch:"undefined"!=typeof window&&("ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),supportsIePointer:"undefined"!=typeof navigator&&navigator.msMaxTouchPoints,isChrome:"undefined"!=typeof navigator&&/Chrome/i.test(navigator&&navigator.userAgent)},R=function(t){var e=t.element,i=Math.floor(e.scrollTop);t.containerWidth=e.clientWidth,t.containerHeight=e.clientHeight,t.contentWidth=e.scrollWidth,t.contentHeight=e.scrollHeight,e.contains(t.scrollbarXRail)||(n(e,m.element.rail("x")).forEach(function(t){return l(t)}),e.appendChild(t.scrollbarXRail)),e.contains(t.scrollbarYRail)||(n(e,m.element.rail("y")).forEach(function(t){return l(t)}),e.appendChild(t.scrollbarYRail)),!t.settings.suppressScrollX&&t.containerWidth+t.settings.scrollXMarginOffset<t.contentWidth?(t.scrollbarXActive=!0,t.railXWidth=t.containerWidth-t.railXMarginWidth,t.railXRatio=t.containerWidth/t.railXWidth,t.scrollbarXWidth=p(t,u(t.railXWidth*t.containerWidth/t.contentWidth)),t.scrollbarXLeft=u((t.negativeScrollAdjustment+e.scrollLeft)*(t.railXWidth-t.scrollbarXWidth)/(t.contentWidth-t.containerWidth))):t.scrollbarXActive=!1,!t.settings.suppressScrollY&&t.containerHeight+t.settings.scrollYMarginOffset<t.contentHeight?(t.scrollbarYActive=!0,t.railYHeight=t.containerHeight-t.railYMarginHeight,t.railYRatio=t.containerHeight/t.railYHeight,t.scrollbarYHeight=p(t,u(t.railYHeight*t.containerHeight/t.contentHeight)),t.scrollbarYTop=u(i*(t.railYHeight-t.scrollbarYHeight)/(t.contentHeight-t.containerHeight))):t.scrollbarYActive=!1,t.scrollbarXLeft>=t.railXWidth-t.scrollbarXWidth&&(t.scrollbarXLeft=t.railXWidth-t.scrollbarXWidth),t.scrollbarYTop>=t.railYHeight-t.scrollbarYHeight&&(t.scrollbarYTop=t.railYHeight-t.scrollbarYHeight),b(e,t),t.scrollbarXActive?e.classList.add(m.state.active("x")):(e.classList.remove(m.state.active("x")),t.scrollbarXWidth=0,t.scrollbarXLeft=0,e.scrollLeft=0),t.scrollbarYActive?e.classList.add(m.state.active("y")):(e.classList.remove(m.state.active("y")),t.scrollbarYHeight=0,t.scrollbarYTop=0,e.scrollTop=0)},T={"click-rail":function(t){t.event.bind(t.scrollbarY,"mousedown",function(t){return t.stopPropagation()}),t.event.bind(t.scrollbarYRail,"mousedown",function(e){var i=e.pageY-window.pageYOffset-t.scrollbarYRail.getBoundingClientRect().top>t.scrollbarYTop?1:-1;t.element.scrollTop+=i*t.containerHeight,R(t),e.stopPropagation()}),t.event.bind(t.scrollbarX,"mousedown",function(t){return t.stopPropagation()}),t.event.bind(t.scrollbarXRail,"mousedown",function(e){var i=e.pageX-window.pageXOffset-t.scrollbarXRail.getBoundingClientRect().left>t.scrollbarXLeft?1:-1;t.element.scrollLeft+=i*t.containerWidth,R(t),e.stopPropagation()})},"drag-thumb":function(t){g(t,["containerWidth","contentWidth","pageX","railXWidth","scrollbarX","scrollbarXWidth","scrollLeft","x","scrollbarXRail"]),g(t,["containerHeight","contentHeight","pageY","railYHeight","scrollbarY","scrollbarYHeight","scrollTop","y","scrollbarYRail"])},keyboard:function(t){function e(e,r){var l=Math.floor(i.scrollTop);if(0===e){if(!t.scrollbarYActive)return!1;if(0===l&&r>0||l>=t.contentHeight-t.containerHeight&&r<0)return!t.settings.wheelPropagation}var n=i.scrollLeft;if(0===r){if(!t.scrollbarXActive)return!1;if(0===n&&e<0||n>=t.contentWidth-t.containerWidth&&e>0)return!t.settings.wheelPropagation}return!0}var i=t.element,l=function(){return r(i,":hover")},n=function(){return r(t.scrollbarX,":focus")||r(t.scrollbarY,":focus")};t.event.bind(t.ownerDocument,"keydown",function(r){if(!(r.isDefaultPrevented&&r.isDefaultPrevented()||r.defaultPrevented)&&(l()||n())){var o=document.activeElement?document.activeElement:t.ownerDocument.activeElement;if(o){if("IFRAME"===o.tagName)o=o.contentDocument.activeElement;else for(;o.shadowRoot;)o=o.shadowRoot.activeElement;if(d(o))return}var s=0,a=0;switch(r.which){case 37:s=r.metaKey?-t.contentWidth:r.altKey?-t.containerWidth:-30;break;case 38:a=r.metaKey?t.contentHeight:r.altKey?t.containerHeight:30;break;case 39:s=r.metaKey?t.contentWidth:r.altKey?t.containerWidth:30;break;case 40:a=r.metaKey?-t.contentHeight:r.altKey?-t.containerHeight:-30;break;case 32:a=r.shiftKey?t.containerHeight:-t.containerHeight;break;case 33:a=t.containerHeight;break;case 34:a=-t.containerHeight;break;case 36:a=t.contentHeight;break;case 35:a=-t.contentHeight;break;default:return}t.settings.suppressScrollX&&0!==s||t.settings.suppressScrollY&&0!==a||(i.scrollTop-=a,i.scrollLeft+=s,R(t),e(s,a)&&r.preventDefault())}})},wheel:function(e){function i(t,i){var r=Math.floor(o.scrollTop),l=0===o.scrollTop,n=r+o.offsetHeight===o.scrollHeight,s=0===o.scrollLeft,a=o.scrollLeft+o.offsetWidth===o.scrollWidth;return!(Math.abs(i)>Math.abs(t)?l||n:s||a)||!e.settings.wheelPropagation}function r(t){var e=t.deltaX,i=-1*t.deltaY;return void 0!==e&&void 0!==i||(e=-1*t.wheelDeltaX/6,i=t.wheelDeltaY/6),t.deltaMode&&1===t.deltaMode&&(e*=10,i*=10),e!==e&&i!==i&&(e=0,i=t.wheelDelta),t.shiftKey?[-i,-e]:[e,i]}function l(e,i,r){if(!L.isWebKit&&o.querySelector("select:focus"))return!0;if(!o.contains(e))return!1;for(var l=e;l&&l!==o;){if(l.classList.contains(m.element.consuming))return!0;var n=t(l);if([n.overflow,n.overflowX,n.overflowY].join("").match(/(scroll|auto)/)){var s=l.scrollHeight-l.clientHeight;if(s>0&&!(0===l.scrollTop&&r>0||l.scrollTop===s&&r<0))return!0;var a=l.scrollWidth-l.clientWidth;if(a>0&&!(0===l.scrollLeft&&i<0||l.scrollLeft===a&&i>0))return!0}l=l.parentNode}return!1}function n(t){var n=r(t),s=n[0],a=n[1];if(!l(t.target,s,a)){var c=!1;e.settings.useBothWheelAxes?e.scrollbarYActive&&!e.scrollbarXActive?(a?o.scrollTop-=a*e.settings.wheelSpeed:o.scrollTop+=s*e.settings.wheelSpeed,c=!0):e.scrollbarXActive&&!e.scrollbarYActive&&(s?o.scrollLeft+=s*e.settings.wheelSpeed:o.scrollLeft-=a*e.settings.wheelSpeed,c=!0):(o.scrollTop-=a*e.settings.wheelSpeed,o.scrollLeft+=s*e.settings.wheelSpeed),R(e),(c=c||i(s,a))&&!t.ctrlKey&&(t.stopPropagation(),t.preventDefault())}}var o=e.element;void 0!==window.onwheel?e.event.bind(o,"wheel",n):void 0!==window.onmousewheel&&e.event.bind(o,"mousewheel",n)},touch:function(e){function i(t,i){var r=Math.floor(h.scrollTop),l=h.scrollLeft,n=Math.abs(t),o=Math.abs(i);if(o>n){if(i<0&&r===e.contentHeight-e.containerHeight||i>0&&0===r)return 0===window.scrollY&&i>0&&L.isChrome}else if(n>o&&(t<0&&l===e.contentWidth-e.containerWidth||t>0&&0===l))return!0;return!0}function r(t,i){h.scrollTop-=i,h.scrollLeft-=t,R(e)}function l(t){return t.targetTouches?t.targetTouches[0]:t}function n(t){return!(t.pointerType&&"pen"===t.pointerType&&0===t.buttons||(!t.targetTouches||1!==t.targetTouches.length)&&(!t.pointerType||"mouse"===t.pointerType||t.pointerType===t.MSPOINTER_TYPE_MOUSE))}function o(t){if(n(t)){var e=l(t);u.pageX=e.pageX,u.pageY=e.pageY,d=(new Date).getTime(),null!==p&&clearInterval(p)}}function s(e,i,r){if(!h.contains(e))return!1;for(var l=e;l&&l!==h;){if(l.classList.contains(m.element.consuming))return!0;var n=t(l);if([n.overflow,n.overflowX,n.overflowY].join("").match(/(scroll|auto)/)){var o=l.scrollHeight-l.clientHeight;if(o>0&&!(0===l.scrollTop&&r>0||l.scrollTop===o&&r<0))return!0;var s=l.scrollLeft-l.clientWidth;if(s>0&&!(0===l.scrollLeft&&i<0||l.scrollLeft===s&&i>0))return!0}l=l.parentNode}return!1}function a(t){if(n(t)){var e=l(t),o={pageX:e.pageX,pageY:e.pageY},a=o.pageX-u.pageX,c=o.pageY-u.pageY;if(s(t.target,a,c))return;r(a,c),u=o;var h=(new Date).getTime(),p=h-d;p>0&&(f.x=a/p,f.y=c/p,d=h),i(a,c)&&t.preventDefault()}}function c(){e.settings.swipeEasing&&(clearInterval(p),p=setInterval(function(){e.isInitialized?clearInterval(p):f.x||f.y?Math.abs(f.x)<.01&&Math.abs(f.y)<.01?clearInterval(p):(r(30*f.x,30*f.y),f.x*=.8,f.y*=.8):clearInterval(p)},10))}if(L.supportsTouch||L.supportsIePointer){var h=e.element,u={},d=0,f={},p=null;L.supportsTouch?(e.event.bind(h,"touchstart",o),e.event.bind(h,"touchmove",a),e.event.bind(h,"touchend",c)):L.supportsIePointer&&(window.PointerEvent?(e.event.bind(h,"pointerdown",o),e.event.bind(h,"pointermove",a),e.event.bind(h,"pointerup",c)):window.MSPointerEvent&&(e.event.bind(h,"MSPointerDown",o),e.event.bind(h,"MSPointerMove",a),e.event.bind(h,"MSPointerUp",c)))}}},H=function(r,l){var n=this;if(void 0===l&&(l={}),"string"==typeof r&&(r=document.querySelector(r)),!r||!r.nodeName)throw new Error("no element is specified to initialize PerfectScrollbar");this.element=r,r.classList.add(m.main),this.settings={handlers:["click-rail","drag-thumb","keyboard","wheel","touch"],maxScrollbarLength:null,minScrollbarLength:null,scrollingThreshold:1e3,scrollXMarginOffset:0,scrollYMarginOffset:0,suppressScrollX:!1,suppressScrollY:!1,swipeEasing:!0,useBothWheelAxes:!1,wheelPropagation:!0,wheelSpeed:1};for(var o in l)n.settings[o]=l[o];this.containerWidth=null,this.containerHeight=null,this.contentWidth=null,this.contentHeight=null;var s=function(){return r.classList.add(m.state.focus)},a=function(){return r.classList.remove(m.state.focus)};this.isRtl="rtl"===t(r).direction,this.isNegativeScroll=function(){var t=r.scrollLeft,e=null;return r.scrollLeft=-1,e=r.scrollLeft<0,r.scrollLeft=t,e}(),this.negativeScrollAdjustment=this.isNegativeScroll?r.scrollWidth-r.clientWidth:0,this.event=new y,this.ownerDocument=r.ownerDocument||document,this.scrollbarXRail=i(m.element.rail("x")),r.appendChild(this.scrollbarXRail),this.scrollbarX=i(m.element.thumb("x")),this.scrollbarXRail.appendChild(this.scrollbarX),this.scrollbarX.setAttribute("tabindex",0),this.event.bind(this.scrollbarX,"focus",s),this.event.bind(this.scrollbarX,"blur",a),this.scrollbarXActive=null,this.scrollbarXWidth=null,this.scrollbarXLeft=null;var c=t(this.scrollbarXRail);this.scrollbarXBottom=parseInt(c.bottom,10),isNaN(this.scrollbarXBottom)?(this.isScrollbarXUsingBottom=!1,this.scrollbarXTop=u(c.top)):this.isScrollbarXUsingBottom=!0,this.railBorderXWidth=u(c.borderLeftWidth)+u(c.borderRightWidth),e(this.scrollbarXRail,{display:"block"}),this.railXMarginWidth=u(c.marginLeft)+u(c.marginRight),e(this.scrollbarXRail,{display:""}),this.railXWidth=null,this.railXRatio=null,this.scrollbarYRail=i(m.element.rail("y")),r.appendChild(this.scrollbarYRail),this.scrollbarY=i(m.element.thumb("y")),this.scrollbarYRail.appendChild(this.scrollbarY),this.scrollbarY.setAttribute("tabindex",0),this.event.bind(this.scrollbarY,"focus",s),this.event.bind(this.scrollbarY,"blur",a),this.scrollbarYActive=null,this.scrollbarYHeight=null,this.scrollbarYTop=null;var h=t(this.scrollbarYRail);this.scrollbarYRight=parseInt(h.right,10),isNaN(this.scrollbarYRight)?(this.isScrollbarYUsingRight=!1,this.scrollbarYLeft=u(h.left)):this.isScrollbarYUsingRight=!0,this.scrollbarYOuterWidth=this.isRtl?f(this.scrollbarY):null,this.railBorderYWidth=u(h.borderTopWidth)+u(h.borderBottomWidth),e(this.scrollbarYRail,{display:"block"}),this.railYMarginHeight=u(h.marginTop)+u(h.marginBottom),e(this.scrollbarYRail,{display:""}),this.railYHeight=null,this.railYRatio=null,this.reach={x:r.scrollLeft<=0?"start":r.scrollLeft>=this.contentWidth-this.containerWidth?"end":null,y:r.scrollTop<=0?"start":r.scrollTop>=this.contentHeight-this.containerHeight?"end":null},this.isAlive=!0,this.settings.handlers.forEach(function(t){return T[t](n)}),this.lastScrollTop=Math.floor(r.scrollTop),this.lastScrollLeft=r.scrollLeft,this.event.bind(this.element,"scroll",function(t){return n.onScroll(t)}),R(this)};return H.prototype.update=function(){this.isAlive&&(this.negativeScrollAdjustment=this.isNegativeScroll?this.element.scrollWidth-this.element.clientWidth:0,e(this.scrollbarXRail,{display:"block"}),e(this.scrollbarYRail,{display:"block"}),this.railXMarginWidth=u(t(this.scrollbarXRail).marginLeft)+u(t(this.scrollbarXRail).marginRight),this.railYMarginHeight=u(t(this.scrollbarYRail).marginTop)+u(t(this.scrollbarYRail).marginBottom),e(this.scrollbarXRail,{display:"none"}),e(this.scrollbarYRail,{display:"none"}),R(this),W(this,"top",0,!1,!0),W(this,"left",0,!1,!0),e(this.scrollbarXRail,{display:""}),e(this.scrollbarYRail,{display:""}))},H.prototype.onScroll=function(t){this.isAlive&&(R(this),W(this,"top",this.element.scrollTop-this.lastScrollTop),W(this,"left",this.element.scrollLeft-this.lastScrollLeft),this.lastScrollTop=Math.floor(this.element.scrollTop),this.lastScrollLeft=this.element.scrollLeft)},H.prototype.destroy=function(){this.isAlive&&(this.event.unbindAll(),l(this.scrollbarX),l(this.scrollbarY),l(this.scrollbarXRail),l(this.scrollbarYRail),this.removePsClasses(),this.element=null,this.scrollbarX=null,this.scrollbarY=null,this.scrollbarXRail=null,this.scrollbarYRail=null,this.isAlive=!1)},H.prototype.removePsClasses=function(){this.element.className=this.element.className.split(" ").filter(function(t){return!t.match(/^ps([-_].+|)$/)}).join(" ")},H});
  "use strict";
  'use scrict';
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
  
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  
  (function ($) {
    $(document).ready(function () {
      $(document).on('click', '.chip .close', function () {
        var $this = $(this);
  
        if ($this.closest('.chips').data('initialized')) {
          return;
        }
  
        $this.closest('.chip').remove();
      });
    });
  
    var MaterialChip =
    /*#__PURE__*/
    function () {
      function MaterialChip(chips, options) {
        _classCallCheck(this, MaterialChip);
  
        this.chips = chips;
        this.$document = $(document);
        this.options = options;
        this.eventsHandled = false;
        this.ulWrapper = $('<ul class="chip-ul z-depth-1"></ul>');
        this.defaultOptions = {
          data: [],
          dataChip: [],
          placeholder: '',
          secondaryPlaceholder: ''
        };
        this.selectors = {
          chips: '.chips',
          chip: '.chip',
          input: 'input',
          delete: '.fas',
          selectedChip: '.selected'
        };
        this.keyCodes = {
          enter: 13,
          backspace: 8,
          delete: 46,
          arrowLeft: 37,
          arrowRight: 39,
          comma: 188
        };
        this.init();
      }
  
      _createClass(MaterialChip, [{
        key: "init",
        value: function init() {
          var _this = this;
  
          this.optionsDataStatement();
          this.assignOptions();
          this.chips.each(function (index, element) {
            var $this = $(element);
  
            if ($this.data('initialized')) {
              return;
            }
  
            var options = $this.data('options');
  
            if (!options.data || !Array.isArray(options.data)) {
              options.data = [];
            }
  
            $this.data('chips', options.data);
            $this.data('index', index);
            $this.data('initialized', true);
  
            if (!$this.hasClass(_this.selectors.chips)) {
              $this.addClass('chips');
            }
  
            _this.renderChips($this);
          });
  
          if (!this.eventsHandled) {
            this.handleEvents();
            this.eventsHandled = true;
          }
  
          return this;
        }
      }, {
        key: "optionsDataStatement",
        value: function optionsDataStatement() {
          if (this.options === 'data') {
            return this.chips.data('chips');
          }
  
          if (this.options === 'options') {
            return this.chips.data('options');
          }
  
          return true;
        }
      }, {
        key: "assignOptions",
        value: function assignOptions() {
          this.chips.data('options', $.extend({}, this.defaultOptions, this.options));
        }
      }, {
        key: "handleEvents",
        value: function handleEvents() {
          this.handleSelecorChips();
          this.handleBlurInput();
          this.handleSelectorChip();
          this.handleDocumentKeyDown();
          this.handleDocumentFocusIn();
          this.handleDocumentFocusOut();
          this.handleDocumentKeyDownChipsInput();
          this.handleDocumentClickChipsDelete();
          this.inputKeyDown();
          this.renderedLiClick();
          this.dynamicInputChanges();
        }
      }, {
        key: "handleSelecorChips",
        value: function handleSelecorChips() {
          var _this2 = this;
  
          this.$document.on('click', this.selectors.chips, function (e) {
            return $(e.target).find(_this2.selectors.input).focus();
          });
        }
      }, {
        key: "handleBlurInput",
        value: function handleBlurInput() {
          var _this3 = this;
  
          this.$document.on('blur', this.selectors.chips, function () {
            return setTimeout(function () {
              return _this3.ulWrapper.hide();
            }, 100);
          });
        }
      }, {
        key: "handleSelectorChip",
        value: function handleSelectorChip() {
          this.chips.on('click', '.chip', function (e) {
            return $(e.target).removeClass('selected').addClass('selected');
          });
        }
      }, {
        key: "handleDocumentKeyDown",
        value: function handleDocumentKeyDown() {
          var _this4 = this;
  
          this.$document.on('keydown', function (e) {
            if ($(e.target).is('input, textarea')) {
              return;
            }
  
            var $selectedChip = _this4.$document.find(_this4.selectors.chip + _this4.selectors.selectedChip);
  
            var $chipsWrapper = $selectedChip.closest(_this4.selectors.chips);
            var siblingsLength = $selectedChip.siblings(_this4.selectors.chip).length;
  
            if (!$selectedChip.length) {
              return;
            }
  
            var backspacePressed = e.which === _this4.keyCodes.backspace;
            var deletePressed = e.which === _this4.keyCodes.delete;
            var leftArrowPressed = e.which === _this4.keyCodes.arrowLeft;
            var rightArrowPressed = e.which === _this4.keyCodes.arrowRight;
  
            if (backspacePressed || deletePressed) {
              e.preventDefault();
  
              _this4.deleteSelectedChip($chipsWrapper, $selectedChip, siblingsLength);
            } else if (leftArrowPressed) {
              _this4.selectLeftChip($chipsWrapper, $selectedChip);
            } else if (rightArrowPressed) {
              _this4.selectRightChip($chipsWrapper, $selectedChip, siblingsLength);
            }
          });
        }
      }, {
        key: "handleDocumentFocusIn",
        value: function handleDocumentFocusIn() {
          var _this5 = this;
  
          var $chipsInput;
          var $chips = this.chips;
  
          if ($chips.hasClass('chips-autocomplete')) {
            $chipsInput = $chips.children().children('input');
          } else {
            $chipsInput = $chips.children('input');
          }
  
          $chipsInput.on('click', function (e) {
            $(e.target).closest(_this5.selectors.chips).addClass('focus');
            $(_this5.selectors.chip).removeClass('selected');
          });
        }
      }, {
        key: "handleDocumentFocusOut",
        value: function handleDocumentFocusOut() {
          var _this6 = this;
  
          this.$document.on('focusout', "".concat(this.selectors.chips, " ").concat(this.selectors.input), function (e) {
            return $(e.target).closest(_this6.selectors.chips).removeClass('focus');
          });
        }
      }, {
        key: "handleDocumentKeyDownChipsInput",
        value: function handleDocumentKeyDownChipsInput() {
          var _this7 = this;
  
          this.$document.on('keydown', "".concat(this.selectors.chips, " ").concat(this.selectors.input), function (e) {
            var $target = $(e.target);
            var $chipsWrapper = $target.closest(_this7.selectors.chips);
            var chipsIndex = $chipsWrapper.data('index');
            var chipsLength = $chipsWrapper.children(_this7.selectors.chip).length;
            var enterPressed = e.which === _this7.keyCodes.enter;
            var commaPressed = e.which === _this7.keyCodes.comma;
  
            if (enterPressed || commaPressed) {
              e.preventDefault();
  
              _this7.addChip(chipsIndex, {
                tag: $target.val()
              }, $chipsWrapper);
  
              $target.val('');
              return;
            }
  
            var leftArrowOrDeletePressed = e.keyCode === _this7.keyCodes.arrowLeft || e.keyCode === _this7.keyCodes.delete;
            var isValueEmpty = $target.val() === '';
  
            if (leftArrowOrDeletePressed && isValueEmpty && chipsLength) {
              _this7.selectChip(chipsIndex, chipsLength - 1, $chipsWrapper);
  
              $target.blur();
            }
          });
        }
      }, {
        key: "handleDocumentClickChipsDelete",
        value: function handleDocumentClickChipsDelete() {
          var _this8 = this;
  
          this.chips.on('click', '.chip .fas', function (e) {
            var $target = $(e.target);
            var $chip = $target.parent($(_this8.chips));
            var $chipsWrapper;
  
            if ($chip.parents().eq(1).hasClass('chips-autocomplete')) {
              $chipsWrapper = $chip.parents().eq(1);
            } else if (!$chip.parent().hasClass('chips-autocomplete') && !$chip.parents().eq(1).hasClass('chips-autocomplete')) {
              $chipsWrapper = $chip.parents().eq(0);
            } else if ($chip.parent().hasClass('chips-initial') && $chip.parent().hasClass('chips-autocomplete')) {
              $chipsWrapper = $chip.parents().eq(0);
            }
  
            _this8.deleteChip($chipsWrapper.data('index'), $chip.index(), $chipsWrapper);
  
            $chipsWrapper.find('input').focus();
          });
        }
      }, {
        key: "inputKeyDown",
        value: function inputKeyDown() {
          var _this9 = this;
  
          var $ulWrapper = this.ulWrapper;
          var dataChip = this.options.dataChip;
          var $thisChups = this.chips;
          var $input = $thisChups.children('.chip-position-wrapper').children('input');
          $input.on('keyup', function (e) {
            var $inputValue = $input.val();
            $ulWrapper.empty();
  
            if ($inputValue.length) {
              for (var item in dataChip) {
                if (dataChip[item].toLowerCase().includes($inputValue.toLowerCase())) {
                  $thisChups.children('.chip-position-wrapper').append($ulWrapper.append($("<li>".concat(dataChip[item], "</li>"))));
                }
              }
            }
  
            if (e.which === _this9.keyCodes.enter) {
              $ulWrapper.empty();
              $thisChups.children(':first').trigger('click');
              $ulWrapper.remove();
            } // eslint-disable-next-line no-unused-expressions
  
  
            $inputValue.length === 0 ? $ulWrapper.hide() : $ulWrapper.show();
          });
        }
      }, {
        key: "dynamicInputChanges",
        value: function dynamicInputChanges() {
          var dataChip = this.options.dataChip;
  
          if (dataChip !== undefined) {
            this.chips.children('.chip-position-wrapper').children('input').on('change', function (e) {
              var $targetVal = $(e.target).val();
  
              if (!dataChip.includes($targetVal)) {
                dataChip.push($targetVal);
                dataChip.sort();
              }
            });
          }
        }
      }, {
        key: "renderedLiClick",
        value: function renderedLiClick() {
          var _this10 = this;
  
          this.chips.on('click', 'li', function (e) {
            e.preventDefault();
            var $target = $(e.target);
            var $chipsWrapper = $target.closest($(_this10.selectors.chips));
            var chipsIndex = $chipsWrapper.data('index');
  
            _this10.addChip(chipsIndex, {
              tag: $target.text()
            }, $chipsWrapper);
  
            _this10.chips.children('.chip-position-wrapper').children('input').val('');
  
            _this10.ulWrapper.remove();
          });
        }
      }, {
        key: "deleteSelectedChip",
        value: function deleteSelectedChip($chipsWrapper, $selectedChip, siblingsLength) {
          var chipsIndex = $chipsWrapper.data('index');
          var chipIndex = $selectedChip.index();
          this.deleteChip(chipsIndex, chipIndex, $chipsWrapper);
          var selectIndex = null;
  
          if (chipIndex < siblingsLength - 1) {
            selectIndex = chipIndex;
          } else if (chipIndex === siblingsLength || chipIndex === siblingsLength - 1) {
            selectIndex = siblingsLength - 1;
          }
  
          if (selectIndex < 0) {
            selectIndex = null;
          }
  
          if (selectIndex !== null) {
            this.selectChip(chipsIndex, selectIndex, $chipsWrapper);
          }
  
          if (!siblingsLength) {
            $chipsWrapper.find('input').focus();
          }
        }
      }, {
        key: "selectLeftChip",
        value: function selectLeftChip($chipsWrapper, $selectedChip) {
          var chipIndex = $selectedChip.index() - 1;
  
          if (chipIndex < 0) {
            return;
          }
  
          $(this.selectors.chip).removeClass('selected');
          this.selectChip($chipsWrapper.data('index'), chipIndex, $chipsWrapper);
        }
      }, {
        key: "selectRightChip",
        value: function selectRightChip($chipsWrapper, $selectedChip, siblingsLength) {
          var chipIndex = $selectedChip.index() + 1;
          $(this.selectors.chip).removeClass('selected');
  
          if (chipIndex > siblingsLength) {
            $chipsWrapper.find('input').focus();
            return;
          }
  
          this.selectChip($chipsWrapper.data('index'), chipIndex, $chipsWrapper);
        }
      }, {
        key: "renderChips",
        value: function renderChips($chipsWrapper) {
          var _this11 = this;
  
          var html = '';
          $chipsWrapper.data('chips').forEach(function (elem) {
            html += _this11.getSingleChipHtml(elem);
          });
  
          if ($chipsWrapper.hasClass('chips-autocomplete')) {
            html += '<span class="chip-position-wrapper position-relative"><input class="input" placeholder=""></span>';
          } else {
            html += '<input class="input" placeholder="">';
          }
  
          $chipsWrapper.html(html);
          this.setPlaceholder($chipsWrapper);
        }
      }, {
        key: "getSingleChipHtml",
        value: function getSingleChipHtml(elem) {
          if (!elem.tag) {
            return '';
          }
  
          var html = "<div class=\"chip\">".concat(elem.tag);
  
          if (elem.image) {
            html += " <img src=\"".concat(elem.image, "\"> ");
          }
  
          html += '<i class="close fas fa-times"></i>';
          html += '</div>';
          return html;
        }
      }, {
        key: "setPlaceholder",
        value: function setPlaceholder($chips) {
          var options = $chips.data('options');
  
          if ($chips.data('chips').length && options.placeholder) {
            $chips.find('input').prop('placeholder', options.placeholder);
          } else if (!$chips.data('chips').length && options.secondaryPlaceholder) {
            $chips.find('input').prop('placeholder', options.secondaryPlaceholder);
          }
        }
      }, {
        key: "isValid",
        value: function isValid($chipsWrapper, elem) {
          var chips = $chipsWrapper.data('chips');
  
          for (var i = 0; i < chips.length; i++) {
            if (chips[i].tag === elem.tag) {
              return false;
            }
          }
  
          return elem.tag !== '';
        }
      }, {
        key: "addChip",
        value: function addChip(chipsIndex, elem, $chipsWrapper) {
          if (!this.isValid($chipsWrapper, elem)) {
            return;
          }
  
          var $chipHtml = $(this.getSingleChipHtml(elem));
          $chipsWrapper.data('chips').push(elem);
  
          if ($chipsWrapper.hasClass('chips-autocomplete') && $chipsWrapper.hasClass('chips-initial') && $chipsWrapper.find('.chip').length > 0) {
            $chipHtml.insertAfter($chipsWrapper.find('.chip').last());
          } else {
            $chipHtml.insertBefore($chipsWrapper.find('input'));
          }
  
          $chipsWrapper.trigger('chip.add', elem);
          this.setPlaceholder($chipsWrapper);
        }
      }, {
        key: "deleteChip",
        value: function deleteChip(chipsIndex, chipIndex, $chipsWrapper) {
          var chip = $chipsWrapper.data('chips')[chipIndex];
          $chipsWrapper.find('.chip').eq(chipIndex).remove();
          $chipsWrapper.data('chips').splice(chipIndex, 1);
          $chipsWrapper.trigger('chip.delete', chip);
          this.setPlaceholder($chipsWrapper);
        }
      }, {
        key: "selectChip",
        value: function selectChip(chipsIndex, chipIndex, $chipsWrapper) {
          var $chip = $chipsWrapper.find('.chip').eq(chipIndex);
  
          if ($chip && $chip.hasClass('selected') === false) {
            $chip.addClass('selected');
            $chipsWrapper.trigger('chip.select', $chipsWrapper.data('chips')[chipIndex]);
          }
        }
      }, {
        key: "getChipsElement",
        value: function getChipsElement(index, $chipsWrapper) {
          return $chipsWrapper.eq(index);
        }
      }]);
  
      return MaterialChip;
    }();
  
    $.fn.materialChip = function (options) {
      return this.each(function () {
        new MaterialChip($(this), options);
      });
    };
  })(jQuery);
  /*!
   * Name    : Just Another Parallax [Jarallax]
   * Version : 1.10.4
   * Author  : nK <https://nkdev.info>
   * GitHub  : https://github.com/nk-o/jarallax
   */
  /******/ (function(modules) { // webpackBootstrap
  /******/ 	// The module cache
  /******/ 	var installedModules = {};
  /******/
  /******/ 	// The require function
  /******/ 	function __webpack_require__(moduleId) {
  /******/
  /******/ 		// Check if module is in cache
  /******/ 		if(installedModules[moduleId]) {
  /******/ 			return installedModules[moduleId].exports;
  /******/ 		}
  /******/ 		// Create a new module (and put it into the cache)
  /******/ 		var module = installedModules[moduleId] = {
  /******/ 			i: moduleId,
  /******/ 			l: false,
  /******/ 			exports: {}
  /******/ 		};
  /******/
  /******/ 		// Execute the module function
  /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  /******/
  /******/ 		// Flag the module as loaded
  /******/ 		module.l = true;
  /******/
  /******/ 		// Return the exports of the module
  /******/ 		return module.exports;
  /******/ 	}
  /******/
  /******/
  /******/ 	// expose the modules object (__webpack_modules__)
  /******/ 	__webpack_require__.m = modules;
  /******/
  /******/ 	// expose the module cache
  /******/ 	__webpack_require__.c = installedModules;
  /******/
  /******/ 	// define getter function for harmony exports
  /******/ 	__webpack_require__.d = function(exports, name, getter) {
  /******/ 		if(!__webpack_require__.o(exports, name)) {
  /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
  /******/ 		}
  /******/ 	};
  /******/
  /******/ 	// define __esModule on exports
  /******/ 	__webpack_require__.r = function(exports) {
  /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  /******/ 		}
  /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
  /******/ 	};
  /******/
  /******/ 	// create a fake namespace object
  /******/ 	// mode & 1: value is a module id, require it
  /******/ 	// mode & 2: merge all properties of value into the ns
  /******/ 	// mode & 4: return value when already ns object
  /******/ 	// mode & 8|1: behave like require
  /******/ 	__webpack_require__.t = function(value, mode) {
  /******/ 		if(mode & 1) value = __webpack_require__(value);
  /******/ 		if(mode & 8) return value;
  /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  /******/ 		var ns = Object.create(null);
  /******/ 		__webpack_require__.r(ns);
  /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  /******/ 		return ns;
  /******/ 	};
  /******/
  /******/ 	// getDefaultExport function for compatibility with non-harmony modules
  /******/ 	__webpack_require__.n = function(module) {
  /******/ 		var getter = module && module.__esModule ?
  /******/ 			function getDefault() { return module['default']; } :
  /******/ 			function getModuleExports() { return module; };
  /******/ 		__webpack_require__.d(getter, 'a', getter);
  /******/ 		return getter;
  /******/ 	};
  /******/
  /******/ 	// Object.prototype.hasOwnProperty.call
  /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  /******/
  /******/ 	// __webpack_public_path__
  /******/ 	__webpack_require__.p = "";
  /******/
  /******/
  /******/ 	// Load entry module and return exports
  /******/ 	return __webpack_require__(__webpack_require__.s = 11);
  /******/ })
  /************************************************************************/
  /******/ ([
  /* 0 */,
  /* 1 */,
  /* 2 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  module.exports = function (callback) {
  
  	if (document.readyState === 'complete' || document.readyState === 'interactive') {
  		// Already ready or interactive, execute callback
  		callback.call();
  	} else if (document.attachEvent) {
  		// Old browsers
  		document.attachEvent('onreadystatechange', function () {
  			if (document.readyState === 'interactive') callback.call();
  		});
  	} else if (document.addEventListener) {
  		// Modern browsers
  		document.addEventListener('DOMContentLoaded', callback);
  	}
  };
  
  /***/ }),
  /* 3 */,
  /* 4 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  /* WEBPACK VAR INJECTION */(function(global) {
  
  var win;
  
  if (typeof window !== "undefined") {
      win = window;
  } else if (typeof global !== "undefined") {
      win = global;
  } else if (typeof self !== "undefined") {
      win = self;
  } else {
      win = {};
  }
  
  module.exports = win;
  /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)))
  
  /***/ }),
  /* 5 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var g;
  
  // This works in non-strict mode
  g = function () {
  	return this;
  }();
  
  try {
  	// This works if eval is allowed (see CSP)
  	g = g || Function("return this")() || (1, eval)("this");
  } catch (e) {
  	// This works if the window reference is available
  	if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") g = window;
  }
  
  // g can still be undefined, but nothing to do about it...
  // We return undefined, instead of nothing here, so it's
  // easier to handle this case. if(!global) { ...}
  
  module.exports = g;
  
  /***/ }),
  /* 6 */,
  /* 7 */,
  /* 8 */,
  /* 9 */,
  /* 10 */,
  /* 11 */
  /***/ (function(module, exports, __webpack_require__) {
  
  module.exports = __webpack_require__(12);
  
  
  /***/ }),
  /* 12 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _liteReady = __webpack_require__(2);
  
  var _liteReady2 = _interopRequireDefault(_liteReady);
  
  var _global = __webpack_require__(4);
  
  var _jarallax = __webpack_require__(13);
  
  var _jarallax2 = _interopRequireDefault(_jarallax);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  // no conflict
  var oldPlugin = _global.window.jarallax;
  _global.window.jarallax = _jarallax2.default;
  _global.window.jarallax.noConflict = function () {
      _global.window.jarallax = oldPlugin;
      return this;
  };
  
  // jQuery support
  if (typeof _global.jQuery !== 'undefined') {
      var jQueryPlugin = function jQueryPlugin() {
          var args = arguments || [];
          Array.prototype.unshift.call(args, this);
          var res = _jarallax2.default.apply(_global.window, args);
          return (typeof res === 'undefined' ? 'undefined' : _typeof(res)) !== 'object' ? res : this;
      };
      jQueryPlugin.constructor = _jarallax2.default.constructor;
  
      // no conflict
      var oldJqPlugin = _global.jQuery.fn.jarallax;
      _global.jQuery.fn.jarallax = jQueryPlugin;
      _global.jQuery.fn.jarallax.noConflict = function () {
          _global.jQuery.fn.jarallax = oldJqPlugin;
          return this;
      };
  }
  
  // data-jarallax initialization
  (0, _liteReady2.default)(function () {
      (0, _jarallax2.default)(document.querySelectorAll('[data-jarallax]'));
  });
  
  /***/ }),
  /* 13 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  /* WEBPACK VAR INJECTION */(function(global) {
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  
  var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  
  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; }; }();
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _liteReady = __webpack_require__(2);
  
  var _liteReady2 = _interopRequireDefault(_liteReady);
  
  var _rafl = __webpack_require__(14);
  
  var _rafl2 = _interopRequireDefault(_rafl);
  
  var _global = __webpack_require__(4);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  var isIE = navigator.userAgent.indexOf('MSIE ') > -1 || navigator.userAgent.indexOf('Trident/') > -1 || navigator.userAgent.indexOf('Edge/') > -1;
  
  var supportTransform = function () {
      var prefixes = 'transform WebkitTransform MozTransform'.split(' ');
      var div = document.createElement('div');
      for (var i = 0; i < prefixes.length; i++) {
          if (div && div.style[prefixes[i]] !== undefined) {
              return prefixes[i];
          }
      }
      return false;
  }();
  
  // Window data
  var wndW = void 0;
  var wndH = void 0;
  var wndY = void 0;
  var forceResizeParallax = false;
  var forceScrollParallax = false;
  function updateWndVars(e) {
      wndW = _global.window.innerWidth || document.documentElement.clientWidth;
      wndH = _global.window.innerHeight || document.documentElement.clientHeight;
      if ((typeof e === 'undefined' ? 'undefined' : _typeof(e)) === 'object' && (e.type === 'load' || e.type === 'dom-loaded')) {
          forceResizeParallax = true;
      }
  }
  updateWndVars();
  _global.window.addEventListener('resize', updateWndVars);
  _global.window.addEventListener('orientationchange', updateWndVars);
  _global.window.addEventListener('load', updateWndVars);
  (0, _liteReady2.default)(function () {
      updateWndVars({
          type: 'dom-loaded'
      });
  });
  
  // list with all jarallax instances
  // need to render all in one scroll/resize event
  var jarallaxList = [];
  
  // Animate if changed window size or scrolled page
  var oldPageData = false;
  function updateParallax() {
      if (!jarallaxList.length) {
          return;
      }
  
      if (_global.window.pageYOffset !== undefined) {
          wndY = _global.window.pageYOffset;
      } else {
          wndY = (document.documentElement || document.body.parentNode || document.body).scrollTop;
      }
  
      var isResized = forceResizeParallax || !oldPageData || oldPageData.width !== wndW || oldPageData.height !== wndH;
      var isScrolled = forceScrollParallax || isResized || !oldPageData || oldPageData.y !== wndY;
  
      forceResizeParallax = false;
      forceScrollParallax = false;
  
      if (isResized || isScrolled) {
          jarallaxList.forEach(function (item) {
              if (isResized) {
                  item.onResize();
              }
              if (isScrolled) {
                  item.onScroll();
              }
          });
  
          oldPageData = {
              width: wndW,
              height: wndH,
              y: wndY
          };
      }
  
      (0, _rafl2.default)(updateParallax);
  }
  
  // ResizeObserver
  var resizeObserver = global.ResizeObserver ? new global.ResizeObserver(function (entry) {
      if (entry && entry.length) {
          (0, _rafl2.default)(function () {
              entry.forEach(function (item) {
                  if (item.target && item.target.jarallax) {
                      if (!forceResizeParallax) {
                          item.target.jarallax.onResize();
                      }
                      forceScrollParallax = true;
                  }
              });
          });
      }
  }) : false;
  
  var instanceID = 0;
  
  // Jarallax class
  
  var Jarallax = function () {
      function Jarallax(item, userOptions) {
          _classCallCheck(this, Jarallax);
  
          var self = this;
  
          self.instanceID = instanceID++;
  
          self.$item = item;
  
          self.defaults = {
              type: 'scroll', // type of parallax: scroll, scale, opacity, scale-opacity, scroll-opacity
              speed: 0.5, // supported value from -1 to 2
              imgSrc: null,
              imgElement: '.jarallax-img',
              imgSize: 'cover',
              imgPosition: '50% 50%',
              imgRepeat: 'no-repeat', // supported only for background, not for <img> tag
              keepImg: false, // keep <img> tag in it's default place
              elementInViewport: null,
              zIndex: -100,
              disableParallax: false,
              disableVideo: false,
              automaticResize: true, // use ResizeObserver to recalculate position and size of parallax image
  
              // video
              videoSrc: null,
              videoStartTime: 0,
              videoEndTime: 0,
              videoVolume: 0,
              videoPlayOnlyVisible: true,
  
              // events
              onScroll: null, // function(calculations) {}
              onInit: null, // function() {}
              onDestroy: null, // function() {}
              onCoverImage: null // function() {}
          };
  
          // DEPRECATED: old data-options
          var deprecatedDataAttribute = self.$item.getAttribute('data-jarallax');
          var oldDataOptions = JSON.parse(deprecatedDataAttribute || '{}');
          if (deprecatedDataAttribute) {
              // eslint-disable-next-line no-console
              console.warn('Detected usage of deprecated data-jarallax JSON options, you should use pure data-attribute options. See info here - https://github.com/nk-o/jarallax/issues/53');
          }
  
          // prepare data-options
          var dataOptions = self.$item.dataset || {};
          var pureDataOptions = {};
          Object.keys(dataOptions).forEach(function (key) {
              var loweCaseOption = key.substr(0, 1).toLowerCase() + key.substr(1);
              if (loweCaseOption && typeof self.defaults[loweCaseOption] !== 'undefined') {
                  pureDataOptions[loweCaseOption] = dataOptions[key];
              }
          });
  
          self.options = self.extend({}, self.defaults, oldDataOptions, pureDataOptions, userOptions);
          self.pureOptions = self.extend({}, self.options);
  
          // prepare 'true' and 'false' strings to boolean
          Object.keys(self.options).forEach(function (key) {
              if (self.options[key] === 'true') {
                  self.options[key] = true;
              } else if (self.options[key] === 'false') {
                  self.options[key] = false;
              }
          });
  
          // fix speed option [-1.0, 2.0]
          self.options.speed = Math.min(2, Math.max(-1, parseFloat(self.options.speed)));
  
          // deprecated noAndroid and noIos options
          if (self.options.noAndroid || self.options.noIos) {
              // eslint-disable-next-line no-console
              console.warn('Detected usage of deprecated noAndroid or noIos options, you should use disableParallax option. See info here - https://github.com/nk-o/jarallax/#disable-on-mobile-devices');
  
              // prepare fallback if disableParallax option is not used
              if (!self.options.disableParallax) {
                  if (self.options.noIos && self.options.noAndroid) {
                      self.options.disableParallax = /iPad|iPhone|iPod|Android/;
                  } else if (self.options.noIos) {
                      self.options.disableParallax = /iPad|iPhone|iPod/;
                  } else if (self.options.noAndroid) {
                      self.options.disableParallax = /Android/;
                  }
              }
          }
  
          // prepare disableParallax callback
          if (typeof self.options.disableParallax === 'string') {
              self.options.disableParallax = new RegExp(self.options.disableParallax);
          }
          if (self.options.disableParallax instanceof RegExp) {
              var disableParallaxRegexp = self.options.disableParallax;
              self.options.disableParallax = function () {
                  return disableParallaxRegexp.test(navigator.userAgent);
              };
          }
          if (typeof self.options.disableParallax !== 'function') {
              self.options.disableParallax = function () {
                  return false;
              };
          }
  
          // prepare disableVideo callback
          if (typeof self.options.disableVideo === 'string') {
              self.options.disableVideo = new RegExp(self.options.disableVideo);
          }
          if (self.options.disableVideo instanceof RegExp) {
              var disableVideoRegexp = self.options.disableVideo;
              self.options.disableVideo = function () {
                  return disableVideoRegexp.test(navigator.userAgent);
              };
          }
          if (typeof self.options.disableVideo !== 'function') {
              self.options.disableVideo = function () {
                  return false;
              };
          }
  
          // custom element to check if parallax in viewport
          var elementInVP = self.options.elementInViewport;
          // get first item from array
          if (elementInVP && (typeof elementInVP === 'undefined' ? 'undefined' : _typeof(elementInVP)) === 'object' && typeof elementInVP.length !== 'undefined') {
              var _elementInVP = elementInVP;
  
              var _elementInVP2 = _slicedToArray(_elementInVP, 1);
  
              elementInVP = _elementInVP2[0];
          }
          // check if dom element
          if (!(elementInVP instanceof Element)) {
              elementInVP = null;
          }
          self.options.elementInViewport = elementInVP;
  
          self.image = {
              src: self.options.imgSrc || null,
              $container: null,
              useImgTag: false,
  
              // position fixed is needed for the most of browsers because absolute position have glitches
              // on MacOS with smooth scroll there is a huge lags with absolute position - https://github.com/nk-o/jarallax/issues/75
              // on mobile devices better scrolled with absolute position
              position: /iPad|iPhone|iPod|Android/.test(navigator.userAgent) ? 'absolute' : 'fixed'
          };
  
          if (self.initImg() && self.canInitParallax()) {
              self.init();
          }
      }
  
      // add styles to element
  
  
      _createClass(Jarallax, [{
          key: 'css',
          value: function css(el, styles) {
              if (typeof styles === 'string') {
                  return _global.window.getComputedStyle(el).getPropertyValue(styles);
              }
  
              // add transform property with vendor prefix
              if (styles.transform && supportTransform) {
                  styles[supportTransform] = styles.transform;
              }
  
              Object.keys(styles).forEach(function (key) {
                  el.style[key] = styles[key];
              });
              return el;
          }
  
          // Extend like jQuery.extend
  
      }, {
          key: 'extend',
          value: function extend(out) {
              var _arguments = arguments;
  
              out = out || {};
              Object.keys(arguments).forEach(function (i) {
                  if (!_arguments[i]) {
                      return;
                  }
                  Object.keys(_arguments[i]).forEach(function (key) {
                      out[key] = _arguments[i][key];
                  });
              });
              return out;
          }
  
          // get window size and scroll position. Useful for extensions
  
      }, {
          key: 'getWindowData',
          value: function getWindowData() {
              return {
                  width: wndW,
                  height: wndH,
                  y: wndY
              };
          }
  
          // Jarallax functions
  
      }, {
          key: 'initImg',
          value: function initImg() {
              var self = this;
  
              // find image element
              var $imgElement = self.options.imgElement;
              if ($imgElement && typeof $imgElement === 'string') {
                  $imgElement = self.$item.querySelector($imgElement);
              }
              // check if dom element
              if (!($imgElement instanceof Element)) {
                  $imgElement = null;
              }
  
              if ($imgElement) {
                  if (self.options.keepImg) {
                      self.image.$item = $imgElement.cloneNode(true);
                  } else {
                      self.image.$item = $imgElement;
                      self.image.$itemParent = $imgElement.parentNode;
                  }
                  self.image.useImgTag = true;
              }
  
              // true if there is img tag
              if (self.image.$item) {
                  return true;
              }
  
              // get image src
              if (self.image.src === null) {
                  self.image.src = self.css(self.$item, 'background-image').replace(/^url\(['"]?/g, '').replace(/['"]?\)$/g, '');
              }
              return !(!self.image.src || self.image.src === 'none');
          }
      }, {
          key: 'canInitParallax',
          value: function canInitParallax() {
              return supportTransform && !this.options.disableParallax();
          }
      }, {
          key: 'init',
          value: function init() {
              var self = this;
              var containerStyles = {
                  position: 'absolute',
                  top: 0,
                  left: 0,
                  width: '100%',
                  height: '100%',
                  overflow: 'hidden',
                  pointerEvents: 'none'
              };
              var imageStyles = {};
  
              if (!self.options.keepImg) {
                  // save default user styles
                  var curStyle = self.$item.getAttribute('style');
                  if (curStyle) {
                      self.$item.setAttribute('data-jarallax-original-styles', curStyle);
                  }
                  if (self.image.useImgTag) {
                      var curImgStyle = self.image.$item.getAttribute('style');
                      if (curImgStyle) {
                          self.image.$item.setAttribute('data-jarallax-original-styles', curImgStyle);
                      }
                  }
              }
  
              // set relative position and z-index to the parent
              if (self.css(self.$item, 'position') === 'static') {
                  self.css(self.$item, {
                      position: 'relative'
                  });
              }
              if (self.css(self.$item, 'z-index') === 'auto') {
                  self.css(self.$item, {
                      zIndex: 0
                  });
              }
  
              // container for parallax image
              self.image.$container = document.createElement('div');
              self.css(self.image.$container, containerStyles);
              self.css(self.image.$container, {
                  'z-index': self.options.zIndex
              });
  
              // fix for IE https://github.com/nk-o/jarallax/issues/110
              if (isIE) {
                  self.css(self.image.$container, {
                      opacity: 0.9999
                  });
              }
  
              self.image.$container.setAttribute('id', 'jarallax-container-' + self.instanceID);
              self.$item.appendChild(self.image.$container);
  
              // use img tag
              if (self.image.useImgTag) {
                  imageStyles = self.extend({
                      'object-fit': self.options.imgSize,
                      'object-position': self.options.imgPosition,
                      // support for plugin https://github.com/bfred-it/object-fit-images
                      'font-family': 'object-fit: ' + self.options.imgSize + '; object-position: ' + self.options.imgPosition + ';',
                      'max-width': 'none'
                  }, containerStyles, imageStyles);
  
                  // use div with background image
              } else {
                  self.image.$item = document.createElement('div');
                  if (self.image.src) {
                      imageStyles = self.extend({
                          'background-position': self.options.imgPosition,
                          'background-size': self.options.imgSize,
                          'background-repeat': self.options.imgRepeat,
                          'background-image': 'url("' + self.image.src + '")'
                      }, containerStyles, imageStyles);
                  }
              }
  
              if (self.options.type === 'opacity' || self.options.type === 'scale' || self.options.type === 'scale-opacity' || self.options.speed === 1) {
                  self.image.position = 'absolute';
              }
  
              // check if one of parents have transform style (without this check, scroll transform will be inverted if used parallax with position fixed)
              // discussion - https://github.com/nk-o/jarallax/issues/9
              if (self.image.position === 'fixed') {
                  var parentWithTransform = 0;
                  var $itemParents = self.$item;
                  while ($itemParents !== null && $itemParents !== document && parentWithTransform === 0) {
                      var parentTransform = self.css($itemParents, '-webkit-transform') || self.css($itemParents, '-moz-transform') || self.css($itemParents, 'transform');
                      if (parentTransform && parentTransform !== 'none') {
                          parentWithTransform = 1;
                          self.image.position = 'absolute';
                      }
                      $itemParents = $itemParents.parentNode;
                  }
              }
  
              // add position to parallax block
              imageStyles.position = self.image.position;
  
              // insert parallax image
              self.css(self.image.$item, imageStyles);
              self.image.$container.appendChild(self.image.$item);
  
              // set initial position and size
              self.onResize();
              self.onScroll(true);
  
              // ResizeObserver
              if (self.options.automaticResize && resizeObserver) {
                  resizeObserver.observe(self.$item);
              }
  
              // call onInit event
              if (self.options.onInit) {
                  self.options.onInit.call(self);
              }
  
              // remove default user background
              if (self.css(self.$item, 'background-image') !== 'none') {
                  self.css(self.$item, {
                      'background-image': 'none'
                  });
              }
  
              self.addToParallaxList();
          }
  
          // add to parallax instances list
  
      }, {
          key: 'addToParallaxList',
          value: function addToParallaxList() {
              jarallaxList.push(this);
  
              if (jarallaxList.length === 1) {
                  updateParallax();
              }
          }
  
          // remove from parallax instances list
  
      }, {
          key: 'removeFromParallaxList',
          value: function removeFromParallaxList() {
              var self = this;
  
              jarallaxList.forEach(function (item, key) {
                  if (item.instanceID === self.instanceID) {
                      jarallaxList.splice(key, 1);
                  }
              });
          }
      }, {
          key: 'destroy',
          value: function destroy() {
              var self = this;
  
              self.removeFromParallaxList();
  
              // return styles on container as before jarallax init
              var originalStylesTag = self.$item.getAttribute('data-jarallax-original-styles');
              self.$item.removeAttribute('data-jarallax-original-styles');
              // null occurs if there is no style tag before jarallax init
              if (!originalStylesTag) {
                  self.$item.removeAttribute('style');
              } else {
                  self.$item.setAttribute('style', originalStylesTag);
              }
  
              if (self.image.useImgTag) {
                  // return styles on img tag as before jarallax init
                  var originalStylesImgTag = self.image.$item.getAttribute('data-jarallax-original-styles');
                  self.image.$item.removeAttribute('data-jarallax-original-styles');
                  // null occurs if there is no style tag before jarallax init
                  if (!originalStylesImgTag) {
                      self.image.$item.removeAttribute('style');
                  } else {
                      self.image.$item.setAttribute('style', originalStylesTag);
                  }
  
                  // move img tag to its default position
                  if (self.image.$itemParent) {
                      self.image.$itemParent.appendChild(self.image.$item);
                  }
              }
  
              // remove additional dom elements
              if (self.$clipStyles) {
                  self.$clipStyles.parentNode.removeChild(self.$clipStyles);
              }
              if (self.image.$container) {
                  self.image.$container.parentNode.removeChild(self.image.$container);
              }
  
              // call onDestroy event
              if (self.options.onDestroy) {
                  self.options.onDestroy.call(self);
              }
  
              // delete jarallax from item
              delete self.$item.jarallax;
          }
  
          // it will remove some image overlapping
          // overlapping occur due to an image position fixed inside absolute position element
  
      }, {
          key: 'clipContainer',
          value: function clipContainer() {
              // needed only when background in fixed position
              if (this.image.position !== 'fixed') {
                  return;
              }
  
              var self = this;
              var rect = self.image.$container.getBoundingClientRect();
              var width = rect.width,
                  height = rect.height;
  
  
              if (!self.$clipStyles) {
                  self.$clipStyles = document.createElement('style');
                  self.$clipStyles.setAttribute('type', 'text/css');
                  self.$clipStyles.setAttribute('id', 'jarallax-clip-' + self.instanceID);
                  var head = document.head || document.getElementsByTagName('head')[0];
                  head.appendChild(self.$clipStyles);
              }
  
              var styles = '#jarallax-container-' + self.instanceID + ' {\n           clip: rect(0 ' + width + 'px ' + height + 'px 0);\n           clip: rect(0, ' + width + 'px, ' + height + 'px, 0);\n        }';
  
              // add clip styles inline (this method need for support IE8 and less browsers)
              if (self.$clipStyles.styleSheet) {
                  self.$clipStyles.styleSheet.cssText = styles;
              } else {
                  self.$clipStyles.innerHTML = styles;
              }
          }
      }, {
          key: 'coverImage',
          value: function coverImage() {
              var self = this;
  
              var rect = self.image.$container.getBoundingClientRect();
              var contH = rect.height;
              var speed = self.options.speed;
  
              var isScroll = self.options.type === 'scroll' || self.options.type === 'scroll-opacity';
              var scrollDist = 0;
              var resultH = contH;
              var resultMT = 0;
  
              // scroll parallax
              if (isScroll) {
                  // scroll distance and height for image
                  if (speed < 0) {
                      scrollDist = speed * Math.max(contH, wndH);
                  } else {
                      scrollDist = speed * (contH + wndH);
                  }
  
                  // size for scroll parallax
                  if (speed > 1) {
                      resultH = Math.abs(scrollDist - wndH);
                  } else if (speed < 0) {
                      resultH = scrollDist / speed + Math.abs(scrollDist);
                  } else {
                      resultH += Math.abs(wndH - contH) * (1 - speed);
                  }
  
                  scrollDist /= 2;
              }
  
              // store scroll distance
              self.parallaxScrollDistance = scrollDist;
  
              // vertical center
              if (isScroll) {
                  resultMT = (wndH - resultH) / 2;
              } else {
                  resultMT = (contH - resultH) / 2;
              }
  
              // apply result to item
              self.css(self.image.$item, {
                  height: resultH + 'px',
                  marginTop: resultMT + 'px',
                  left: self.image.position === 'fixed' ? rect.left + 'px' : '0',
                  width: rect.width + 'px'
              });
  
              // call onCoverImage event
              if (self.options.onCoverImage) {
                  self.options.onCoverImage.call(self);
              }
  
              // return some useful data. Used in the video cover function
              return {
                  image: {
                      height: resultH,
                      marginTop: resultMT
                  },
                  container: rect
              };
          }
      }, {
          key: 'isVisible',
          value: function isVisible() {
              return this.isElementInViewport || false;
          }
      }, {
          key: 'onScroll',
          value: function onScroll(force) {
              var self = this;
  
              var rect = self.$item.getBoundingClientRect();
              var contT = rect.top;
              var contH = rect.height;
              var styles = {};
  
              // check if in viewport
              var viewportRect = rect;
              if (self.options.elementInViewport) {
                  viewportRect = self.options.elementInViewport.getBoundingClientRect();
              }
              self.isElementInViewport = viewportRect.bottom >= 0 && viewportRect.right >= 0 && viewportRect.top <= wndH && viewportRect.left <= wndW;
  
              // stop calculations if item is not in viewport
              if (force ? false : !self.isElementInViewport) {
                  return;
              }
  
              // calculate parallax helping variables
              var beforeTop = Math.max(0, contT);
              var beforeTopEnd = Math.max(0, contH + contT);
              var afterTop = Math.max(0, -contT);
              var beforeBottom = Math.max(0, contT + contH - wndH);
              var beforeBottomEnd = Math.max(0, contH - (contT + contH - wndH));
              var afterBottom = Math.max(0, -contT + wndH - contH);
              var fromViewportCenter = 1 - 2 * (wndH - contT) / (wndH + contH);
  
              // calculate on how percent of section is visible
              var visiblePercent = 1;
              if (contH < wndH) {
                  visiblePercent = 1 - (afterTop || beforeBottom) / contH;
              } else if (beforeTopEnd <= wndH) {
                  visiblePercent = beforeTopEnd / wndH;
              } else if (beforeBottomEnd <= wndH) {
                  visiblePercent = beforeBottomEnd / wndH;
              }
  
              // opacity
              if (self.options.type === 'opacity' || self.options.type === 'scale-opacity' || self.options.type === 'scroll-opacity') {
                  styles.transform = 'translate3d(0,0,0)';
                  styles.opacity = visiblePercent;
              }
  
              // scale
              if (self.options.type === 'scale' || self.options.type === 'scale-opacity') {
                  var scale = 1;
                  if (self.options.speed < 0) {
                      scale -= self.options.speed * visiblePercent;
                  } else {
                      scale += self.options.speed * (1 - visiblePercent);
                  }
                  styles.transform = 'scale(' + scale + ') translate3d(0,0,0)';
              }
  
              // scroll
              if (self.options.type === 'scroll' || self.options.type === 'scroll-opacity') {
                  var positionY = self.parallaxScrollDistance * fromViewportCenter;
  
                  // fix if parallax block in absolute position
                  if (self.image.position === 'absolute') {
                      positionY -= contT;
                  }
  
                  styles.transform = 'translate3d(0,' + positionY + 'px,0)';
              }
  
              self.css(self.image.$item, styles);
  
              // call onScroll event
              if (self.options.onScroll) {
                  self.options.onScroll.call(self, {
                      section: rect,
  
                      beforeTop: beforeTop,
                      beforeTopEnd: beforeTopEnd,
                      afterTop: afterTop,
                      beforeBottom: beforeBottom,
                      beforeBottomEnd: beforeBottomEnd,
                      afterBottom: afterBottom,
  
                      visiblePercent: visiblePercent,
                      fromViewportCenter: fromViewportCenter
                  });
              }
          }
      }, {
          key: 'onResize',
          value: function onResize() {
              this.coverImage();
              this.clipContainer();
          }
      }]);
  
      return Jarallax;
  }();
  
  // global definition
  
  
  var plugin = function plugin(items) {
      // check for dom element
      // thanks: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
      if ((typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === 'object' ? items instanceof HTMLElement : items && (typeof items === 'undefined' ? 'undefined' : _typeof(items)) === 'object' && items !== null && items.nodeType === 1 && typeof items.nodeName === 'string') {
          items = [items];
      }
  
      var options = arguments[1];
      var args = Array.prototype.slice.call(arguments, 2);
      var len = items.length;
      var k = 0;
      var ret = void 0;
  
      for (k; k < len; k++) {
          if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' || typeof options === 'undefined') {
              if (!items[k].jarallax) {
                  items[k].jarallax = new Jarallax(items[k], options);
              }
          } else if (items[k].jarallax) {
              // eslint-disable-next-line prefer-spread
              ret = items[k].jarallax[options].apply(items[k].jarallax, args);
          }
          if (typeof ret !== 'undefined') {
              return ret;
          }
      }
  
      return items;
  };
  plugin.constructor = Jarallax;
  
  exports.default = plugin;
  /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)))
  
  /***/ }),
  /* 14 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  var global = __webpack_require__(4);
  
  /**
   * `requestAnimationFrame()`
   */
  
  var request = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame || fallback;
  
  var prev = +new Date();
  function fallback(fn) {
    var curr = +new Date();
    var ms = Math.max(0, 16 - (curr - prev));
    var req = setTimeout(fn, ms);
    return prev = curr, req;
  }
  
  /**
   * `cancelAnimationFrame()`
   */
  
  var cancel = global.cancelAnimationFrame || global.webkitCancelAnimationFrame || global.mozCancelAnimationFrame || clearTimeout;
  
  if (Function.prototype.bind) {
    request = request.bind(global);
    cancel = cancel.bind(global);
  }
  
  exports = module.exports = request;
  exports.cancel = cancel;
  
  /***/ })
  /******/ ]);
  
  /*!
   * Name    : Video Background Extension for Jarallax
   * Version : 1.0.1
   * Author  : nK <https://nkdev.info>
   * GitHub  : https://github.com/nk-o/jarallax
   */
  /******/ (function(modules) { // webpackBootstrap
  /******/ 	// The module cache
  /******/ 	var installedModules = {};
  /******/
  /******/ 	// The require function
  /******/ 	function __webpack_require__(moduleId) {
  /******/
  /******/ 		// Check if module is in cache
  /******/ 		if(installedModules[moduleId]) {
  /******/ 			return installedModules[moduleId].exports;
  /******/ 		}
  /******/ 		// Create a new module (and put it into the cache)
  /******/ 		var module = installedModules[moduleId] = {
  /******/ 			i: moduleId,
  /******/ 			l: false,
  /******/ 			exports: {}
  /******/ 		};
  /******/
  /******/ 		// Execute the module function
  /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  /******/
  /******/ 		// Flag the module as loaded
  /******/ 		module.l = true;
  /******/
  /******/ 		// Return the exports of the module
  /******/ 		return module.exports;
  /******/ 	}
  /******/
  /******/
  /******/ 	// expose the modules object (__webpack_modules__)
  /******/ 	__webpack_require__.m = modules;
  /******/
  /******/ 	// expose the module cache
  /******/ 	__webpack_require__.c = installedModules;
  /******/
  /******/ 	// define getter function for harmony exports
  /******/ 	__webpack_require__.d = function(exports, name, getter) {
  /******/ 		if(!__webpack_require__.o(exports, name)) {
  /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
  /******/ 		}
  /******/ 	};
  /******/
  /******/ 	// define __esModule on exports
  /******/ 	__webpack_require__.r = function(exports) {
  /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  /******/ 		}
  /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
  /******/ 	};
  /******/
  /******/ 	// create a fake namespace object
  /******/ 	// mode & 1: value is a module id, require it
  /******/ 	// mode & 2: merge all properties of value into the ns
  /******/ 	// mode & 4: return value when already ns object
  /******/ 	// mode & 8|1: behave like require
  /******/ 	__webpack_require__.t = function(value, mode) {
  /******/ 		if(mode & 1) value = __webpack_require__(value);
  /******/ 		if(mode & 8) return value;
  /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  /******/ 		var ns = Object.create(null);
  /******/ 		__webpack_require__.r(ns);
  /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  /******/ 		return ns;
  /******/ 	};
  /******/
  /******/ 	// getDefaultExport function for compatibility with non-harmony modules
  /******/ 	__webpack_require__.n = function(module) {
  /******/ 		var getter = module && module.__esModule ?
  /******/ 			function getDefault() { return module['default']; } :
  /******/ 			function getModuleExports() { return module; };
  /******/ 		__webpack_require__.d(getter, 'a', getter);
  /******/ 		return getter;
  /******/ 	};
  /******/
  /******/ 	// Object.prototype.hasOwnProperty.call
  /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  /******/
  /******/ 	// __webpack_public_path__
  /******/ 	__webpack_require__.p = "";
  /******/
  /******/
  /******/ 	// Load entry module and return exports
  /******/ 	return __webpack_require__(__webpack_require__.s = 6);
  /******/ })
  /************************************************************************/
  /******/ ([
  /* 0 */,
  /* 1 */,
  /* 2 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  module.exports = function (callback) {
  
  	if (document.readyState === 'complete' || document.readyState === 'interactive') {
  		// Already ready or interactive, execute callback
  		callback.call();
  	} else if (document.attachEvent) {
  		// Old browsers
  		document.attachEvent('onreadystatechange', function () {
  			if (document.readyState === 'interactive') callback.call();
  		});
  	} else if (document.addEventListener) {
  		// Modern browsers
  		document.addEventListener('DOMContentLoaded', callback);
  	}
  };
  
  /***/ }),
  /* 3 */,
  /* 4 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  /* WEBPACK VAR INJECTION */(function(global) {
  
  var win;
  
  if (typeof window !== "undefined") {
      win = window;
  } else if (typeof global !== "undefined") {
      win = global;
  } else if (typeof self !== "undefined") {
      win = self;
  } else {
      win = {};
  }
  
  module.exports = win;
  /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)))
  
  /***/ }),
  /* 5 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var g;
  
  // This works in non-strict mode
  g = function () {
  	return this;
  }();
  
  try {
  	// This works if eval is allowed (see CSP)
  	g = g || Function("return this")() || (1, eval)("this");
  } catch (e) {
  	// This works if the window reference is available
  	if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") g = window;
  }
  
  // g can still be undefined, but nothing to do about it...
  // We return undefined, instead of nothing here, so it's
  // easier to handle this case. if(!global) { ...}
  
  module.exports = g;
  
  /***/ }),
  /* 6 */
  /***/ (function(module, exports, __webpack_require__) {
  
  module.exports = __webpack_require__(7);
  
  
  /***/ }),
  /* 7 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  var _videoWorker = __webpack_require__(8);
  
  var _videoWorker2 = _interopRequireDefault(_videoWorker);
  
  var _global = __webpack_require__(4);
  
  var _global2 = _interopRequireDefault(_global);
  
  var _liteReady = __webpack_require__(2);
  
  var _liteReady2 = _interopRequireDefault(_liteReady);
  
  var _jarallaxVideo = __webpack_require__(10);
  
  var _jarallaxVideo2 = _interopRequireDefault(_jarallaxVideo);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  // add video worker globally to fallback jarallax < 1.10 versions
  _global2.default.VideoWorker = _global2.default.VideoWorker || _videoWorker2.default;
  
  (0, _jarallaxVideo2.default)();
  
  // data-jarallax-video initialization
  (0, _liteReady2.default)(function () {
      if (typeof jarallax !== 'undefined') {
          jarallax(document.querySelectorAll('[data-jarallax-video]'));
      }
  });
  
  /***/ }),
  /* 8 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  module.exports = __webpack_require__(9);
  
  /***/ }),
  /* 9 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  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; }; }();
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  // Deferred
  // thanks http://stackoverflow.com/questions/18096715/implement-deferred-object-without-using-jquery
  function Deferred() {
      this._done = [];
      this._fail = [];
  }
  Deferred.prototype = {
      execute: function execute(list, args) {
          var i = list.length;
          args = Array.prototype.slice.call(args);
          while (i--) {
              list[i].apply(null, args);
          }
      },
      resolve: function resolve() {
          this.execute(this._done, arguments);
      },
      reject: function reject() {
          this.execute(this._fail, arguments);
      },
      done: function done(callback) {
          this._done.push(callback);
      },
      fail: function fail(callback) {
          this._fail.push(callback);
      }
  };
  
  var ID = 0;
  var YoutubeAPIadded = 0;
  var VimeoAPIadded = 0;
  var loadingYoutubePlayer = 0;
  var loadingVimeoPlayer = 0;
  var loadingYoutubeDefer = new Deferred();
  var loadingVimeoDefer = new Deferred();
  
  var VideoWorker = function () {
      function VideoWorker(url, options) {
          _classCallCheck(this, VideoWorker);
  
          var self = this;
  
          self.url = url;
  
          self.options_default = {
              autoplay: false,
              loop: false,
              mute: false,
              volume: 100,
              showContols: true,
  
              // start / end video time in seconds
              startTime: 0,
              endTime: 0
          };
  
          self.options = self.extend({}, self.options_default, options);
  
          // check URL
          self.videoID = self.parseURL(url);
  
          // init
          if (self.videoID) {
              self.ID = ID++;
              self.loadAPI();
              self.init();
          }
      }
  
      // Extend like jQuery.extend
  
  
      _createClass(VideoWorker, [{
          key: 'extend',
          value: function extend(out) {
              var _arguments = arguments;
  
              out = out || {};
              Object.keys(arguments).forEach(function (i) {
                  if (!_arguments[i]) {
                      return;
                  }
                  Object.keys(_arguments[i]).forEach(function (key) {
                      out[key] = _arguments[i][key];
                  });
              });
              return out;
          }
      }, {
          key: 'parseURL',
          value: function parseURL(url) {
              // parse youtube ID
              function getYoutubeID(ytUrl) {
                  // eslint-disable-next-line no-useless-escape
                  var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
                  var match = ytUrl.match(regExp);
                  return match && match[1].length === 11 ? match[1] : false;
              }
  
              // parse vimeo ID
              function getVimeoID(vmUrl) {
                  // eslint-disable-next-line no-useless-escape
                  var regExp = /https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/;
                  var match = vmUrl.match(regExp);
                  return match && match[3] ? match[3] : false;
              }
  
              // parse local string
              function getLocalVideos(locUrl) {
                  // eslint-disable-next-line no-useless-escape
                  var videoFormats = locUrl.split(/,(?=mp4\:|webm\:|ogv\:|ogg\:)/);
                  var result = {};
                  var ready = 0;
                  videoFormats.forEach(function (val) {
                      // eslint-disable-next-line no-useless-escape
                      var match = val.match(/^(mp4|webm|ogv|ogg)\:(.*)/);
                      if (match && match[1] && match[2]) {
                          // eslint-disable-next-line prefer-destructuring
                          result[match[1] === 'ogv' ? 'ogg' : match[1]] = match[2];
                          ready = 1;
                      }
                  });
                  return ready ? result : false;
              }
  
              var Youtube = getYoutubeID(url);
              var Vimeo = getVimeoID(url);
              var Local = getLocalVideos(url);
  
              if (Youtube) {
                  this.type = 'youtube';
                  return Youtube;
              } else if (Vimeo) {
                  this.type = 'vimeo';
                  return Vimeo;
              } else if (Local) {
                  this.type = 'local';
                  return Local;
              }
  
              return false;
          }
      }, {
          key: 'isValid',
          value: function isValid() {
              return !!this.videoID;
          }
  
          // events
  
      }, {
          key: 'on',
          value: function on(name, callback) {
              this.userEventsList = this.userEventsList || [];
  
              // add new callback in events list
              (this.userEventsList[name] || (this.userEventsList[name] = [])).push(callback);
          }
      }, {
          key: 'off',
          value: function off(name, callback) {
              var _this = this;
  
              if (!this.userEventsList || !this.userEventsList[name]) {
                  return;
              }
  
              if (!callback) {
                  delete this.userEventsList[name];
              } else {
                  this.userEventsList[name].forEach(function (val, key) {
                      if (val === callback) {
                          _this.userEventsList[name][key] = false;
                      }
                  });
              }
          }
      }, {
          key: 'fire',
          value: function fire(name) {
              var _this2 = this;
  
              var args = [].slice.call(arguments, 1);
              if (this.userEventsList && typeof this.userEventsList[name] !== 'undefined') {
                  this.userEventsList[name].forEach(function (val) {
                      // call with all arguments
                      if (val) {
                          val.apply(_this2, args);
                      }
                  });
              }
          }
      }, {
          key: 'play',
          value: function play(start) {
              var self = this;
              if (!self.player) {
                  return;
              }
  
              if (self.type === 'youtube' && self.player.playVideo) {
                  if (typeof start !== 'undefined') {
                      self.player.seekTo(start || 0);
                  }
                  if (YT.PlayerState.PLAYING !== self.player.getPlayerState()) {
                      self.player.playVideo();
                  }
              }
  
              if (self.type === 'vimeo') {
                  if (typeof start !== 'undefined') {
                      self.player.setCurrentTime(start);
                  }
                  self.player.getPaused().then(function (paused) {
                      if (paused) {
                          self.player.play();
                      }
                  });
              }
  
              if (self.type === 'local') {
                  if (typeof start !== 'undefined') {
                      self.player.currentTime = start;
                  }
                  if (self.player.paused) {
                      self.player.play();
                  }
              }
          }
      }, {
          key: 'pause',
          value: function pause() {
              var self = this;
              if (!self.player) {
                  return;
              }
  
              if (self.type === 'youtube' && self.player.pauseVideo) {
                  if (YT.PlayerState.PLAYING === self.player.getPlayerState()) {
                      self.player.pauseVideo();
                  }
              }
  
              if (self.type === 'vimeo') {
                  self.player.getPaused().then(function (paused) {
                      if (!paused) {
                          self.player.pause();
                      }
                  });
              }
  
              if (self.type === 'local') {
                  if (!self.player.paused) {
                      self.player.pause();
                  }
              }
          }
      }, {
          key: 'mute',
          value: function mute() {
              var self = this;
              if (!self.player) {
                  return;
              }
  
              if (self.type === 'youtube' && self.player.mute) {
                  self.player.mute();
              }
  
              if (self.type === 'vimeo' && self.player.setVolume) {
                  self.player.setVolume(0);
              }
  
              if (self.type === 'local') {
                  self.$video.muted = true;
              }
          }
      }, {
          key: 'unmute',
          value: function unmute() {
              var self = this;
              if (!self.player) {
                  return;
              }
  
              if (self.type === 'youtube' && self.player.mute) {
                  self.player.unMute();
              }
  
              if (self.type === 'vimeo' && self.player.setVolume) {
                  self.player.setVolume(self.options.volume);
              }
  
              if (self.type === 'local') {
                  self.$video.muted = false;
              }
          }
      }, {
          key: 'setVolume',
          value: function setVolume() {
              var volume = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  
              var self = this;
              if (!self.player || !volume) {
                  return;
              }
  
              if (self.type === 'youtube' && self.player.setVolume) {
                  self.player.setVolume(volume);
              }
  
              if (self.type === 'vimeo' && self.player.setVolume) {
                  self.player.setVolume(volume);
              }
  
              if (self.type === 'local') {
                  self.$video.volume = volume / 100;
              }
          }
      }, {
          key: 'getVolume',
          value: function getVolume(callback) {
              var self = this;
              if (!self.player) {
                  callback(false);
                  return;
              }
  
              if (self.type === 'youtube' && self.player.getVolume) {
                  callback(self.player.getVolume());
              }
  
              if (self.type === 'vimeo' && self.player.getVolume) {
                  self.player.getVolume().then(function (volume) {
                      callback(volume);
                  });
              }
  
              if (self.type === 'local') {
                  callback(self.$video.volume * 100);
              }
          }
      }, {
          key: 'getMuted',
          value: function getMuted(callback) {
              var self = this;
              if (!self.player) {
                  callback(null);
                  return;
              }
  
              if (self.type === 'youtube' && self.player.isMuted) {
                  callback(self.player.isMuted());
              }
  
              if (self.type === 'vimeo' && self.player.getVolume) {
                  self.player.getVolume().then(function (volume) {
                      callback(!!volume);
                  });
              }
  
              if (self.type === 'local') {
                  callback(self.$video.muted);
              }
          }
      }, {
          key: 'getImageURL',
          value: function getImageURL(callback) {
              var self = this;
  
              if (self.videoImage) {
                  callback(self.videoImage);
                  return;
              }
  
              if (self.type === 'youtube') {
                  var availableSizes = ['maxresdefault', 'sddefault', 'hqdefault', '0'];
                  var step = 0;
  
                  var tempImg = new Image();
                  tempImg.onload = function () {
                      // if no thumbnail, youtube add their own image with width = 120px
                      if ((this.naturalWidth || this.width) !== 120 || step === availableSizes.length - 1) {
                          // ok
                          self.videoImage = 'https://img.youtube.com/vi/' + self.videoID + '/' + availableSizes[step] + '.jpg';
                          callback(self.videoImage);
                      } else {
                          // try another size
                          step++;
                          this.src = 'https://img.youtube.com/vi/' + self.videoID + '/' + availableSizes[step] + '.jpg';
                      }
                  };
                  tempImg.src = 'https://img.youtube.com/vi/' + self.videoID + '/' + availableSizes[step] + '.jpg';
              }
  
              if (self.type === 'vimeo') {
                  var request = new XMLHttpRequest();
                  request.open('GET', 'https://vimeo.com/api/v2/video/' + self.videoID + '.json', true);
                  request.onreadystatechange = function () {
                      if (this.readyState === 4) {
                          if (this.status >= 200 && this.status < 400) {
                              // Success!
                              var response = JSON.parse(this.responseText);
                              self.videoImage = response[0].thumbnail_large;
                              callback(self.videoImage);
                          } else {
                              // Error :(
                          }
                      }
                  };
                  request.send();
                  request = null;
              }
          }
  
          // fallback to the old version.
  
      }, {
          key: 'getIframe',
          value: function getIframe(callback) {
              this.getVideo(callback);
          }
      }, {
          key: 'getVideo',
          value: function getVideo(callback) {
              var self = this;
  
              // return generated video block
              if (self.$video) {
                  callback(self.$video);
                  return;
              }
  
              // generate new video block
              self.onAPIready(function () {
                  var hiddenDiv = void 0;
                  if (!self.$video) {
                      hiddenDiv = document.createElement('div');
                      hiddenDiv.style.display = 'none';
                  }
  
                  // Youtube
                  if (self.type === 'youtube') {
                      self.playerOptions = {};
                      self.playerOptions.videoId = self.videoID;
                      self.playerOptions.playerVars = {
                          autohide: 1,
                          rel: 0,
                          autoplay: 0,
                          // autoplay enable on mobile devices
                          playsinline: 1
                      };
  
                      // hide controls
                      if (!self.options.showContols) {
                          self.playerOptions.playerVars.iv_load_policy = 3;
                          self.playerOptions.playerVars.modestbranding = 1;
                          self.playerOptions.playerVars.controls = 0;
                          self.playerOptions.playerVars.showinfo = 0;
                          self.playerOptions.playerVars.disablekb = 1;
                      }
  
                      // events
                      var ytStarted = void 0;
                      var ytProgressInterval = void 0;
                      self.playerOptions.events = {
                          onReady: function onReady(e) {
                              // mute
                              if (self.options.mute) {
                                  e.target.mute();
                              } else if (self.options.volume) {
                                  e.target.setVolume(self.options.volume);
                              }
  
                              // autoplay
                              if (self.options.autoplay) {
                                  self.play(self.options.startTime);
                              }
                              self.fire('ready', e);
  
                              // volumechange
                              setInterval(function () {
                                  self.getVolume(function (volume) {
                                      if (self.options.volume !== volume) {
                                          self.options.volume = volume;
                                          self.fire('volumechange', e);
                                      }
                                  });
                              }, 150);
                          },
                          onStateChange: function onStateChange(e) {
                              // loop
                              if (self.options.loop && e.data === YT.PlayerState.ENDED) {
                                  self.play(self.options.startTime);
                              }
                              if (!ytStarted && e.data === YT.PlayerState.PLAYING) {
                                  ytStarted = 1;
                                  self.fire('started', e);
                              }
                              if (e.data === YT.PlayerState.PLAYING) {
                                  self.fire('play', e);
                              }
                              if (e.data === YT.PlayerState.PAUSED) {
                                  self.fire('pause', e);
                              }
                              if (e.data === YT.PlayerState.ENDED) {
                                  self.fire('ended', e);
                              }
  
                              // progress check
                              if (e.data === YT.PlayerState.PLAYING) {
                                  ytProgressInterval = setInterval(function () {
                                      self.fire('timeupdate', e);
  
                                      // check for end of video and play again or stop
                                      if (self.options.endTime && self.player.getCurrentTime() >= self.options.endTime) {
                                          if (self.options.loop) {
                                              self.play(self.options.startTime);
                                          } else {
                                              self.pause();
                                          }
                                      }
                                  }, 150);
                              } else {
                                  clearInterval(ytProgressInterval);
                              }
                          }
                      };
  
                      var firstInit = !self.$video;
                      if (firstInit) {
                          var div = document.createElement('div');
                          div.setAttribute('id', self.playerID);
                          hiddenDiv.appendChild(div);
                          document.body.appendChild(hiddenDiv);
                      }
                      self.player = self.player || new window.YT.Player(self.playerID, self.playerOptions);
                      if (firstInit) {
                          self.$video = document.getElementById(self.playerID);
  
                          // get video width and height
                          self.videoWidth = parseInt(self.$video.getAttribute('width'), 10) || 1280;
                          self.videoHeight = parseInt(self.$video.getAttribute('height'), 10) || 720;
                      }
                  }
  
                  // Vimeo
                  if (self.type === 'vimeo') {
                      self.playerOptions = '';
  
                      self.playerOptions += 'player_id=' + self.playerID;
                      self.playerOptions += '&autopause=0';
                      self.playerOptions += '&transparent=0';
  
                      // hide controls
                      if (!self.options.showContols) {
                          self.playerOptions += '&badge=0&byline=0&portrait=0&title=0';
                      }
  
                      // autoplay
                      self.playerOptions += '&autoplay=' + (self.options.autoplay ? '1' : '0');
  
                      // loop
                      self.playerOptions += '&loop=' + (self.options.loop ? 1 : 0);
  
                      if (!self.$video) {
                          self.$video = document.createElement('iframe');
                          self.$video.setAttribute('id', self.playerID);
                          self.$video.setAttribute('src', 'https://player.vimeo.com/video/' + self.videoID + '?' + self.playerOptions);
                          self.$video.setAttribute('frameborder', '0');
                          hiddenDiv.appendChild(self.$video);
                          document.body.appendChild(hiddenDiv);
                      }
  
                      self.player = self.player || new Vimeo.Player(self.$video);
  
                      // get video width and height
                      self.player.getVideoWidth().then(function (width) {
                          self.videoWidth = width || 1280;
                      });
                      self.player.getVideoHeight().then(function (height) {
                          self.videoHeight = height || 720;
                      });
  
                      // set current time for autoplay
                      if (self.options.startTime && self.options.autoplay) {
                          self.player.setCurrentTime(self.options.startTime);
                      }
  
                      // mute
                      if (self.options.mute) {
                          self.player.setVolume(0);
                      } else if (self.options.volume) {
                          self.player.setVolume(self.options.volume);
                      }
  
                      var vmStarted = void 0;
                      self.player.on('timeupdate', function (e) {
                          if (!vmStarted) {
                              self.fire('started', e);
                              vmStarted = 1;
                          }
  
                          self.fire('timeupdate', e);
  
                          // check for end of video and play again or stop
                          if (self.options.endTime) {
                              if (self.options.endTime && e.seconds >= self.options.endTime) {
                                  if (self.options.loop) {
                                      self.play(self.options.startTime);
                                  } else {
                                      self.pause();
                                  }
                              }
                          }
                      });
                      self.player.on('play', function (e) {
                          self.fire('play', e);
  
                          // check for the start time and start with it
                          if (self.options.startTime && e.seconds === 0) {
                              self.play(self.options.startTime);
                          }
                      });
                      self.player.on('pause', function (e) {
                          self.fire('pause', e);
                      });
                      self.player.on('ended', function (e) {
                          self.fire('ended', e);
                      });
                      self.player.on('loaded', function (e) {
                          self.fire('ready', e);
                      });
                      self.player.on('volumechange', function (e) {
                          self.fire('volumechange', e);
                      });
                  }
  
                  // Local
                  function addSourceToLocal(element, src, type) {
                      var source = document.createElement('source');
                      source.src = src;
                      source.type = type;
                      element.appendChild(source);
                  }
                  if (self.type === 'local') {
                      if (!self.$video) {
                          self.$video = document.createElement('video');
  
                          // show controls
                          if (self.options.showContols) {
                              self.$video.controls = true;
                          }
  
                          // mute
                          if (self.options.mute) {
                              self.$video.muted = true;
                          } else if (self.$video.volume) {
                              self.$video.volume = self.options.volume / 100;
                          }
  
                          // loop
                          if (self.options.loop) {
                              self.$video.loop = true;
                          }
  
                          // autoplay enable on mobile devices
                          self.$video.setAttribute('playsinline', '');
                          self.$video.setAttribute('webkit-playsinline', '');
  
                          self.$video.setAttribute('id', self.playerID);
                          hiddenDiv.appendChild(self.$video);
                          document.body.appendChild(hiddenDiv);
  
                          Object.keys(self.videoID).forEach(function (key) {
                              addSourceToLocal(self.$video, self.videoID[key], 'video/' + key);
                          });
                      }
  
                      self.player = self.player || self.$video;
  
                      var locStarted = void 0;
                      self.player.addEventListener('playing', function (e) {
                          if (!locStarted) {
                              self.fire('started', e);
                          }
                          locStarted = 1;
                      });
                      self.player.addEventListener('timeupdate', function (e) {
                          self.fire('timeupdate', e);
  
                          // check for end of video and play again or stop
                          if (self.options.endTime) {
                              if (self.options.endTime && this.currentTime >= self.options.endTime) {
                                  if (self.options.loop) {
                                      self.play(self.options.startTime);
                                  } else {
                                      self.pause();
                                  }
                              }
                          }
                      });
                      self.player.addEventListener('play', function (e) {
                          self.fire('play', e);
                      });
                      self.player.addEventListener('pause', function (e) {
                          self.fire('pause', e);
                      });
                      self.player.addEventListener('ended', function (e) {
                          self.fire('ended', e);
                      });
                      self.player.addEventListener('loadedmetadata', function () {
                          // get video width and height
                          self.videoWidth = this.videoWidth || 1280;
                          self.videoHeight = this.videoHeight || 720;
  
                          self.fire('ready');
  
                          // autoplay
                          if (self.options.autoplay) {
                              self.play(self.options.startTime);
                          }
                      });
                      self.player.addEventListener('volumechange', function (e) {
                          self.getVolume(function (volume) {
                              self.options.volume = volume;
                          });
                          self.fire('volumechange', e);
                      });
                  }
  
                  callback(self.$video);
              });
          }
      }, {
          key: 'init',
          value: function init() {
              var self = this;
  
              self.playerID = 'VideoWorker-' + self.ID;
          }
      }, {
          key: 'loadAPI',
          value: function loadAPI() {
              var self = this;
  
              if (YoutubeAPIadded && VimeoAPIadded) {
                  return;
              }
  
              var src = '';
  
              // load Youtube API
              if (self.type === 'youtube' && !YoutubeAPIadded) {
                  YoutubeAPIadded = 1;
                  src = 'https://www.youtube.com/iframe_api';
              }
  
              // load Vimeo API
              if (self.type === 'vimeo' && !VimeoAPIadded) {
                  VimeoAPIadded = 1;
                  src = 'https://player.vimeo.com/api/player.js';
              }
  
              if (!src) {
                  return;
              }
  
              // add script in head section
              var tag = document.createElement('script');
              var head = document.getElementsByTagName('head')[0];
              tag.src = src;
  
              head.appendChild(tag);
  
              head = null;
              tag = null;
          }
      }, {
          key: 'onAPIready',
          value: function onAPIready(callback) {
              var self = this;
  
              // Youtube
              if (self.type === 'youtube') {
                  // Listen for global YT player callback
                  if ((typeof YT === 'undefined' || YT.loaded === 0) && !loadingYoutubePlayer) {
                      // Prevents Ready event from being called twice
                      loadingYoutubePlayer = 1;
  
                      // Creates deferred so, other players know when to wait.
                      window.onYouTubeIframeAPIReady = function () {
                          window.onYouTubeIframeAPIReady = null;
                          loadingYoutubeDefer.resolve('done');
                          callback();
                      };
                  } else if ((typeof YT === 'undefined' ? 'undefined' : _typeof(YT)) === 'object' && YT.loaded === 1) {
                      callback();
                  } else {
                      loadingYoutubeDefer.done(function () {
                          callback();
                      });
                  }
              }
  
              // Vimeo
              if (self.type === 'vimeo') {
                  if (typeof Vimeo === 'undefined' && !loadingVimeoPlayer) {
                      loadingVimeoPlayer = 1;
                      var vimeoInterval = setInterval(function () {
                          if (typeof Vimeo !== 'undefined') {
                              clearInterval(vimeoInterval);
                              loadingVimeoDefer.resolve('done');
                              callback();
                          }
                      }, 20);
                  } else if (typeof Vimeo !== 'undefined') {
                      callback();
                  } else {
                      loadingVimeoDefer.done(function () {
                          callback();
                      });
                  }
              }
  
              // Local
              if (self.type === 'local') {
                  callback();
              }
          }
      }]);
  
      return VideoWorker;
  }();
  
  exports.default = VideoWorker;
  
  /***/ }),
  /* 10 */
  /***/ (function(module, exports, __webpack_require__) {
  
  "use strict";
  
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  exports.default = jarallaxVideo;
  
  var _videoWorker = __webpack_require__(8);
  
  var _videoWorker2 = _interopRequireDefault(_videoWorker);
  
  var _global = __webpack_require__(4);
  
  var _global2 = _interopRequireDefault(_global);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function jarallaxVideo() {
      var jarallax = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _global2.default.jarallax;
  
      if (typeof jarallax === 'undefined') {
          return;
      }
  
      var Jarallax = jarallax.constructor;
  
      // append video after init Jarallax
      var defInit = Jarallax.prototype.init;
      Jarallax.prototype.init = function () {
          var self = this;
  
          defInit.apply(self);
  
          if (self.video && !self.options.disableVideo()) {
              self.video.getVideo(function (video) {
                  var $parent = video.parentNode;
                  self.css(video, {
                      position: self.image.position,
                      top: '0px',
                      left: '0px',
                      right: '0px',
                      bottom: '0px',
                      width: '100%',
                      height: '100%',
                      maxWidth: 'none',
                      maxHeight: 'none',
                      margin: 0,
                      zIndex: -1
                  });
                  self.$video = video;
                  self.image.$container.appendChild(video);
  
                  // remove parent video element (created by VideoWorker)
                  $parent.parentNode.removeChild($parent);
              });
          }
      };
  
      // cover video
      var defCoverImage = Jarallax.prototype.coverImage;
      Jarallax.prototype.coverImage = function () {
          var self = this;
          var imageData = defCoverImage.apply(self);
          var node = self.image.$item ? self.image.$item.nodeName : false;
  
          if (imageData && self.video && node && (node === 'IFRAME' || node === 'VIDEO')) {
              var h = imageData.image.height;
              var w = h * self.image.width / self.image.height;
              var ml = (imageData.container.width - w) / 2;
              var mt = imageData.image.marginTop;
  
              if (imageData.container.width > w) {
                  w = imageData.container.width;
                  h = w * self.image.height / self.image.width;
                  ml = 0;
                  mt += (imageData.image.height - h) / 2;
              }
  
              // add video height over than need to hide controls
              if (node === 'IFRAME') {
                  h += 400;
                  mt -= 200;
              }
  
              self.css(self.$video, {
                  width: w + 'px',
                  marginLeft: ml + 'px',
                  height: h + 'px',
                  marginTop: mt + 'px'
              });
          }
  
          return imageData;
      };
  
      // init video
      var defInitImg = Jarallax.prototype.initImg;
      Jarallax.prototype.initImg = function () {
          var self = this;
          var defaultResult = defInitImg.apply(self);
  
          if (!self.options.videoSrc) {
              self.options.videoSrc = self.$item.getAttribute('data-jarallax-video') || null;
          }
  
          if (self.options.videoSrc) {
              self.defaultInitImgResult = defaultResult;
              return true;
          }
  
          return defaultResult;
      };
  
      var defCanInitParallax = Jarallax.prototype.canInitParallax;
      Jarallax.prototype.canInitParallax = function () {
          var self = this;
          var defaultResult = defCanInitParallax.apply(self);
  
          if (!self.options.videoSrc) {
              return defaultResult;
          }
  
          var video = new _videoWorker2.default(self.options.videoSrc, {
              autoplay: true,
              loop: true,
              showContols: false,
              startTime: self.options.videoStartTime || 0,
              endTime: self.options.videoEndTime || 0,
              mute: self.options.videoVolume ? 0 : 1,
              volume: self.options.videoVolume || 0
          });
  
          if (video.isValid()) {
              // if parallax will not be inited, we can add thumbnail on background.
              if (!defaultResult) {
                  if (!self.defaultInitImgResult) {
                      video.getImageURL(function (url) {
                          // save default user styles
                          var curStyle = self.$item.getAttribute('style');
                          if (curStyle) {
                              self.$item.setAttribute('data-jarallax-original-styles', curStyle);
                          }
  
                          // set new background
                          self.css(self.$item, {
                              'background-image': 'url("' + url + '")',
                              'background-position': 'center',
                              'background-size': 'cover'
                          });
                      });
                  }
  
                  // init video
              } else {
                  video.on('ready', function () {
                      if (self.options.videoPlayOnlyVisible) {
                          var oldOnScroll = self.onScroll;
                          self.onScroll = function () {
                              oldOnScroll.apply(self);
                              if (self.isVisible()) {
                                  video.play();
                              } else {
                                  video.pause();
                              }
                          };
                      } else {
                          video.play();
                      }
                  });
  
                  video.on('started', function () {
                      self.image.$default_item = self.image.$item;
                      self.image.$item = self.$video;
  
                      // set video width and height
                      self.image.width = self.video.videoWidth || 1280;
                      self.image.height = self.video.videoHeight || 720;
                      self.options.imgWidth = self.image.width;
                      self.options.imgHeight = self.image.height;
                      self.coverImage();
                      self.clipContainer();
                      self.onScroll();
  
                      // hide image
                      if (self.image.$default_item) {
                          self.image.$default_item.style.display = 'none';
                      }
                  });
  
                  self.video = video;
  
                  // set image if not exists
                  if (!self.defaultInitImgResult) {
                      if (video.type !== 'local') {
                          video.getImageURL(function (url) {
                              self.image.src = url;
                              self.init();
                          });
  
                          return false;
                      }
  
                      // set empty image on local video if not defined
                      self.image.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
                      return true;
                  }
              }
          }
  
          return defaultResult;
      };
  
      // Destroy video parallax
      var defDestroy = Jarallax.prototype.destroy;
      Jarallax.prototype.destroy = function () {
          var self = this;
  
          if (self.image.$default_item) {
              self.image.$item = self.image.$default_item;
              delete self.image.$default_item;
          }
  
          defDestroy.apply(self);
      };
  }
  
  /***/ })
  /******/ ]);
  "use strict";
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
  
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  
  (function ($) {
    var INPUT_DATA = {};
    var DATA_COLOR = '';
    var BUTTON_X_COLOR = '';
    var BUTTON_X_BLUR_COLOR = '#ced4da';
    var INPUT_FOCUS = '1px solid #4285f4';
    var INPUT_BLUR = '1px solid #ced4da';
    var INPUT_FOCUS_SHADOW = '0 1px 0 0 #4285f4';
    var INPUT_BLUR_SHADOW = '';
    var ENTER_CHAR_CODE = 13;
  
    var mdbAutocomplete =
    /*#__PURE__*/
    function () {
      function mdbAutocomplete(input, options) {
        _classCallCheck(this, mdbAutocomplete);
  
        this.defaults = {
          data: INPUT_DATA,
          dataColor: DATA_COLOR,
          xColor: BUTTON_X_COLOR,
          xBlurColor: BUTTON_X_BLUR_COLOR,
          inputFocus: INPUT_FOCUS,
          inputBlur: INPUT_BLUR,
          inputFocusShadow: INPUT_FOCUS_SHADOW,
          inputBlurShadow: INPUT_BLUR_SHADOW
        };
        this.$input = input;
        this.options = this.assignOptions(options);
        this.$clearButton = $('.mdb-autocomplete-clear');
        this.$autocompleteWrap = $('<ul class="mdb-autocomplete-wrap"></ul>');
        this.init();
      }
  
      _createClass(mdbAutocomplete, [{
        key: "init",
        value: function init() {
          this.setData();
          this.inputFocus();
          this.inputBlur();
          this.inputKeyupData();
          this.inputLiClick();
          this.clearAutocomplete();
        }
      }, {
        key: "assignOptions",
        value: function assignOptions(newOptions) {
          return $.extend({}, this.defaults, newOptions);
        }
      }, {
        key: "setData",
        value: function setData() {
          if (Object.keys(this.options.data).length) {
            this.$autocompleteWrap.insertAfter(this.$input);
          }
        }
      }, {
        key: "inputFocus",
        value: function inputFocus() {
          var _this = this;
  
          this.$input.on('focus', function () {
            _this.$input.css('border-bottom', _this.options.inputFocus);
  
            _this.$input.css('box-shadow', _this.options.inputFocusShadow);
          });
        }
      }, {
        key: "inputBlur",
        value: function inputBlur() {
          var _this2 = this;
  
          this.$input.on('blur', function () {
            _this2.$input.css('border-bottom', _this2.options.inputBlur);
  
            _this2.$input.css('box-shadow', _this2.options.inputBlurShadow);
          });
        }
      }, {
        key: "inputKeyupData",
        value: function inputKeyupData() {
          var _this3 = this;
  
          this.$input.on('keyup', function (e) {
            var $inputValue = _this3.$input.val();
  
            _this3.$autocompleteWrap.empty();
  
            if ($inputValue.length) {
              for (var item in _this3.options.data) {
                if (_this3.options.data[item].toLowerCase().indexOf($inputValue.toLowerCase()) !== -1) {
                  var option = $("<li>".concat(_this3.options.data[item], "</li>"));
  
                  _this3.$autocompleteWrap.append(option);
                }
              }
            }
  
            if (e.which === ENTER_CHAR_CODE) {
              _this3.$autocompleteWrap.children(':first').trigger('click');
  
              _this3.$autocompleteWrap.empty();
            }
  
            if ($inputValue.length === 0) {
              _this3.$input.parent().find('.mdb-autocomplete-clear').css('visibility', 'hidden');
            } else {
              _this3.$input.parent().find('.mdb-autocomplete-clear').css('visibility', 'visible');
            }
  
            _this3.$autocompleteWrap.children().css('color', _this3.options.dataColor);
          });
        }
      }, {
        key: "inputLiClick",
        value: function inputLiClick() {
          var _this4 = this;
  
          this.$autocompleteWrap.on('click', 'li', function (e) {
            e.preventDefault();
  
            _this4.$input.val($(e.target).text());
  
            _this4.$autocompleteWrap.empty();
          });
        }
      }, {
        key: "clearAutocomplete",
        value: function clearAutocomplete() {
          var _this5 = this;
  
          this.$clearButton.on('click', function (e) {
            e.preventDefault();
            var $this = $(e.currentTarget);
            $this.parent().find('.mdb-autocomplete').val('');
            $this.css('visibility', 'hidden');
  
            _this5.$autocompleteWrap.empty();
  
            $this.parent().find('label').removeClass('active');
          });
        }
      }, {
        key: "changeSVGcolors",
        value: function changeSVGcolors() {
          var _this6 = this;
  
          if (this.$input.hasClass('mdb-autocomplete')) {
            this.$input.on('click keyup', function (e) {
              e.preventDefault();
              $(e.target).parent().find('.mdb-autocomplete-clear').find('svg').css('fill', _this6.options.xColor);
            });
            this.$input.on('blur', function (e) {
              e.preventDefault();
              $(e.target).parent().find('.mdb-autocomplete-clear').find('svg').css('fill', _this6.options.xBlurColor);
            });
          }
        }
      }]);
  
      return mdbAutocomplete;
    }();
  
    $.fn.mdbAutocomplete = function (options) {
      return this.each(function () {
        new mdbAutocomplete($(this), options);
      });
    };
  })(jQuery);
  /*
      Enhanced Bootstrap Modals
      https://mdbootstrap.com
      office@mdbootstrap.com
  */
  
  (function($){
    $('body').on('shown.bs.modal', '.modal', function() {
      if(!$('.modal-backdrop').length) {
  
        $modal_dialog = $(this).children('.modal-dialog')
  
        if($modal_dialog.hasClass('modal-side')) {
          $(this).addClass('modal-scrolling');
          $('body').addClass('scrollable');
        }
  
        if($modal_dialog.hasClass('modal-frame')) {
          $(this).addClass('modal-content-clickable');
          $('body').addClass('scrollable');
        }
      }
    });
    $('body').on('hidden.bs.modal', '.modal', function() {
      $('body').removeClass('scrollable');
    });
  })(jQuery);
  
  /*!
   * bsCustomFileInput v1.3.2 (https://github.com/Johann-S/bs-custom-file-input)
   * Copyright 2018 - 2019 Johann-S <johann.servoire@gmail.com>
   * Licensed under MIT (https://github.com/Johann-S/bs-custom-file-input/blob/master/LICENSE)
   */
  (function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
      typeof define === 'function' && define.amd ? define(factory) :
      (global = global || self, global.bsCustomFileInput = factory());
  }(this, function () {
    'use strict';
  
    var Selector = {
      CUSTOMFILE: '.custom-file input[type="file"]',
      CUSTOMFILELABEL: '.custom-file-label',
      FORM: 'form',
      INPUT: 'input'
    };
  
    var textNodeType = 3;
  
    var getDefaultText = function getDefaultText(input) {
      var defaultText = '';
      var label = input.parentNode.querySelector(Selector.CUSTOMFILELABEL);
  
      if (label) {
        defaultText = label.innerHTML;
      }
  
      return defaultText;
    };
  
    var findFirstChildNode = function findFirstChildNode(element) {
      if (element.childNodes.length > 0) {
        var childNodes = [].slice.call(element.childNodes);
  
        for (var i = 0; i < childNodes.length; i++) {
          var node = childNodes[i];
  
          if (node.nodeType !== textNodeType) {
            return node;
          }
        }
      }
  
      return element;
    };
  
    var restoreDefaultText = function restoreDefaultText(input) {
      var defaultText = input.bsCustomFileInput.defaultText;
      var label = input.parentNode.querySelector(Selector.CUSTOMFILELABEL);
  
      if (label) {
        var element = findFirstChildNode(label);
        element.innerHTML = defaultText;
      }
    };
  
    var fileApi = !!window.File;
    var FAKE_PATH = 'fakepath';
    var FAKE_PATH_SEPARATOR = '\\';
  
    var getSelectedFiles = function getSelectedFiles(input) {
      if (input.hasAttribute('multiple') && fileApi) {
        return [].slice.call(input.files).map(function (file) {
          return file.name;
        }).join(', ');
      }
  
      if (input.value.indexOf(FAKE_PATH) !== -1) {
        var splittedValue = input.value.split(FAKE_PATH_SEPARATOR);
        return splittedValue[splittedValue.length - 1];
      }
  
      return input.value;
    };
  
    function handleInputChange() {
      var label = this.parentNode.querySelector(Selector.CUSTOMFILELABEL);
  
      if (label) {
        var element = findFirstChildNode(label);
        var inputValue = getSelectedFiles(this);
  
        if (inputValue.length) {
          element.innerHTML = inputValue;
        } else {
          restoreDefaultText(this);
        }
      }
    }
  
    function handleFormReset() {
      var customFileList = [].slice.call(this.querySelectorAll(Selector.INPUT)).filter(function (input) {
        return !!input.bsCustomFileInput;
      });
  
      for (var i = 0, len = customFileList.length; i < len; i++) {
        restoreDefaultText(customFileList[i]);
      }
    }
  
    var customProperty = 'bsCustomFileInput';
    var Event = {
      FORMRESET: 'reset',
      INPUTCHANGE: 'change'
    };
    var bsCustomFileInput = {
      init: function init(inputSelector, formSelector) {
        if (inputSelector === void 0) {
          inputSelector = Selector.CUSTOMFILE;
        }
  
        if (formSelector === void 0) {
          formSelector = Selector.FORM;
        }
  
        var customFileInputList = [].slice.call(document.querySelectorAll(inputSelector));
        var formList = [].slice.call(document.querySelectorAll(formSelector));
  
        for (var i = 0, len = customFileInputList.length; i < len; i++) {
          var input = customFileInputList[i];
          Object.defineProperty(input, customProperty, {
            value: {
              defaultText: getDefaultText(input)
            },
            writable: true
          });
          handleInputChange.call(input);
          input.addEventListener(Event.INPUTCHANGE, handleInputChange);
        }
  
        for (var _i = 0, _len = formList.length; _i < _len; _i++) {
          formList[_i].addEventListener(Event.FORMRESET, handleFormReset);
  
          Object.defineProperty(formList[_i], customProperty, {
            value: true,
            writable: true
          });
        }
      },
      destroy: function destroy() {
        var formList = [].slice.call(document.querySelectorAll(Selector.FORM)).filter(function (form) {
          return !!form.bsCustomFileInput;
        });
        var customFileInputList = [].slice.call(document.querySelectorAll(Selector.INPUT)).filter(function (input) {
          return !!input.bsCustomFileInput;
        });
  
        for (var i = 0, len = customFileInputList.length; i < len; i++) {
          var input = customFileInputList[i];
          restoreDefaultText(input);
          input[customProperty] = undefined;
          input.removeEventListener(Event.INPUTCHANGE, handleInputChange);
        }
  
        for (var _i2 = 0, _len2 = formList.length; _i2 < _len2; _i2++) {
          formList[_i2].removeEventListener(Event.FORMRESET, handleFormReset);
  
          formList[_i2][customProperty] = undefined;
        }
      }
    };
  
    return bsCustomFileInput;
  
  }));
  //# sourceMappingURL=bs-custom-file-input.js.map
  
  document.addEventListener("DOMContentLoaded", function () {
  
    bsCustomFileInput.init()
  });
  
  "use strict";
  
  var toggler = document.getElementsByClassName("rotate");
  var i;
  
  for (i = 0; i < toggler.length; i++) {
    toggler[i].addEventListener("click", function () {
      this.parentElement.querySelector(".nested").classList.toggle("active");
      this.classList.toggle("down");
    });
  }