{"version":3,"sources":["../../node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js","../../node_modules/flickity/dist/flickity.pkgd.js","../../node_modules/colcade/colcade.js","../../node_modules/plyr/dist/plyr.js","../../node_modules/animejs/lib/anime.min.js","../../node_modules/scrollreveal/dist/scrollreveal.js","_jquery.ba-throttle-debounce.js","utils/_ie11_assign.js","utils/_scrollto.js","vendor.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC5+VA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACr/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC9WA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC1/QA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC5hDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC5PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACpaA","file":"vendor.js","sourcesContent":["// ==================================================\n// fancyBox v3.5.7\n//\n// Licensed GPLv3 for open source use\n// or fancyBox Commercial License for commercial use\n//\n// http://fancyapps.com/fancybox/\n// Copyright 2019 fancyApps\n//\n// ==================================================\n(function (window, document, $, undefined) {\r\n \"use strict\";\r\n\r\n window.console = window.console || {\r\n info: function (stuff) {}\r\n };\r\n\r\n // If there's no jQuery, fancyBox can't work\r\n // =========================================\r\n\r\n if (!$) {\r\n return;\r\n }\r\n\r\n // Check if fancyBox is already initialized\r\n // ========================================\r\n\r\n if ($.fn.fancybox) {\r\n console.info(\"fancyBox already initialized\");\r\n\r\n return;\r\n }\r\n\r\n // Private default settings\r\n // ========================\r\n\r\n var defaults = {\r\n // Close existing modals\r\n // Set this to false if you do not need to stack multiple instances\r\n closeExisting: false,\r\n\r\n // Enable infinite gallery navigation\r\n loop: false,\r\n\r\n // Horizontal space between slides\r\n gutter: 50,\r\n\r\n // Enable keyboard navigation\r\n keyboard: true,\r\n\r\n // Should allow caption to overlap the content\r\n preventCaptionOverlap: true,\r\n\r\n // Should display navigation arrows at the screen edges\r\n arrows: true,\r\n\r\n // Should display counter at the top left corner\r\n infobar: true,\r\n\r\n // Should display close button (using `btnTpl.smallBtn` template) over the content\r\n // Can be true, false, \"auto\"\r\n // If \"auto\" - will be automatically enabled for \"html\", \"inline\" or \"ajax\" items\r\n smallBtn: \"auto\",\r\n\r\n // Should display toolbar (buttons at the top)\r\n // Can be true, false, \"auto\"\r\n // If \"auto\" - will be automatically hidden if \"smallBtn\" is enabled\r\n toolbar: \"auto\",\r\n\r\n // What buttons should appear in the top right corner.\r\n // Buttons will be created using templates from `btnTpl` option\r\n // and they will be placed into toolbar (class=\"fancybox-toolbar\"` element)\r\n buttons: [\r\n \"zoom\",\r\n //\"share\",\r\n \"slideShow\",\r\n //\"fullScreen\",\r\n //\"download\",\r\n \"thumbs\",\r\n \"close\"\r\n ],\r\n\r\n // Detect \"idle\" time in seconds\r\n idleTime: 3,\r\n\r\n // Disable right-click and use simple image protection for images\r\n protect: false,\r\n\r\n // Shortcut to make content \"modal\" - disable keyboard navigtion, hide buttons, etc\r\n modal: false,\r\n\r\n image: {\r\n // Wait for images to load before displaying\r\n // true - wait for image to load and then display;\r\n // false - display thumbnail and load the full-sized image over top,\r\n // requires predefined image dimensions (`data-width` and `data-height` attributes)\r\n preload: false\r\n },\r\n\r\n ajax: {\r\n // Object containing settings for ajax request\r\n settings: {\r\n // This helps to indicate that request comes from the modal\r\n // Feel free to change naming\r\n data: {\r\n fancybox: true\r\n }\r\n }\r\n },\r\n\r\n iframe: {\r\n // Iframe template\r\n tpl: '',\r\n\r\n // Preload iframe before displaying it\r\n // This allows to calculate iframe content width and height\r\n // (note: Due to \"Same Origin Policy\", you can't get cross domain data).\r\n preload: true,\r\n\r\n // Custom CSS styling for iframe wrapping element\r\n // You can use this to set custom iframe dimensions\r\n css: {},\r\n\r\n // Iframe tag attributes\r\n attr: {\r\n scrolling: \"auto\"\r\n }\r\n },\r\n\r\n // For HTML5 video only\r\n video: {\r\n tpl: '\",\r\n format: \"\", // custom video format\r\n autoStart: true\r\n },\r\n\r\n // Default content type if cannot be detected automatically\r\n defaultType: \"image\",\r\n\r\n // Open/close animation type\r\n // Possible values:\r\n // false - disable\r\n // \"zoom\" - zoom images from/to thumbnail\r\n // \"fade\"\r\n // \"zoom-in-out\"\r\n //\r\n animationEffect: \"zoom\",\r\n\r\n // Duration in ms for open/close animation\r\n animationDuration: 366,\r\n\r\n // Should image change opacity while zooming\r\n // If opacity is \"auto\", then opacity will be changed if image and thumbnail have different aspect ratios\r\n zoomOpacity: \"auto\",\r\n\r\n // Transition effect between slides\r\n //\r\n // Possible values:\r\n // false - disable\r\n // \"fade'\r\n // \"slide'\r\n // \"circular'\r\n // \"tube'\r\n // \"zoom-in-out'\r\n // \"rotate'\r\n //\r\n transitionEffect: \"fade\",\r\n\r\n // Duration in ms for transition animation\r\n transitionDuration: 366,\r\n\r\n // Custom CSS class for slide element\r\n slideClass: \"\",\r\n\r\n // Custom CSS class for layout\r\n baseClass: \"\",\r\n\r\n // Base template for layout\r\n baseTpl: '
' +\r\n '
' +\r\n '
' +\r\n '
 / 
' +\r\n '
{{buttons}}
' +\r\n '
{{arrows}}
' +\r\n '
' +\r\n '
' +\r\n \"
\" +\r\n \"
\",\r\n\r\n // Loading indicator template\r\n spinnerTpl: '
',\r\n\r\n // Error message template\r\n errorTpl: '

{{ERROR}}

',\r\n\r\n btnTpl: {\r\n download: '' +\r\n '' +\r\n \"\",\r\n\r\n zoom: '\",\r\n\r\n close: '\",\r\n\r\n // Arrows\r\n arrowLeft: '\",\r\n\r\n arrowRight: '\",\r\n\r\n // This small close button will be appended to your html/inline/ajax content by default,\r\n // if \"smallBtn\" option is not set to false\r\n smallBtn: '\"\r\n },\r\n\r\n // Container is injected into this element\r\n parentEl: \"body\",\r\n\r\n // Hide browser vertical scrollbars; use at your own risk\r\n hideScrollbar: true,\r\n\r\n // Focus handling\r\n // ==============\r\n\r\n // Try to focus on the first focusable element after opening\r\n autoFocus: true,\r\n\r\n // Put focus back to active element after closing\r\n backFocus: true,\r\n\r\n // Do not let user to focus on element outside modal content\r\n trapFocus: true,\r\n\r\n // Module specific options\r\n // =======================\r\n\r\n fullScreen: {\r\n autoStart: false\r\n },\r\n\r\n // Set `touch: false` to disable panning/swiping\r\n touch: {\r\n vertical: true, // Allow to drag content vertically\r\n momentum: true // Continue movement after releasing mouse/touch when panning\r\n },\r\n\r\n // Hash value when initializing manually,\r\n // set `false` to disable hash change\r\n hash: null,\r\n\r\n // Customize or add new media types\r\n // Example:\r\n /*\r\n media : {\r\n youtube : {\r\n params : {\r\n autoplay : 0\r\n }\r\n }\r\n }\r\n */\r\n media: {},\r\n\r\n slideShow: {\r\n autoStart: false,\r\n speed: 3000\r\n },\r\n\r\n thumbs: {\r\n autoStart: false, // Display thumbnails on opening\r\n hideOnClose: true, // Hide thumbnail grid when closing animation starts\r\n parentEl: \".fancybox-container\", // Container is injected into this element\r\n axis: \"y\" // Vertical (y) or horizontal (x) scrolling\r\n },\r\n\r\n // Use mousewheel to navigate gallery\r\n // If 'auto' - enabled for images only\r\n wheel: \"auto\",\r\n\r\n // Callbacks\r\n //==========\r\n\r\n // See Documentation/API/Events for more information\r\n // Example:\r\n /*\r\n afterShow: function( instance, current ) {\r\n console.info( 'Clicked element:' );\r\n console.info( current.opts.$orig );\r\n }\r\n */\r\n\r\n onInit: $.noop, // When instance has been initialized\r\n\r\n beforeLoad: $.noop, // Before the content of a slide is being loaded\r\n afterLoad: $.noop, // When the content of a slide is done loading\r\n\r\n beforeShow: $.noop, // Before open animation starts\r\n afterShow: $.noop, // When content is done loading and animating\r\n\r\n beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.\r\n afterClose: $.noop, // After instance has been closed\r\n\r\n onActivate: $.noop, // When instance is brought to front\r\n onDeactivate: $.noop, // When other instance has been activated\r\n\r\n // Interaction\r\n // ===========\r\n\r\n // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,\r\n // each option can be string or method that returns value.\r\n //\r\n // Possible values:\r\n // \"close\" - close instance\r\n // \"next\" - move to next gallery item\r\n // \"nextOrClose\" - move to next gallery item or close if gallery has only one item\r\n // \"toggleControls\" - show/hide controls\r\n // \"zoom\" - zoom image (if loaded)\r\n // false - do nothing\r\n\r\n // Clicked on the content\r\n clickContent: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n },\r\n\r\n // Clicked on the slide\r\n clickSlide: \"close\",\r\n\r\n // Clicked on the background (backdrop) element;\r\n // if you have not changed the layout, then most likely you need to use `clickSlide` option\r\n clickOutside: \"close\",\r\n\r\n // Same as previous two, but for double click\r\n dblclickContent: false,\r\n dblclickSlide: false,\r\n dblclickOutside: false,\r\n\r\n // Custom options when mobile device is detected\r\n // =============================================\r\n\r\n mobile: {\r\n preventCaptionOverlap: false,\r\n idleTime: false,\r\n clickContent: function (current, event) {\r\n return current.type === \"image\" ? \"toggleControls\" : false;\r\n },\r\n clickSlide: function (current, event) {\r\n return current.type === \"image\" ? \"toggleControls\" : \"close\";\r\n },\r\n dblclickContent: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n },\r\n dblclickSlide: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n }\r\n },\r\n\r\n // Internationalization\r\n // ====================\r\n\r\n lang: \"en\",\r\n i18n: {\r\n en: {\r\n CLOSE: \"Close\",\r\n NEXT: \"Next\",\r\n PREV: \"Previous\",\r\n ERROR: \"The requested content cannot be loaded.
Please try again later.\",\r\n PLAY_START: \"Start slideshow\",\r\n PLAY_STOP: \"Pause slideshow\",\r\n FULL_SCREEN: \"Full screen\",\r\n THUMBS: \"Thumbnails\",\r\n DOWNLOAD: \"Download\",\r\n SHARE: \"Share\",\r\n ZOOM: \"Zoom\"\r\n },\r\n de: {\r\n CLOSE: \"Schließen\",\r\n NEXT: \"Weiter\",\r\n PREV: \"Zurück\",\r\n ERROR: \"Die angeforderten Daten konnten nicht geladen werden.
Bitte versuchen Sie es später nochmal.\",\r\n PLAY_START: \"Diaschau starten\",\r\n PLAY_STOP: \"Diaschau beenden\",\r\n FULL_SCREEN: \"Vollbild\",\r\n THUMBS: \"Vorschaubilder\",\r\n DOWNLOAD: \"Herunterladen\",\r\n SHARE: \"Teilen\",\r\n ZOOM: \"Vergrößern\"\r\n }\r\n }\r\n };\r\n\r\n // Few useful variables and methods\r\n // ================================\r\n\r\n var $W = $(window);\r\n var $D = $(document);\r\n\r\n var called = 0;\r\n\r\n // Check if an object is a jQuery object and not a native JavaScript object\r\n // ========================================================================\r\n var isQuery = function (obj) {\r\n return obj && obj.hasOwnProperty && obj instanceof $;\r\n };\r\n\r\n // Handle multiple browsers for \"requestAnimationFrame\" and \"cancelAnimationFrame\"\r\n // ===============================================================================\r\n var requestAFrame = (function () {\r\n return (\r\n window.requestAnimationFrame ||\r\n window.webkitRequestAnimationFrame ||\r\n window.mozRequestAnimationFrame ||\r\n window.oRequestAnimationFrame ||\r\n // if all else fails, use setTimeout\r\n function (callback) {\r\n return window.setTimeout(callback, 1000 / 60);\r\n }\r\n );\r\n })();\r\n\r\n var cancelAFrame = (function () {\r\n return (\r\n window.cancelAnimationFrame ||\r\n window.webkitCancelAnimationFrame ||\r\n window.mozCancelAnimationFrame ||\r\n window.oCancelAnimationFrame ||\r\n function (id) {\r\n window.clearTimeout(id);\r\n }\r\n );\r\n })();\r\n\r\n // Detect the supported transition-end event property name\r\n // =======================================================\r\n var transitionEnd = (function () {\r\n var el = document.createElement(\"fakeelement\"),\r\n t;\r\n\r\n var transitions = {\r\n transition: \"transitionend\",\r\n OTransition: \"oTransitionEnd\",\r\n MozTransition: \"transitionend\",\r\n WebkitTransition: \"webkitTransitionEnd\"\r\n };\r\n\r\n for (t in transitions) {\r\n if (el.style[t] !== undefined) {\r\n return transitions[t];\r\n }\r\n }\r\n\r\n return \"transitionend\";\r\n })();\r\n\r\n // Force redraw on an element.\r\n // This helps in cases where the browser doesn't redraw an updated element properly\r\n // ================================================================================\r\n var forceRedraw = function ($el) {\r\n return $el && $el.length && $el[0].offsetHeight;\r\n };\r\n\r\n // Exclude array (`buttons`) options from deep merging\r\n // ===================================================\r\n var mergeOpts = function (opts1, opts2) {\r\n var rez = $.extend(true, {}, opts1, opts2);\r\n\r\n $.each(opts2, function (key, value) {\r\n if ($.isArray(value)) {\r\n rez[key] = value;\r\n }\r\n });\r\n\r\n return rez;\r\n };\r\n\r\n // How much of an element is visible in viewport\r\n // =============================================\r\n\r\n var inViewport = function (elem) {\r\n var elemCenter, rez;\r\n\r\n if (!elem || elem.ownerDocument !== document) {\r\n return false;\r\n }\r\n\r\n $(\".fancybox-container\").css(\"pointer-events\", \"none\");\r\n\r\n elemCenter = {\r\n x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,\r\n y: elem.getBoundingClientRect().top + elem.offsetHeight / 2\r\n };\r\n\r\n rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem;\r\n\r\n $(\".fancybox-container\").css(\"pointer-events\", \"\");\r\n\r\n return rez;\r\n };\r\n\r\n // Class definition\r\n // ================\r\n\r\n var FancyBox = function (content, opts, index) {\r\n var self = this;\r\n\r\n self.opts = mergeOpts({\r\n index: index\r\n }, $.fancybox.defaults);\r\n\r\n if ($.isPlainObject(opts)) {\r\n self.opts = mergeOpts(self.opts, opts);\r\n }\r\n\r\n if ($.fancybox.isMobile) {\r\n self.opts = mergeOpts(self.opts, self.opts.mobile);\r\n }\r\n\r\n self.id = self.opts.id || ++called;\r\n\r\n self.currIndex = parseInt(self.opts.index, 10) || 0;\r\n self.prevIndex = null;\r\n\r\n self.prevPos = null;\r\n self.currPos = 0;\r\n\r\n self.firstRun = true;\r\n\r\n // All group items\r\n self.group = [];\r\n\r\n // Existing slides (for current, next and previous gallery items)\r\n self.slides = {};\r\n\r\n // Create group elements\r\n self.addContent(content);\r\n\r\n if (!self.group.length) {\r\n return;\r\n }\r\n\r\n self.init();\r\n };\r\n\r\n $.extend(FancyBox.prototype, {\r\n // Create DOM structure\r\n // ====================\r\n\r\n init: function () {\r\n var self = this,\r\n firstItem = self.group[self.currIndex],\r\n firstItemOpts = firstItem.opts,\r\n $container,\r\n buttonStr;\r\n\r\n if (firstItemOpts.closeExisting) {\r\n $.fancybox.close(true);\r\n }\r\n\r\n // Hide scrollbars\r\n // ===============\r\n\r\n $(\"body\").addClass(\"fancybox-active\");\r\n\r\n if (\r\n !$.fancybox.getInstance() &&\r\n firstItemOpts.hideScrollbar !== false &&\r\n !$.fancybox.isMobile &&\r\n document.body.scrollHeight > window.innerHeight\r\n ) {\r\n $(\"head\").append(\r\n '\"\r\n );\r\n\r\n $(\"body\").addClass(\"compensate-for-scrollbar\");\r\n }\r\n\r\n // Build html markup and set references\r\n // ====================================\r\n\r\n // Build html code for buttons and insert into main template\r\n buttonStr = \"\";\r\n\r\n $.each(firstItemOpts.buttons, function (index, value) {\r\n buttonStr += firstItemOpts.btnTpl[value] || \"\";\r\n });\r\n\r\n // Create markup from base template, it will be initially hidden to\r\n // avoid unnecessary work like painting while initializing is not complete\r\n $container = $(\r\n self.translate(\r\n self,\r\n firstItemOpts.baseTpl\r\n .replace(\"{{buttons}}\", buttonStr)\r\n .replace(\"{{arrows}}\", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight)\r\n )\r\n )\r\n .attr(\"id\", \"fancybox-container-\" + self.id)\r\n .addClass(firstItemOpts.baseClass)\r\n .data(\"FancyBox\", self)\r\n .appendTo(firstItemOpts.parentEl);\r\n\r\n // Create object holding references to jQuery wrapped nodes\r\n self.$refs = {\r\n container: $container\r\n };\r\n\r\n [\"bg\", \"inner\", \"infobar\", \"toolbar\", \"stage\", \"caption\", \"navigation\"].forEach(function (item) {\r\n self.$refs[item] = $container.find(\".fancybox-\" + item);\r\n });\r\n\r\n self.trigger(\"onInit\");\r\n\r\n // Enable events, deactive previous instances\r\n self.activate();\r\n\r\n // Build slides, load and reveal content\r\n self.jumpTo(self.currIndex);\r\n },\r\n\r\n // Simple i18n support - replaces object keys found in template\r\n // with corresponding values\r\n // ============================================================\r\n\r\n translate: function (obj, str) {\r\n var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en;\r\n\r\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, function (match, n) {\r\n return arr[n] === undefined ? match : arr[n];\r\n });\r\n },\r\n\r\n // Populate current group with fresh content\r\n // Check if each object has valid type and content\r\n // ===============================================\r\n\r\n addContent: function (content) {\r\n var self = this,\r\n items = $.makeArray(content),\r\n thumbs;\r\n\r\n $.each(items, function (i, item) {\r\n var obj = {},\r\n opts = {},\r\n $item,\r\n type,\r\n found,\r\n src,\r\n srcParts;\r\n\r\n // Step 1 - Make sure we have an object\r\n // ====================================\r\n\r\n if ($.isPlainObject(item)) {\r\n // We probably have manual usage here, something like\r\n // $.fancybox.open( [ { src : \"image.jpg\", type : \"image\" } ] )\r\n\r\n obj = item;\r\n opts = item.opts || item;\r\n } else if ($.type(item) === \"object\" && $(item).length) {\r\n // Here we probably have jQuery collection returned by some selector\r\n $item = $(item);\r\n\r\n // Support attributes like `data-options='{\"touch\" : false}'` and `data-touch='false'`\r\n opts = $item.data() || {};\r\n opts = $.extend(true, {}, opts, opts.options);\r\n\r\n // Here we store clicked element\r\n opts.$orig = $item;\r\n\r\n obj.src = self.opts.src || opts.src || $item.attr(\"href\");\r\n\r\n // Assume that simple syntax is used, for example:\r\n // `$.fancybox.open( $(\"#test\"), {} );`\r\n if (!obj.type && !obj.src) {\r\n obj.type = \"inline\";\r\n obj.src = item;\r\n }\r\n } else {\r\n // Assume we have a simple html code, for example:\r\n // $.fancybox.open( '

Hi!

' );\r\n obj = {\r\n type: \"html\",\r\n src: item + \"\"\r\n };\r\n }\r\n\r\n // Each gallery object has full collection of options\r\n obj.opts = $.extend(true, {}, self.opts, opts);\r\n\r\n // Do not merge buttons array\r\n if ($.isArray(opts.buttons)) {\r\n obj.opts.buttons = opts.buttons;\r\n }\r\n\r\n if ($.fancybox.isMobile && obj.opts.mobile) {\r\n obj.opts = mergeOpts(obj.opts, obj.opts.mobile);\r\n }\r\n\r\n // Step 2 - Make sure we have content type, if not - try to guess\r\n // ==============================================================\r\n\r\n type = obj.type || obj.opts.type;\r\n src = obj.src || \"\";\r\n\r\n if (!type && src) {\r\n if ((found = src.match(/\\.(mp4|mov|ogv|webm)((\\?|#).*)?$/i))) {\r\n type = \"video\";\r\n\r\n if (!obj.opts.video.format) {\r\n obj.opts.video.format = \"video/\" + (found[1] === \"ogv\" ? \"ogg\" : found[1]);\r\n }\r\n } else if (src.match(/(^data:image\\/[a-z0-9+\\/=]*,)|(\\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\\?|#).*)?$)/i)) {\r\n type = \"image\";\r\n } else if (src.match(/\\.(pdf)((\\?|#).*)?$/i)) {\r\n type = \"iframe\";\r\n obj = $.extend(true, obj, {\r\n contentType: \"pdf\",\r\n opts: {\r\n iframe: {\r\n preload: false\r\n }\r\n }\r\n });\r\n } else if (src.charAt(0) === \"#\") {\r\n type = \"inline\";\r\n }\r\n }\r\n\r\n if (type) {\r\n obj.type = type;\r\n } else {\r\n self.trigger(\"objectNeedsType\", obj);\r\n }\r\n\r\n if (!obj.contentType) {\r\n obj.contentType = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1 ? \"html\" : obj.type;\r\n }\r\n\r\n // Step 3 - Some adjustments\r\n // =========================\r\n\r\n obj.index = self.group.length;\r\n\r\n if (obj.opts.smallBtn == \"auto\") {\r\n obj.opts.smallBtn = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1;\r\n }\r\n\r\n if (obj.opts.toolbar === \"auto\") {\r\n obj.opts.toolbar = !obj.opts.smallBtn;\r\n }\r\n\r\n // Find thumbnail image, check if exists and if is in the viewport\r\n obj.$thumb = obj.opts.$thumb || null;\r\n\r\n if (obj.opts.$trigger && obj.index === self.opts.index) {\r\n obj.$thumb = obj.opts.$trigger.find(\"img:first\");\r\n\r\n if (obj.$thumb.length) {\r\n obj.opts.$orig = obj.opts.$trigger;\r\n }\r\n }\r\n\r\n if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) {\r\n obj.$thumb = obj.opts.$orig.find(\"img:first\");\r\n }\r\n\r\n if (obj.$thumb && !obj.$thumb.length) {\r\n obj.$thumb = null;\r\n }\r\n\r\n obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null);\r\n\r\n // \"caption\" is a \"special\" option, it can be used to customize caption per gallery item\r\n if ($.type(obj.opts.caption) === \"function\") {\r\n obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);\r\n }\r\n\r\n if ($.type(self.opts.caption) === \"function\") {\r\n obj.opts.caption = self.opts.caption.apply(item, [self, obj]);\r\n }\r\n\r\n // Make sure we have caption as a string or jQuery object\r\n if (!(obj.opts.caption instanceof $)) {\r\n obj.opts.caption = obj.opts.caption === undefined ? \"\" : obj.opts.caption + \"\";\r\n }\r\n\r\n // Check if url contains \"filter\" used to filter the content\r\n // Example: \"ajax.html #something\"\r\n if (obj.type === \"ajax\") {\r\n srcParts = src.split(/\\s+/, 2);\r\n\r\n if (srcParts.length > 1) {\r\n obj.src = srcParts.shift();\r\n\r\n obj.opts.filter = srcParts.shift();\r\n }\r\n }\r\n\r\n // Hide all buttons and disable interactivity for modal items\r\n if (obj.opts.modal) {\r\n obj.opts = $.extend(true, obj.opts, {\r\n trapFocus: true,\r\n // Remove buttons\r\n infobar: 0,\r\n toolbar: 0,\r\n\r\n smallBtn: 0,\r\n\r\n // Disable keyboard navigation\r\n keyboard: 0,\r\n\r\n // Disable some modules\r\n slideShow: 0,\r\n fullScreen: 0,\r\n thumbs: 0,\r\n touch: 0,\r\n\r\n // Disable click event handlers\r\n clickContent: false,\r\n clickSlide: false,\r\n clickOutside: false,\r\n dblclickContent: false,\r\n dblclickSlide: false,\r\n dblclickOutside: false\r\n });\r\n }\r\n\r\n // Step 4 - Add processed object to group\r\n // ======================================\r\n\r\n self.group.push(obj);\r\n });\r\n\r\n // Update controls if gallery is already opened\r\n if (Object.keys(self.slides).length) {\r\n self.updateControls();\r\n\r\n // Update thumbnails, if needed\r\n thumbs = self.Thumbs;\r\n\r\n if (thumbs && thumbs.isActive) {\r\n thumbs.create();\r\n\r\n thumbs.focus();\r\n }\r\n }\r\n },\r\n\r\n // Attach an event handler functions for:\r\n // - navigation buttons\r\n // - browser scrolling, resizing;\r\n // - focusing\r\n // - keyboard\r\n // - detecting inactivity\r\n // ======================================\r\n\r\n addEvents: function () {\r\n var self = this;\r\n\r\n self.removeEvents();\r\n\r\n // Make navigation elements clickable\r\n // ==================================\r\n\r\n self.$refs.container\r\n .on(\"click.fb-close\", \"[data-fancybox-close]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.close(e);\r\n })\r\n .on(\"touchstart.fb-prev click.fb-prev\", \"[data-fancybox-prev]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.previous();\r\n })\r\n .on(\"touchstart.fb-next click.fb-next\", \"[data-fancybox-next]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.next();\r\n })\r\n .on(\"click.fb\", \"[data-fancybox-zoom]\", function (e) {\r\n // Click handler for zoom button\r\n self[self.isScaledDown() ? \"scaleToActual\" : \"scaleToFit\"]();\r\n });\r\n\r\n // Handle page scrolling and browser resizing\r\n // ==========================================\r\n\r\n $W.on(\"orientationchange.fb resize.fb\", function (e) {\r\n if (e && e.originalEvent && e.originalEvent.type === \"resize\") {\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n self.update(e);\r\n });\r\n } else {\r\n if (self.current && self.current.type === \"iframe\") {\r\n self.$refs.stage.hide();\r\n }\r\n\r\n setTimeout(\r\n function () {\r\n self.$refs.stage.show();\r\n\r\n self.update(e);\r\n },\r\n $.fancybox.isMobile ? 600 : 250\r\n );\r\n }\r\n });\r\n\r\n $D.on(\"keydown.fb\", function (e) {\r\n var instance = $.fancybox ? $.fancybox.getInstance() : null,\r\n current = instance.current,\r\n keycode = e.keyCode || e.which;\r\n\r\n // Trap keyboard focus inside of the modal\r\n // =======================================\r\n\r\n if (keycode == 9) {\r\n if (current.opts.trapFocus) {\r\n self.focus(e);\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Enable keyboard navigation\r\n // ==========================\r\n\r\n if (!current.opts.keyboard || e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is(\"input,textarea,video,audio,select\")) {\r\n return;\r\n }\r\n\r\n // Backspace and Esc keys\r\n if (keycode === 8 || keycode === 27) {\r\n e.preventDefault();\r\n\r\n self.close(e);\r\n\r\n return;\r\n }\r\n\r\n // Left arrow and Up arrow\r\n if (keycode === 37 || keycode === 38) {\r\n e.preventDefault();\r\n\r\n self.previous();\r\n\r\n return;\r\n }\r\n\r\n // Righ arrow and Down arrow\r\n if (keycode === 39 || keycode === 40) {\r\n e.preventDefault();\r\n\r\n self.next();\r\n\r\n return;\r\n }\r\n\r\n self.trigger(\"afterKeydown\", e, keycode);\r\n });\r\n\r\n // Hide controls after some inactivity period\r\n if (self.group[self.currIndex].opts.idleTime) {\r\n self.idleSecondsCounter = 0;\r\n\r\n $D.on(\r\n \"mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle\",\r\n function (e) {\r\n self.idleSecondsCounter = 0;\r\n\r\n if (self.isIdle) {\r\n self.showControls();\r\n }\r\n\r\n self.isIdle = false;\r\n }\r\n );\r\n\r\n self.idleInterval = window.setInterval(function () {\r\n self.idleSecondsCounter++;\r\n\r\n if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) {\r\n self.isIdle = true;\r\n self.idleSecondsCounter = 0;\r\n\r\n self.hideControls();\r\n }\r\n }, 1000);\r\n }\r\n },\r\n\r\n // Remove events added by the core\r\n // ===============================\r\n\r\n removeEvents: function () {\r\n var self = this;\r\n\r\n $W.off(\"orientationchange.fb resize.fb\");\r\n $D.off(\"keydown.fb .fb-idle\");\r\n\r\n this.$refs.container.off(\".fb-close .fb-prev .fb-next\");\r\n\r\n if (self.idleInterval) {\r\n window.clearInterval(self.idleInterval);\r\n\r\n self.idleInterval = null;\r\n }\r\n },\r\n\r\n // Change to previous gallery item\r\n // ===============================\r\n\r\n previous: function (duration) {\r\n return this.jumpTo(this.currPos - 1, duration);\r\n },\r\n\r\n // Change to next gallery item\r\n // ===========================\r\n\r\n next: function (duration) {\r\n return this.jumpTo(this.currPos + 1, duration);\r\n },\r\n\r\n // Switch to selected gallery item\r\n // ===============================\r\n\r\n jumpTo: function (pos, duration) {\r\n var self = this,\r\n groupLen = self.group.length,\r\n firstRun,\r\n isMoved,\r\n loop,\r\n current,\r\n previous,\r\n slidePos,\r\n stagePos,\r\n prop,\r\n diff;\r\n\r\n if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {\r\n return;\r\n }\r\n\r\n // Should loop?\r\n pos = parseInt(pos, 10);\r\n loop = self.current ? self.current.opts.loop : self.opts.loop;\r\n\r\n if (!loop && (pos < 0 || pos >= groupLen)) {\r\n return false;\r\n }\r\n\r\n // Check if opening for the first time; this helps to speed things up\r\n firstRun = self.firstRun = !Object.keys(self.slides).length;\r\n\r\n // Create slides\r\n previous = self.current;\r\n\r\n self.prevIndex = self.currIndex;\r\n self.prevPos = self.currPos;\r\n\r\n current = self.createSlide(pos);\r\n\r\n if (groupLen > 1) {\r\n if (loop || current.index < groupLen - 1) {\r\n self.createSlide(pos + 1);\r\n }\r\n\r\n if (loop || current.index > 0) {\r\n self.createSlide(pos - 1);\r\n }\r\n }\r\n\r\n self.current = current;\r\n self.currIndex = current.index;\r\n self.currPos = current.pos;\r\n\r\n self.trigger(\"beforeShow\", firstRun);\r\n\r\n self.updateControls();\r\n\r\n // Validate duration length\r\n current.forcedDuration = undefined;\r\n\r\n if ($.isNumeric(duration)) {\r\n current.forcedDuration = duration;\r\n } else {\r\n duration = current.opts[firstRun ? \"animationDuration\" : \"transitionDuration\"];\r\n }\r\n\r\n duration = parseInt(duration, 10);\r\n\r\n // Check if user has swiped the slides or if still animating\r\n isMoved = self.isMoved(current);\r\n\r\n // Make sure current slide is visible\r\n current.$slide.addClass(\"fancybox-slide--current\");\r\n\r\n // Fresh start - reveal container, current slide and start loading content\r\n if (firstRun) {\r\n if (current.opts.animationEffect && duration) {\r\n self.$refs.container.css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n self.$refs.container.addClass(\"fancybox-is-open\").trigger(\"focus\");\r\n\r\n // Attempt to load content into slide\r\n // This will later call `afterLoad` -> `revealContent`\r\n self.loadSlide(current);\r\n\r\n self.preload(\"image\");\r\n\r\n return;\r\n }\r\n\r\n // Get actual slide/stage positions (before cleaning up)\r\n slidePos = $.fancybox.getTranslate(previous.$slide);\r\n stagePos = $.fancybox.getTranslate(self.$refs.stage);\r\n\r\n // Clean up all slides\r\n $.each(self.slides, function (index, slide) {\r\n $.fancybox.stop(slide.$slide, true);\r\n });\r\n\r\n if (previous.pos !== current.pos) {\r\n previous.isComplete = false;\r\n }\r\n\r\n previous.$slide.removeClass(\"fancybox-slide--complete fancybox-slide--current\");\r\n\r\n // If slides are out of place, then animate them to correct position\r\n if (isMoved) {\r\n // Calculate horizontal swipe distance\r\n diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter);\r\n\r\n $.each(self.slides, function (index, slide) {\r\n slide.$slide.removeClass(\"fancybox-animated\").removeClass(function (index, className) {\r\n return (className.match(/(^|\\s)fancybox-fx-\\S+/g) || []).join(\" \");\r\n });\r\n\r\n // Make sure that each slide is in equal distance\r\n // This is mostly needed for freshly added slides, because they are not yet positioned\r\n var leftPos = slide.pos * slidePos.width + slide.pos * slide.opts.gutter;\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: 0,\r\n left: leftPos - stagePos.left + diff\r\n });\r\n\r\n if (slide.pos !== current.pos) {\r\n slide.$slide.addClass(\"fancybox-slide--\" + (slide.pos > current.pos ? \"next\" : \"previous\"));\r\n }\r\n\r\n // Redraw to make sure that transition will start\r\n forceRedraw(slide.$slide);\r\n\r\n // Animate the slide\r\n $.fancybox.animate(\r\n slide.$slide, {\r\n top: 0,\r\n left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter\r\n },\r\n duration,\r\n function () {\r\n slide.$slide\r\n .css({\r\n transform: \"\",\r\n opacity: \"\"\r\n })\r\n .removeClass(\"fancybox-slide--next fancybox-slide--previous\");\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n }\r\n );\r\n });\r\n } else if (duration && current.opts.transitionEffect) {\r\n // Set transition effect for previously active slide\r\n prop = \"fancybox-animated fancybox-fx-\" + current.opts.transitionEffect;\r\n\r\n previous.$slide.addClass(\"fancybox-slide--\" + (previous.pos > current.pos ? \"next\" : \"previous\"));\r\n\r\n $.fancybox.animate(\r\n previous.$slide,\r\n prop,\r\n duration,\r\n function () {\r\n previous.$slide.removeClass(prop).removeClass(\"fancybox-slide--next fancybox-slide--previous\");\r\n },\r\n false\r\n );\r\n }\r\n\r\n if (current.isLoaded) {\r\n self.revealContent(current);\r\n } else {\r\n self.loadSlide(current);\r\n }\r\n\r\n self.preload(\"image\");\r\n },\r\n\r\n // Create new \"slide\" element\r\n // These are gallery items that are actually added to DOM\r\n // =======================================================\r\n\r\n createSlide: function (pos) {\r\n var self = this,\r\n $slide,\r\n index;\r\n\r\n index = pos % self.group.length;\r\n index = index < 0 ? self.group.length + index : index;\r\n\r\n if (!self.slides[pos] && self.group[index]) {\r\n $slide = $('
').appendTo(self.$refs.stage);\r\n\r\n self.slides[pos] = $.extend(true, {}, self.group[index], {\r\n pos: pos,\r\n $slide: $slide,\r\n isLoaded: false\r\n });\r\n\r\n self.updateSlide(self.slides[pos]);\r\n }\r\n\r\n return self.slides[pos];\r\n },\r\n\r\n // Scale image to the actual size of the image;\r\n // x and y values should be relative to the slide\r\n // ==============================================\r\n\r\n scaleToActual: function (x, y, duration) {\r\n var self = this,\r\n current = self.current,\r\n $content = current.$content,\r\n canvasWidth = $.fancybox.getTranslate(current.$slide).width,\r\n canvasHeight = $.fancybox.getTranslate(current.$slide).height,\r\n newImgWidth = current.width,\r\n newImgHeight = current.height,\r\n imgPos,\r\n posX,\r\n posY,\r\n scaleX,\r\n scaleY;\r\n\r\n if (self.isAnimating || self.isMoved() || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\r\n return;\r\n }\r\n\r\n self.isAnimating = true;\r\n\r\n $.fancybox.stop($content);\r\n\r\n x = x === undefined ? canvasWidth * 0.5 : x;\r\n y = y === undefined ? canvasHeight * 0.5 : y;\r\n\r\n imgPos = $.fancybox.getTranslate($content);\r\n\r\n imgPos.top -= $.fancybox.getTranslate(current.$slide).top;\r\n imgPos.left -= $.fancybox.getTranslate(current.$slide).left;\r\n\r\n scaleX = newImgWidth / imgPos.width;\r\n scaleY = newImgHeight / imgPos.height;\r\n\r\n // Get center position for original image\r\n posX = canvasWidth * 0.5 - newImgWidth * 0.5;\r\n posY = canvasHeight * 0.5 - newImgHeight * 0.5;\r\n\r\n // Make sure image does not move away from edges\r\n if (newImgWidth > canvasWidth) {\r\n posX = imgPos.left * scaleX - (x * scaleX - x);\r\n\r\n if (posX > 0) {\r\n posX = 0;\r\n }\r\n\r\n if (posX < canvasWidth - newImgWidth) {\r\n posX = canvasWidth - newImgWidth;\r\n }\r\n }\r\n\r\n if (newImgHeight > canvasHeight) {\r\n posY = imgPos.top * scaleY - (y * scaleY - y);\r\n\r\n if (posY > 0) {\r\n posY = 0;\r\n }\r\n\r\n if (posY < canvasHeight - newImgHeight) {\r\n posY = canvasHeight - newImgHeight;\r\n }\r\n }\r\n\r\n self.updateCursor(newImgWidth, newImgHeight);\r\n\r\n $.fancybox.animate(\r\n $content, {\r\n top: posY,\r\n left: posX,\r\n scaleX: scaleX,\r\n scaleY: scaleY\r\n },\r\n duration || 366,\r\n function () {\r\n self.isAnimating = false;\r\n }\r\n );\r\n\r\n // Stop slideshow\r\n if (self.SlideShow && self.SlideShow.isActive) {\r\n self.SlideShow.stop();\r\n }\r\n },\r\n\r\n // Scale image to fit inside parent element\r\n // ========================================\r\n\r\n scaleToFit: function (duration) {\r\n var self = this,\r\n current = self.current,\r\n $content = current.$content,\r\n end;\r\n\r\n if (self.isAnimating || self.isMoved() || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\r\n return;\r\n }\r\n\r\n self.isAnimating = true;\r\n\r\n $.fancybox.stop($content);\r\n\r\n end = self.getFitPos(current);\r\n\r\n self.updateCursor(end.width, end.height);\r\n\r\n $.fancybox.animate(\r\n $content, {\r\n top: end.top,\r\n left: end.left,\r\n scaleX: end.width / $content.width(),\r\n scaleY: end.height / $content.height()\r\n },\r\n duration || 366,\r\n function () {\r\n self.isAnimating = false;\r\n }\r\n );\r\n },\r\n\r\n // Calculate image size to fit inside viewport\r\n // ===========================================\r\n\r\n getFitPos: function (slide) {\r\n var self = this,\r\n $content = slide.$content,\r\n $slide = slide.$slide,\r\n width = slide.width || slide.opts.width,\r\n height = slide.height || slide.opts.height,\r\n maxWidth,\r\n maxHeight,\r\n minRatio,\r\n aspectRatio,\r\n rez = {};\r\n\r\n if (!slide.isLoaded || !$content || !$content.length) {\r\n return false;\r\n }\r\n\r\n maxWidth = $.fancybox.getTranslate(self.$refs.stage).width;\r\n maxHeight = $.fancybox.getTranslate(self.$refs.stage).height;\r\n\r\n maxWidth -=\r\n parseFloat($slide.css(\"paddingLeft\")) +\r\n parseFloat($slide.css(\"paddingRight\")) +\r\n parseFloat($content.css(\"marginLeft\")) +\r\n parseFloat($content.css(\"marginRight\"));\r\n\r\n maxHeight -=\r\n parseFloat($slide.css(\"paddingTop\")) +\r\n parseFloat($slide.css(\"paddingBottom\")) +\r\n parseFloat($content.css(\"marginTop\")) +\r\n parseFloat($content.css(\"marginBottom\"));\r\n\r\n if (!width || !height) {\r\n width = maxWidth;\r\n height = maxHeight;\r\n }\r\n\r\n minRatio = Math.min(1, maxWidth / width, maxHeight / height);\r\n\r\n width = minRatio * width;\r\n height = minRatio * height;\r\n\r\n // Adjust width/height to precisely fit into container\r\n if (width > maxWidth - 0.5) {\r\n width = maxWidth;\r\n }\r\n\r\n if (height > maxHeight - 0.5) {\r\n height = maxHeight;\r\n }\r\n\r\n if (slide.type === \"image\") {\r\n rez.top = Math.floor((maxHeight - height) * 0.5) + parseFloat($slide.css(\"paddingTop\"));\r\n rez.left = Math.floor((maxWidth - width) * 0.5) + parseFloat($slide.css(\"paddingLeft\"));\r\n } else if (slide.contentType === \"video\") {\r\n // Force aspect ratio for the video\r\n // \"I say the whole world must learn of our peaceful ways… by force!\"\r\n aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9;\r\n\r\n if (height > width / aspectRatio) {\r\n height = width / aspectRatio;\r\n } else if (width > height * aspectRatio) {\r\n width = height * aspectRatio;\r\n }\r\n }\r\n\r\n rez.width = width;\r\n rez.height = height;\r\n\r\n return rez;\r\n },\r\n\r\n // Update content size and position for all slides\r\n // ==============================================\r\n\r\n update: function (e) {\r\n var self = this;\r\n\r\n $.each(self.slides, function (key, slide) {\r\n self.updateSlide(slide, e);\r\n });\r\n },\r\n\r\n // Update slide content position and size\r\n // ======================================\r\n\r\n updateSlide: function (slide, e) {\r\n var self = this,\r\n $content = slide && slide.$content,\r\n width = slide.width || slide.opts.width,\r\n height = slide.height || slide.opts.height,\r\n $slide = slide.$slide;\r\n\r\n // First, prevent caption overlap, if needed\r\n self.adjustCaption(slide);\r\n\r\n // Then resize content to fit inside the slide\r\n if ($content && (width || height || slide.contentType === \"video\") && !slide.hasError) {\r\n $.fancybox.stop($content);\r\n\r\n $.fancybox.setTranslate($content, self.getFitPos(slide));\r\n\r\n if (slide.pos === self.currPos) {\r\n self.isAnimating = false;\r\n\r\n self.updateCursor();\r\n }\r\n }\r\n\r\n // Then some adjustments\r\n self.adjustLayout(slide);\r\n\r\n if ($slide.length) {\r\n $slide.trigger(\"refresh\");\r\n\r\n if (slide.pos === self.currPos) {\r\n self.$refs.toolbar\r\n .add(self.$refs.navigation.find(\".fancybox-button--arrow_right\"))\r\n .toggleClass(\"compensate-for-scrollbar\", $slide.get(0).scrollHeight > $slide.get(0).clientHeight);\r\n }\r\n }\r\n\r\n self.trigger(\"onUpdate\", slide, e);\r\n },\r\n\r\n // Horizontally center slide\r\n // =========================\r\n\r\n centerSlide: function (duration) {\r\n var self = this,\r\n current = self.current,\r\n $slide = current.$slide;\r\n\r\n if (self.isClosing || !current) {\r\n return;\r\n }\r\n\r\n $slide.siblings().css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n $slide\r\n .parent()\r\n .children()\r\n .removeClass(\"fancybox-slide--previous fancybox-slide--next\");\r\n\r\n $.fancybox.animate(\r\n $slide, {\r\n top: 0,\r\n left: 0,\r\n opacity: 1\r\n },\r\n duration === undefined ? 0 : duration,\r\n function () {\r\n // Clean up\r\n $slide.css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n if (!current.isComplete) {\r\n self.complete();\r\n }\r\n },\r\n false\r\n );\r\n },\r\n\r\n // Check if current slide is moved (swiped)\r\n // ========================================\r\n\r\n isMoved: function (slide) {\r\n var current = slide || this.current,\r\n slidePos,\r\n stagePos;\r\n\r\n if (!current) {\r\n return false;\r\n }\r\n\r\n stagePos = $.fancybox.getTranslate(this.$refs.stage);\r\n slidePos = $.fancybox.getTranslate(current.$slide);\r\n\r\n return (\r\n !current.$slide.hasClass(\"fancybox-animated\") &&\r\n (Math.abs(slidePos.top - stagePos.top) > 0.5 || Math.abs(slidePos.left - stagePos.left) > 0.5)\r\n );\r\n },\r\n\r\n // Update cursor style depending if content can be zoomed\r\n // ======================================================\r\n\r\n updateCursor: function (nextWidth, nextHeight) {\r\n var self = this,\r\n current = self.current,\r\n $container = self.$refs.container,\r\n canPan,\r\n isZoomable;\r\n\r\n if (!current || self.isClosing || !self.Guestures) {\r\n return;\r\n }\r\n\r\n $container.removeClass(\"fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan\");\r\n\r\n canPan = self.canPan(nextWidth, nextHeight);\r\n\r\n isZoomable = canPan ? true : self.isZoomable();\r\n\r\n $container.toggleClass(\"fancybox-is-zoomable\", isZoomable);\r\n\r\n $(\"[data-fancybox-zoom]\").prop(\"disabled\", !isZoomable);\r\n\r\n if (canPan) {\r\n $container.addClass(\"fancybox-can-pan\");\r\n } else if (\r\n isZoomable &&\r\n (current.opts.clickContent === \"zoom\" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) == \"zoom\"))\r\n ) {\r\n $container.addClass(\"fancybox-can-zoomIn\");\r\n } else if (current.opts.touch && (current.opts.touch.vertical || self.group.length > 1) && current.contentType !== \"video\") {\r\n $container.addClass(\"fancybox-can-swipe\");\r\n }\r\n },\r\n\r\n // Check if current slide is zoomable\r\n // ==================================\r\n\r\n isZoomable: function () {\r\n var self = this,\r\n current = self.current,\r\n fitPos;\r\n\r\n // Assume that slide is zoomable if:\r\n // - image is still loading\r\n // - actual size of the image is smaller than available area\r\n if (current && !self.isClosing && current.type === \"image\" && !current.hasError) {\r\n if (!current.isLoaded) {\r\n return true;\r\n }\r\n\r\n fitPos = self.getFitPos(current);\r\n\r\n if (fitPos && (current.width > fitPos.width || current.height > fitPos.height)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n\r\n // Check if current image dimensions are smaller than actual\r\n // =========================================================\r\n\r\n isScaledDown: function (nextWidth, nextHeight) {\r\n var self = this,\r\n rez = false,\r\n current = self.current,\r\n $content = current.$content;\r\n\r\n if (nextWidth !== undefined && nextHeight !== undefined) {\r\n rez = nextWidth < current.width && nextHeight < current.height;\r\n } else if ($content) {\r\n rez = $.fancybox.getTranslate($content);\r\n rez = rez.width < current.width && rez.height < current.height;\r\n }\r\n\r\n return rez;\r\n },\r\n\r\n // Check if image dimensions exceed parent element\r\n // ===============================================\r\n\r\n canPan: function (nextWidth, nextHeight) {\r\n var self = this,\r\n current = self.current,\r\n pos = null,\r\n rez = false;\r\n\r\n if (current.type === \"image\" && (current.isComplete || (nextWidth && nextHeight)) && !current.hasError) {\r\n rez = self.getFitPos(current);\r\n\r\n if (nextWidth !== undefined && nextHeight !== undefined) {\r\n pos = {\r\n width: nextWidth,\r\n height: nextHeight\r\n };\r\n } else if (current.isComplete) {\r\n pos = $.fancybox.getTranslate(current.$content);\r\n }\r\n\r\n if (pos && rez) {\r\n rez = Math.abs(pos.width - rez.width) > 1.5 || Math.abs(pos.height - rez.height) > 1.5;\r\n }\r\n }\r\n\r\n return rez;\r\n },\r\n\r\n // Load content into the slide\r\n // ===========================\r\n\r\n loadSlide: function (slide) {\r\n var self = this,\r\n type,\r\n $slide,\r\n ajaxLoad;\r\n\r\n if (slide.isLoading || slide.isLoaded) {\r\n return;\r\n }\r\n\r\n slide.isLoading = true;\r\n\r\n if (self.trigger(\"beforeLoad\", slide) === false) {\r\n slide.isLoading = false;\r\n\r\n return false;\r\n }\r\n\r\n type = slide.type;\r\n $slide = slide.$slide;\r\n\r\n $slide\r\n .off(\"refresh\")\r\n .trigger(\"onReset\")\r\n .addClass(slide.opts.slideClass);\r\n\r\n // Create content depending on the type\r\n switch (type) {\r\n case \"image\":\r\n self.setImage(slide);\r\n\r\n break;\r\n\r\n case \"iframe\":\r\n self.setIframe(slide);\r\n\r\n break;\r\n\r\n case \"html\":\r\n self.setContent(slide, slide.src || slide.content);\r\n\r\n break;\r\n\r\n case \"video\":\r\n self.setContent(\r\n slide,\r\n slide.opts.video.tpl\r\n .replace(/\\{\\{src\\}\\}/gi, slide.src)\r\n .replace(\"{{format}}\", slide.opts.videoFormat || slide.opts.video.format || \"\")\r\n .replace(\"{{poster}}\", slide.thumb || \"\")\r\n );\r\n\r\n break;\r\n\r\n case \"inline\":\r\n if ($(slide.src).length) {\r\n self.setContent(slide, $(slide.src));\r\n } else {\r\n self.setError(slide);\r\n }\r\n\r\n break;\r\n\r\n case \"ajax\":\r\n self.showLoading(slide);\r\n\r\n ajaxLoad = $.ajax(\r\n $.extend({}, slide.opts.ajax.settings, {\r\n url: slide.src,\r\n success: function (data, textStatus) {\r\n if (textStatus === \"success\") {\r\n self.setContent(slide, data);\r\n }\r\n },\r\n error: function (jqXHR, textStatus) {\r\n if (jqXHR && textStatus !== \"abort\") {\r\n self.setError(slide);\r\n }\r\n }\r\n })\r\n );\r\n\r\n $slide.one(\"onReset\", function () {\r\n ajaxLoad.abort();\r\n });\r\n\r\n break;\r\n\r\n default:\r\n self.setError(slide);\r\n\r\n break;\r\n }\r\n\r\n return true;\r\n },\r\n\r\n // Use thumbnail image, if possible\r\n // ================================\r\n\r\n setImage: function (slide) {\r\n var self = this,\r\n ghost;\r\n\r\n // Check if need to show loading icon\r\n setTimeout(function () {\r\n var $img = slide.$image;\r\n\r\n if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) {\r\n self.showLoading(slide);\r\n }\r\n }, 50);\r\n\r\n //Check if image has srcset\r\n self.checkSrcset(slide);\r\n\r\n // This will be wrapper containing both ghost and actual image\r\n slide.$content = $('
')\r\n .addClass(\"fancybox-is-hidden\")\r\n .appendTo(slide.$slide.addClass(\"fancybox-slide--image\"));\r\n\r\n // If we have a thumbnail, we can display it while actual image is loading\r\n // Users will not stare at black screen and actual image will appear gradually\r\n if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && slide.thumb) {\r\n slide.width = slide.opts.width;\r\n slide.height = slide.opts.height;\r\n\r\n ghost = document.createElement(\"img\");\r\n\r\n ghost.onerror = function () {\r\n $(this).remove();\r\n\r\n slide.$ghost = null;\r\n };\r\n\r\n ghost.onload = function () {\r\n self.afterLoad(slide);\r\n };\r\n\r\n slide.$ghost = $(ghost)\r\n .addClass(\"fancybox-image\")\r\n .appendTo(slide.$content)\r\n .attr(\"src\", slide.thumb);\r\n }\r\n\r\n // Start loading actual image\r\n self.setBigImage(slide);\r\n },\r\n\r\n // Check if image has srcset and get the source\r\n // ============================================\r\n checkSrcset: function (slide) {\r\n var srcset = slide.opts.srcset || slide.opts.image.srcset,\r\n found,\r\n temp,\r\n pxRatio,\r\n windowWidth;\r\n\r\n // If we have \"srcset\", then we need to find first matching \"src\" value.\r\n // This is necessary, because when you set an src attribute, the browser will preload the image\r\n // before any javascript or even CSS is applied.\r\n if (srcset) {\r\n pxRatio = window.devicePixelRatio || 1;\r\n windowWidth = window.innerWidth * pxRatio;\r\n\r\n temp = srcset.split(\",\").map(function (el) {\r\n var ret = {};\r\n\r\n el.trim()\r\n .split(/\\s+/)\r\n .forEach(function (el, i) {\r\n var value = parseInt(el.substring(0, el.length - 1), 10);\r\n\r\n if (i === 0) {\r\n return (ret.url = el);\r\n }\r\n\r\n if (value) {\r\n ret.value = value;\r\n ret.postfix = el[el.length - 1];\r\n }\r\n });\r\n\r\n return ret;\r\n });\r\n\r\n // Sort by value\r\n temp.sort(function (a, b) {\r\n return a.value - b.value;\r\n });\r\n\r\n // Ok, now we have an array of all srcset values\r\n for (var j = 0; j < temp.length; j++) {\r\n var el = temp[j];\r\n\r\n if ((el.postfix === \"w\" && el.value >= windowWidth) || (el.postfix === \"x\" && el.value >= pxRatio)) {\r\n found = el;\r\n break;\r\n }\r\n }\r\n\r\n // If not found, take the last one\r\n if (!found && temp.length) {\r\n found = temp[temp.length - 1];\r\n }\r\n\r\n if (found) {\r\n slide.src = found.url;\r\n\r\n // If we have default width/height values, we can calculate height for matching source\r\n if (slide.width && slide.height && found.postfix == \"w\") {\r\n slide.height = (slide.width / slide.height) * found.value;\r\n slide.width = found.value;\r\n }\r\n\r\n slide.opts.srcset = srcset;\r\n }\r\n }\r\n },\r\n\r\n // Create full-size image\r\n // ======================\r\n\r\n setBigImage: function (slide) {\r\n var self = this,\r\n img = document.createElement(\"img\"),\r\n $img = $(img);\r\n\r\n slide.$image = $img\r\n .one(\"error\", function () {\r\n self.setError(slide);\r\n })\r\n .one(\"load\", function () {\r\n var sizes;\r\n\r\n if (!slide.$ghost) {\r\n self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight);\r\n\r\n self.afterLoad(slide);\r\n }\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n if (slide.opts.srcset) {\r\n sizes = slide.opts.sizes;\r\n\r\n if (!sizes || sizes === \"auto\") {\r\n sizes =\r\n (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? \"100\" : Math.round((slide.width / slide.height) * 100)) +\r\n \"vw\";\r\n }\r\n\r\n $img.attr(\"sizes\", sizes).attr(\"srcset\", slide.opts.srcset);\r\n }\r\n\r\n // Hide temporary image after some delay\r\n if (slide.$ghost) {\r\n setTimeout(function () {\r\n if (slide.$ghost && !self.isClosing) {\r\n slide.$ghost.hide();\r\n }\r\n }, Math.min(300, Math.max(1000, slide.height / 1600)));\r\n }\r\n\r\n self.hideLoading(slide);\r\n })\r\n .addClass(\"fancybox-image\")\r\n .attr(\"src\", slide.src)\r\n .appendTo(slide.$content);\r\n\r\n if ((img.complete || img.readyState == \"complete\") && $img.naturalWidth && $img.naturalHeight) {\r\n $img.trigger(\"load\");\r\n } else if (img.error) {\r\n $img.trigger(\"error\");\r\n }\r\n },\r\n\r\n // Computes the slide size from image size and maxWidth/maxHeight\r\n // ==============================================================\r\n\r\n resolveImageSlideSize: function (slide, imgWidth, imgHeight) {\r\n var maxWidth = parseInt(slide.opts.width, 10),\r\n maxHeight = parseInt(slide.opts.height, 10);\r\n\r\n // Sets the default values from the image\r\n slide.width = imgWidth;\r\n slide.height = imgHeight;\r\n\r\n if (maxWidth > 0) {\r\n slide.width = maxWidth;\r\n slide.height = Math.floor((maxWidth * imgHeight) / imgWidth);\r\n }\r\n\r\n if (maxHeight > 0) {\r\n slide.width = Math.floor((maxHeight * imgWidth) / imgHeight);\r\n slide.height = maxHeight;\r\n }\r\n },\r\n\r\n // Create iframe wrapper, iframe and bindings\r\n // ==========================================\r\n\r\n setIframe: function (slide) {\r\n var self = this,\r\n opts = slide.opts.iframe,\r\n $slide = slide.$slide,\r\n $iframe;\r\n\r\n slide.$content = $('
')\r\n .css(opts.css)\r\n .appendTo($slide);\r\n\r\n $slide.addClass(\"fancybox-slide--\" + slide.contentType);\r\n\r\n slide.$iframe = $iframe = $(opts.tpl.replace(/\\{rnd\\}/g, new Date().getTime()))\r\n .attr(opts.attr)\r\n .appendTo(slide.$content);\r\n\r\n if (opts.preload) {\r\n self.showLoading(slide);\r\n\r\n // Unfortunately, it is not always possible to determine if iframe is successfully loaded\r\n // (due to browser security policy)\r\n\r\n $iframe.on(\"load.fb error.fb\", function (e) {\r\n this.isReady = 1;\r\n\r\n slide.$slide.trigger(\"refresh\");\r\n\r\n self.afterLoad(slide);\r\n });\r\n\r\n // Recalculate iframe content size\r\n // ===============================\r\n\r\n $slide.on(\"refresh.fb\", function () {\r\n var $content = slide.$content,\r\n frameWidth = opts.css.width,\r\n frameHeight = opts.css.height,\r\n $contents,\r\n $body;\r\n\r\n if ($iframe[0].isReady !== 1) {\r\n return;\r\n }\r\n\r\n try {\r\n $contents = $iframe.contents();\r\n $body = $contents.find(\"body\");\r\n } catch (ignore) {}\r\n\r\n // Calculate content dimensions, if it is accessible\r\n if ($body && $body.length && $body.children().length) {\r\n // Avoid scrolling to top (if multiple instances)\r\n $slide.css(\"overflow\", \"visible\");\r\n\r\n $content.css({\r\n width: \"100%\",\r\n \"max-width\": \"100%\",\r\n height: \"9999px\"\r\n });\r\n\r\n if (frameWidth === undefined) {\r\n frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));\r\n }\r\n\r\n $content.css(\"width\", frameWidth ? frameWidth : \"\").css(\"max-width\", \"\");\r\n\r\n if (frameHeight === undefined) {\r\n frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));\r\n }\r\n\r\n $content.css(\"height\", frameHeight ? frameHeight : \"\");\r\n\r\n $slide.css(\"overflow\", \"auto\");\r\n }\r\n\r\n $content.removeClass(\"fancybox-is-hidden\");\r\n });\r\n } else {\r\n self.afterLoad(slide);\r\n }\r\n\r\n $iframe.attr(\"src\", slide.src);\r\n\r\n // Remove iframe if closing or changing gallery item\r\n $slide.one(\"onReset\", function () {\r\n // This helps IE not to throw errors when closing\r\n try {\r\n $(this)\r\n .find(\"iframe\")\r\n .hide()\r\n .unbind()\r\n .attr(\"src\", \"//about:blank\");\r\n } catch (ignore) {}\r\n\r\n $(this)\r\n .off(\"refresh.fb\")\r\n .empty();\r\n\r\n slide.isLoaded = false;\r\n slide.isRevealed = false;\r\n });\r\n },\r\n\r\n // Wrap and append content to the slide\r\n // ======================================\r\n\r\n setContent: function (slide, content) {\r\n var self = this;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n self.hideLoading(slide);\r\n\r\n if (slide.$content) {\r\n $.fancybox.stop(slide.$content);\r\n }\r\n\r\n slide.$slide.empty();\r\n\r\n // If content is a jQuery object, then it will be moved to the slide.\r\n // The placeholder is created so we will know where to put it back.\r\n if (isQuery(content) && content.parent().length) {\r\n // Make sure content is not already moved to fancyBox\r\n if (content.hasClass(\"fancybox-content\") || content.parent().hasClass(\"fancybox-content\")) {\r\n content.parents(\".fancybox-slide\").trigger(\"onReset\");\r\n }\r\n\r\n // Create temporary element marking original place of the content\r\n slide.$placeholder = $(\"
\")\r\n .hide()\r\n .insertAfter(content);\r\n\r\n // Make sure content is visible\r\n content.css(\"display\", \"inline-block\");\r\n } else if (!slide.hasError) {\r\n // If content is just a plain text, try to convert it to html\r\n if ($.type(content) === \"string\") {\r\n content = $(\"
\")\r\n .append($.trim(content))\r\n .contents();\r\n }\r\n\r\n // If \"filter\" option is provided, then filter content\r\n if (slide.opts.filter) {\r\n content = $(\"
\")\r\n .html(content)\r\n .find(slide.opts.filter);\r\n }\r\n }\r\n\r\n slide.$slide.one(\"onReset\", function () {\r\n // Pause all html5 video/audio\r\n $(this)\r\n .find(\"video,audio\")\r\n .trigger(\"pause\");\r\n\r\n // Put content back\r\n if (slide.$placeholder) {\r\n slide.$placeholder.after(content.removeClass(\"fancybox-content\").hide()).remove();\r\n\r\n slide.$placeholder = null;\r\n }\r\n\r\n // Remove custom close button\r\n if (slide.$smallBtn) {\r\n slide.$smallBtn.remove();\r\n\r\n slide.$smallBtn = null;\r\n }\r\n\r\n // Remove content and mark slide as not loaded\r\n if (!slide.hasError) {\r\n $(this).empty();\r\n\r\n slide.isLoaded = false;\r\n slide.isRevealed = false;\r\n }\r\n });\r\n\r\n $(content).appendTo(slide.$slide);\r\n\r\n if ($(content).is(\"video,audio\")) {\r\n $(content).addClass(\"fancybox-video\");\r\n\r\n $(content).wrap(\"
\");\r\n\r\n slide.contentType = \"video\";\r\n\r\n slide.opts.width = slide.opts.width || $(content).attr(\"width\");\r\n slide.opts.height = slide.opts.height || $(content).attr(\"height\");\r\n }\r\n\r\n slide.$content = slide.$slide\r\n .children()\r\n .filter(\"div,form,main,video,audio,article,.fancybox-content\")\r\n .first();\r\n\r\n slide.$content.siblings().hide();\r\n\r\n // Re-check if there is a valid content\r\n // (in some cases, ajax response can contain various elements or plain text)\r\n if (!slide.$content.length) {\r\n slide.$content = slide.$slide\r\n .wrapInner(\"
\")\r\n .children()\r\n .first();\r\n }\r\n\r\n slide.$content.addClass(\"fancybox-content\");\r\n\r\n slide.$slide.addClass(\"fancybox-slide--\" + slide.contentType);\r\n\r\n self.afterLoad(slide);\r\n },\r\n\r\n // Display error message\r\n // =====================\r\n\r\n setError: function (slide) {\r\n slide.hasError = true;\r\n\r\n slide.$slide\r\n .trigger(\"onReset\")\r\n .removeClass(\"fancybox-slide--\" + slide.contentType)\r\n .addClass(\"fancybox-slide--error\");\r\n\r\n slide.contentType = \"html\";\r\n\r\n this.setContent(slide, this.translate(slide, slide.opts.errorTpl));\r\n\r\n if (slide.pos === this.currPos) {\r\n this.isAnimating = false;\r\n }\r\n },\r\n\r\n // Show loading icon inside the slide\r\n // ==================================\r\n\r\n showLoading: function (slide) {\r\n var self = this;\r\n\r\n slide = slide || self.current;\r\n\r\n if (slide && !slide.$spinner) {\r\n slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))\r\n .appendTo(slide.$slide)\r\n .hide()\r\n .fadeIn(\"fast\");\r\n }\r\n },\r\n\r\n // Remove loading icon from the slide\r\n // ==================================\r\n\r\n hideLoading: function (slide) {\r\n var self = this;\r\n\r\n slide = slide || self.current;\r\n\r\n if (slide && slide.$spinner) {\r\n slide.$spinner.stop().remove();\r\n\r\n delete slide.$spinner;\r\n }\r\n },\r\n\r\n // Adjustments after slide content has been loaded\r\n // ===============================================\r\n\r\n afterLoad: function (slide) {\r\n var self = this;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n slide.isLoading = false;\r\n slide.isLoaded = true;\r\n\r\n self.trigger(\"afterLoad\", slide);\r\n\r\n self.hideLoading(slide);\r\n\r\n // Add small close button\r\n if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) {\r\n slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content);\r\n }\r\n\r\n // Disable right click\r\n if (slide.opts.protect && slide.$content && !slide.hasError) {\r\n slide.$content.on(\"contextmenu.fb\", function (e) {\r\n if (e.button == 2) {\r\n e.preventDefault();\r\n }\r\n\r\n return true;\r\n });\r\n\r\n // Add fake element on top of the image\r\n // This makes a bit harder for user to select image\r\n if (slide.type === \"image\") {\r\n $('
').appendTo(slide.$content);\r\n }\r\n }\r\n\r\n self.adjustCaption(slide);\r\n\r\n self.adjustLayout(slide);\r\n\r\n if (slide.pos === self.currPos) {\r\n self.updateCursor();\r\n }\r\n\r\n self.revealContent(slide);\r\n },\r\n\r\n // Prevent caption overlap,\r\n // fix css inconsistency across browsers\r\n // =====================================\r\n\r\n adjustCaption: function (slide) {\r\n var self = this,\r\n current = slide || self.current,\r\n caption = current.opts.caption,\r\n preventOverlap = current.opts.preventCaptionOverlap,\r\n $caption = self.$refs.caption,\r\n $clone,\r\n captionH = false;\r\n\r\n $caption.toggleClass(\"fancybox-caption--separate\", preventOverlap);\r\n\r\n if (preventOverlap && caption && caption.length) {\r\n if (current.pos !== self.currPos) {\r\n $clone = $caption.clone().appendTo($caption.parent());\r\n\r\n $clone\r\n .children()\r\n .eq(0)\r\n .empty()\r\n .html(caption);\r\n\r\n captionH = $clone.outerHeight(true);\r\n\r\n $clone.empty().remove();\r\n } else if (self.$caption) {\r\n captionH = self.$caption.outerHeight(true);\r\n }\r\n\r\n current.$slide.css(\"padding-bottom\", captionH || \"\");\r\n }\r\n },\r\n\r\n // Simple hack to fix inconsistency across browsers, described here (affects Edge, too):\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=748518\r\n // ====================================================================================\r\n\r\n adjustLayout: function (slide) {\r\n var self = this,\r\n current = slide || self.current,\r\n scrollHeight,\r\n marginBottom,\r\n inlinePadding,\r\n actualPadding;\r\n\r\n if (current.isLoaded && current.opts.disableLayoutFix !== true) {\r\n current.$content.css(\"margin-bottom\", \"\");\r\n\r\n // If we would always set margin-bottom for the content,\r\n // then it would potentially break vertical align\r\n if (current.$content.outerHeight() > current.$slide.height() + 0.5) {\r\n inlinePadding = current.$slide[0].style[\"padding-bottom\"];\r\n actualPadding = current.$slide.css(\"padding-bottom\");\r\n\r\n if (parseFloat(actualPadding) > 0) {\r\n scrollHeight = current.$slide[0].scrollHeight;\r\n\r\n current.$slide.css(\"padding-bottom\", 0);\r\n\r\n if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) {\r\n marginBottom = actualPadding;\r\n }\r\n\r\n current.$slide.css(\"padding-bottom\", inlinePadding);\r\n }\r\n }\r\n\r\n current.$content.css(\"margin-bottom\", marginBottom);\r\n }\r\n },\r\n\r\n // Make content visible\r\n // This method is called right after content has been loaded or\r\n // user navigates gallery and transition should start\r\n // ============================================================\r\n\r\n revealContent: function (slide) {\r\n var self = this,\r\n $slide = slide.$slide,\r\n end = false,\r\n start = false,\r\n isMoved = self.isMoved(slide),\r\n isRevealed = slide.isRevealed,\r\n effect,\r\n effectClassName,\r\n duration,\r\n opacity;\r\n\r\n slide.isRevealed = true;\r\n\r\n effect = slide.opts[self.firstRun ? \"animationEffect\" : \"transitionEffect\"];\r\n duration = slide.opts[self.firstRun ? \"animationDuration\" : \"transitionDuration\"];\r\n\r\n duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);\r\n\r\n if (isMoved || slide.pos !== self.currPos || !duration) {\r\n effect = false;\r\n }\r\n\r\n // Check if can zoom\r\n if (effect === \"zoom\") {\r\n if (slide.pos === self.currPos && duration && slide.type === \"image\" && !slide.hasError && (start = self.getThumbPos(slide))) {\r\n end = self.getFitPos(slide);\r\n } else {\r\n effect = \"fade\";\r\n }\r\n }\r\n\r\n // Zoom animation\r\n // ==============\r\n if (effect === \"zoom\") {\r\n self.isAnimating = true;\r\n\r\n end.scaleX = end.width / start.width;\r\n end.scaleY = end.height / start.height;\r\n\r\n // Check if we need to animate opacity\r\n opacity = slide.opts.zoomOpacity;\r\n\r\n if (opacity == \"auto\") {\r\n opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1;\r\n }\r\n\r\n if (opacity) {\r\n start.opacity = 0.1;\r\n end.opacity = 1;\r\n }\r\n\r\n // Draw image at start position\r\n $.fancybox.setTranslate(slide.$content.removeClass(\"fancybox-is-hidden\"), start);\r\n\r\n forceRedraw(slide.$content);\r\n\r\n // Start animation\r\n $.fancybox.animate(slide.$content, end, duration, function () {\r\n self.isAnimating = false;\r\n\r\n self.complete();\r\n });\r\n\r\n return;\r\n }\r\n\r\n self.updateSlide(slide);\r\n\r\n // Simply show content if no effect\r\n // ================================\r\n if (!effect) {\r\n slide.$content.removeClass(\"fancybox-is-hidden\");\r\n\r\n if (!isRevealed && isMoved && slide.type === \"image\" && !slide.hasError) {\r\n slide.$content.hide().fadeIn(\"fast\");\r\n }\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Prepare for CSS transiton\r\n // =========================\r\n $.fancybox.stop($slide);\r\n\r\n //effectClassName = \"fancybox-animated fancybox-slide--\" + (slide.pos >= self.prevPos ? \"next\" : \"previous\") + \" fancybox-fx-\" + effect;\r\n effectClassName = \"fancybox-slide--\" + (slide.pos >= self.prevPos ? \"next\" : \"previous\") + \" fancybox-animated fancybox-fx-\" + effect;\r\n\r\n $slide.addClass(effectClassName).removeClass(\"fancybox-slide--current\"); //.addClass(effectClassName);\r\n\r\n slide.$content.removeClass(\"fancybox-is-hidden\");\r\n\r\n // Force reflow\r\n forceRedraw($slide);\r\n\r\n if (slide.type !== \"image\") {\r\n slide.$content.hide().show(0);\r\n }\r\n\r\n $.fancybox.animate(\r\n $slide,\r\n \"fancybox-slide--current\",\r\n duration,\r\n function () {\r\n $slide.removeClass(effectClassName).css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n },\r\n true\r\n );\r\n },\r\n\r\n // Check if we can and have to zoom from thumbnail\r\n //================================================\r\n\r\n getThumbPos: function (slide) {\r\n var rez = false,\r\n $thumb = slide.$thumb,\r\n thumbPos,\r\n btw,\r\n brw,\r\n bbw,\r\n blw;\r\n\r\n if (!$thumb || !inViewport($thumb[0])) {\r\n return false;\r\n }\r\n\r\n thumbPos = $.fancybox.getTranslate($thumb);\r\n\r\n btw = parseFloat($thumb.css(\"border-top-width\") || 0);\r\n brw = parseFloat($thumb.css(\"border-right-width\") || 0);\r\n bbw = parseFloat($thumb.css(\"border-bottom-width\") || 0);\r\n blw = parseFloat($thumb.css(\"border-left-width\") || 0);\r\n\r\n rez = {\r\n top: thumbPos.top + btw,\r\n left: thumbPos.left + blw,\r\n width: thumbPos.width - brw - blw,\r\n height: thumbPos.height - btw - bbw,\r\n scaleX: 1,\r\n scaleY: 1\r\n };\r\n\r\n return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false;\r\n },\r\n\r\n // Final adjustments after current gallery item is moved to position\r\n // and it`s content is loaded\r\n // ==================================================================\r\n\r\n complete: function () {\r\n var self = this,\r\n current = self.current,\r\n slides = {},\r\n $el;\r\n\r\n if (self.isMoved() || !current.isLoaded) {\r\n return;\r\n }\r\n\r\n if (!current.isComplete) {\r\n current.isComplete = true;\r\n\r\n current.$slide.siblings().trigger(\"onReset\");\r\n\r\n self.preload(\"inline\");\r\n\r\n // Trigger any CSS transiton inside the slide\r\n forceRedraw(current.$slide);\r\n\r\n current.$slide.addClass(\"fancybox-slide--complete\");\r\n\r\n // Remove unnecessary slides\r\n $.each(self.slides, function (key, slide) {\r\n if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {\r\n slides[slide.pos] = slide;\r\n } else if (slide) {\r\n $.fancybox.stop(slide.$slide);\r\n\r\n slide.$slide.off().remove();\r\n }\r\n });\r\n\r\n self.slides = slides;\r\n }\r\n\r\n self.isAnimating = false;\r\n\r\n self.updateCursor();\r\n\r\n self.trigger(\"afterShow\");\r\n\r\n // Autoplay first html5 video/audio\r\n if (!!current.opts.video.autoStart) {\r\n current.$slide\r\n .find(\"video,audio\")\r\n .filter(\":visible:first\")\r\n .trigger(\"play\")\r\n .one(\"ended\", function () {\r\n if (Document.exitFullscreen) {\r\n Document.exitFullscreen();\r\n } else if (this.webkitExitFullscreen) {\r\n this.webkitExitFullscreen();\r\n }\r\n\r\n self.next();\r\n });\r\n }\r\n\r\n // Try to focus on the first focusable element\r\n if (current.opts.autoFocus && current.contentType === \"html\") {\r\n // Look for the first input with autofocus attribute\r\n $el = current.$content.find(\"input[autofocus]:enabled:visible:first\");\r\n\r\n if ($el.length) {\r\n $el.trigger(\"focus\");\r\n } else {\r\n self.focus(null, true);\r\n }\r\n }\r\n\r\n // Avoid jumping\r\n current.$slide.scrollTop(0).scrollLeft(0);\r\n },\r\n\r\n // Preload next and previous slides\r\n // ================================\r\n\r\n preload: function (type) {\r\n var self = this,\r\n prev,\r\n next;\r\n\r\n if (self.group.length < 2) {\r\n return;\r\n }\r\n\r\n next = self.slides[self.currPos + 1];\r\n prev = self.slides[self.currPos - 1];\r\n\r\n if (prev && prev.type === type) {\r\n self.loadSlide(prev);\r\n }\r\n\r\n if (next && next.type === type) {\r\n self.loadSlide(next);\r\n }\r\n },\r\n\r\n // Try to find and focus on the first focusable element\r\n // ====================================================\r\n\r\n focus: function (e, firstRun) {\r\n var self = this,\r\n focusableStr = [\r\n \"a[href]\",\r\n \"area[href]\",\r\n 'input:not([disabled]):not([type=\"hidden\"]):not([aria-hidden])',\r\n \"select:not([disabled]):not([aria-hidden])\",\r\n \"textarea:not([disabled]):not([aria-hidden])\",\r\n \"button:not([disabled]):not([aria-hidden])\",\r\n \"iframe\",\r\n \"object\",\r\n \"embed\",\r\n \"video\",\r\n \"audio\",\r\n \"[contenteditable]\",\r\n '[tabindex]:not([tabindex^=\"-\"])'\r\n ].join(\",\"),\r\n focusableItems,\r\n focusedItemIndex;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n if (e || !self.current || !self.current.isComplete) {\r\n // Focus on any element inside fancybox\r\n focusableItems = self.$refs.container.find(\"*:visible\");\r\n } else {\r\n // Focus inside current slide\r\n focusableItems = self.current.$slide.find(\"*:visible\" + (firstRun ? \":not(.fancybox-close-small)\" : \"\"));\r\n }\r\n\r\n focusableItems = focusableItems.filter(focusableStr).filter(function () {\r\n return $(this).css(\"visibility\") !== \"hidden\" && !$(this).hasClass(\"disabled\");\r\n });\r\n\r\n if (focusableItems.length) {\r\n focusedItemIndex = focusableItems.index(document.activeElement);\r\n\r\n if (e && e.shiftKey) {\r\n // Back tab\r\n if (focusedItemIndex < 0 || focusedItemIndex == 0) {\r\n e.preventDefault();\r\n\r\n focusableItems.eq(focusableItems.length - 1).trigger(\"focus\");\r\n }\r\n } else {\r\n // Outside or Forward tab\r\n if (focusedItemIndex < 0 || focusedItemIndex == focusableItems.length - 1) {\r\n if (e) {\r\n e.preventDefault();\r\n }\r\n\r\n focusableItems.eq(0).trigger(\"focus\");\r\n }\r\n }\r\n } else {\r\n self.$refs.container.trigger(\"focus\");\r\n }\r\n },\r\n\r\n // Activates current instance - brings container to the front and enables keyboard,\r\n // notifies other instances about deactivating\r\n // =================================================================================\r\n\r\n activate: function () {\r\n var self = this;\r\n\r\n // Deactivate all instances\r\n $(\".fancybox-container\").each(function () {\r\n var instance = $(this).data(\"FancyBox\");\r\n\r\n // Skip self and closing instances\r\n if (instance && instance.id !== self.id && !instance.isClosing) {\r\n instance.trigger(\"onDeactivate\");\r\n\r\n instance.removeEvents();\r\n\r\n instance.isVisible = false;\r\n }\r\n });\r\n\r\n self.isVisible = true;\r\n\r\n if (self.current || self.isIdle) {\r\n self.update();\r\n\r\n self.updateControls();\r\n }\r\n\r\n self.trigger(\"onActivate\");\r\n\r\n self.addEvents();\r\n },\r\n\r\n // Start closing procedure\r\n // This will start \"zoom-out\" animation if needed and clean everything up afterwards\r\n // =================================================================================\r\n\r\n close: function (e, d) {\r\n var self = this,\r\n current = self.current,\r\n effect,\r\n duration,\r\n $content,\r\n domRect,\r\n opacity,\r\n start,\r\n end;\r\n\r\n var done = function () {\r\n self.cleanUp(e);\r\n };\r\n\r\n if (self.isClosing) {\r\n return false;\r\n }\r\n\r\n self.isClosing = true;\r\n\r\n // If beforeClose callback prevents closing, make sure content is centered\r\n if (self.trigger(\"beforeClose\", e) === false) {\r\n self.isClosing = false;\r\n\r\n requestAFrame(function () {\r\n self.update();\r\n });\r\n\r\n return false;\r\n }\r\n\r\n // Remove all events\r\n // If there are multiple instances, they will be set again by \"activate\" method\r\n self.removeEvents();\r\n\r\n $content = current.$content;\r\n effect = current.opts.animationEffect;\r\n duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;\r\n\r\n current.$slide.removeClass(\"fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated\");\r\n\r\n if (e !== true) {\r\n $.fancybox.stop(current.$slide);\r\n } else {\r\n effect = false;\r\n }\r\n\r\n // Remove other slides\r\n current.$slide\r\n .siblings()\r\n .trigger(\"onReset\")\r\n .remove();\r\n\r\n // Trigger animations\r\n if (duration) {\r\n self.$refs.container\r\n .removeClass(\"fancybox-is-open\")\r\n .addClass(\"fancybox-is-closing\")\r\n .css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n // Clean up\r\n self.hideLoading(current);\r\n\r\n self.hideControls(true);\r\n\r\n self.updateCursor();\r\n\r\n // Check if possible to zoom-out\r\n if (\r\n effect === \"zoom\" &&\r\n !($content && duration && current.type === \"image\" && !self.isMoved() && !current.hasError && (end = self.getThumbPos(current)))\r\n ) {\r\n effect = \"fade\";\r\n }\r\n\r\n if (effect === \"zoom\") {\r\n $.fancybox.stop($content);\r\n\r\n domRect = $.fancybox.getTranslate($content);\r\n\r\n start = {\r\n top: domRect.top,\r\n left: domRect.left,\r\n scaleX: domRect.width / end.width,\r\n scaleY: domRect.height / end.height,\r\n width: end.width,\r\n height: end.height\r\n };\r\n\r\n // Check if we need to animate opacity\r\n opacity = current.opts.zoomOpacity;\r\n\r\n if (opacity == \"auto\") {\r\n opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1;\r\n }\r\n\r\n if (opacity) {\r\n end.opacity = 0;\r\n }\r\n\r\n $.fancybox.setTranslate($content, start);\r\n\r\n forceRedraw($content);\r\n\r\n $.fancybox.animate($content, end, duration, done);\r\n\r\n return true;\r\n }\r\n\r\n if (effect && duration) {\r\n $.fancybox.animate(\r\n current.$slide.addClass(\"fancybox-slide--previous\").removeClass(\"fancybox-slide--current\"),\r\n \"fancybox-animated fancybox-fx-\" + effect,\r\n duration,\r\n done\r\n );\r\n } else {\r\n // If skip animation\r\n if (e === true) {\r\n setTimeout(done, duration);\r\n } else {\r\n done();\r\n }\r\n }\r\n\r\n return true;\r\n },\r\n\r\n // Final adjustments after removing the instance\r\n // =============================================\r\n\r\n cleanUp: function (e) {\r\n var self = this,\r\n instance,\r\n $focus = self.current.opts.$orig,\r\n x,\r\n y;\r\n\r\n self.current.$slide.trigger(\"onReset\");\r\n\r\n self.$refs.container.empty().remove();\r\n\r\n self.trigger(\"afterClose\", e);\r\n\r\n // Place back focus\r\n if (!!self.current.opts.backFocus) {\r\n if (!$focus || !$focus.length || !$focus.is(\":visible\")) {\r\n $focus = self.$trigger;\r\n }\r\n\r\n if ($focus && $focus.length) {\r\n x = window.scrollX;\r\n y = window.scrollY;\r\n\r\n $focus.trigger(\"focus\");\r\n\r\n $(\"html, body\")\r\n .scrollTop(y)\r\n .scrollLeft(x);\r\n }\r\n }\r\n\r\n self.current = null;\r\n\r\n // Check if there are other instances\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n instance.activate();\r\n } else {\r\n $(\"body\").removeClass(\"fancybox-active compensate-for-scrollbar\");\r\n\r\n $(\"#fancybox-style-noscroll\").remove();\r\n }\r\n },\r\n\r\n // Call callback and trigger an event\r\n // ==================================\r\n\r\n trigger: function (name, slide) {\r\n var args = Array.prototype.slice.call(arguments, 1),\r\n self = this,\r\n obj = slide && slide.opts ? slide : self.current,\r\n rez;\r\n\r\n if (obj) {\r\n args.unshift(obj);\r\n } else {\r\n obj = self;\r\n }\r\n\r\n args.unshift(self);\r\n\r\n if ($.isFunction(obj.opts[name])) {\r\n rez = obj.opts[name].apply(obj, args);\r\n }\r\n\r\n if (rez === false) {\r\n return rez;\r\n }\r\n\r\n if (name === \"afterClose\" || !self.$refs) {\r\n $D.trigger(name + \".fb\", args);\r\n } else {\r\n self.$refs.container.trigger(name + \".fb\", args);\r\n }\r\n },\r\n\r\n // Update infobar values, navigation button states and reveal caption\r\n // ==================================================================\r\n\r\n updateControls: function () {\r\n var self = this,\r\n current = self.current,\r\n index = current.index,\r\n $container = self.$refs.container,\r\n $caption = self.$refs.caption,\r\n caption = current.opts.caption;\r\n\r\n // Recalculate content dimensions\r\n current.$slide.trigger(\"refresh\");\r\n\r\n // Set caption\r\n if (caption && caption.length) {\r\n self.$caption = $caption;\r\n\r\n $caption\r\n .children()\r\n .eq(0)\r\n .html(caption);\r\n } else {\r\n self.$caption = null;\r\n }\r\n\r\n if (!self.hasHiddenControls && !self.isIdle) {\r\n self.showControls();\r\n }\r\n\r\n // Update info and navigation elements\r\n $container.find(\"[data-fancybox-count]\").html(self.group.length);\r\n $container.find(\"[data-fancybox-index]\").html(index + 1);\r\n\r\n $container.find(\"[data-fancybox-prev]\").prop(\"disabled\", !current.opts.loop && index <= 0);\r\n $container.find(\"[data-fancybox-next]\").prop(\"disabled\", !current.opts.loop && index >= self.group.length - 1);\r\n\r\n if (current.type === \"image\") {\r\n // Re-enable buttons; update download button source\r\n $container\r\n .find(\"[data-fancybox-zoom]\")\r\n .show()\r\n .end()\r\n .find(\"[data-fancybox-download]\")\r\n .attr(\"href\", current.opts.image.src || current.src)\r\n .show();\r\n } else if (current.opts.toolbar) {\r\n $container.find(\"[data-fancybox-download],[data-fancybox-zoom]\").hide();\r\n }\r\n\r\n // Make sure focus is not on disabled button/element\r\n if ($(document.activeElement).is(\":hidden,[disabled]\")) {\r\n self.$refs.container.trigger(\"focus\");\r\n }\r\n },\r\n\r\n // Hide toolbar and caption\r\n // ========================\r\n\r\n hideControls: function (andCaption) {\r\n var self = this,\r\n arr = [\"infobar\", \"toolbar\", \"nav\"];\r\n\r\n if (andCaption || !self.current.opts.preventCaptionOverlap) {\r\n arr.push(\"caption\");\r\n }\r\n\r\n this.$refs.container.removeClass(\r\n arr\r\n .map(function (i) {\r\n return \"fancybox-show-\" + i;\r\n })\r\n .join(\" \")\r\n );\r\n\r\n this.hasHiddenControls = true;\r\n },\r\n\r\n showControls: function () {\r\n var self = this,\r\n opts = self.current ? self.current.opts : self.opts,\r\n $container = self.$refs.container;\r\n\r\n self.hasHiddenControls = false;\r\n self.idleSecondsCounter = 0;\r\n\r\n $container\r\n .toggleClass(\"fancybox-show-toolbar\", !!(opts.toolbar && opts.buttons))\r\n .toggleClass(\"fancybox-show-infobar\", !!(opts.infobar && self.group.length > 1))\r\n .toggleClass(\"fancybox-show-caption\", !!self.$caption)\r\n .toggleClass(\"fancybox-show-nav\", !!(opts.arrows && self.group.length > 1))\r\n .toggleClass(\"fancybox-is-modal\", !!opts.modal);\r\n },\r\n\r\n // Toggle toolbar and caption\r\n // ==========================\r\n\r\n toggleControls: function () {\r\n if (this.hasHiddenControls) {\r\n this.showControls();\r\n } else {\r\n this.hideControls();\r\n }\r\n }\r\n });\r\n\r\n $.fancybox = {\r\n version: \"3.5.7\",\r\n defaults: defaults,\r\n\r\n // Get current instance and execute a command.\r\n //\r\n // Examples of usage:\r\n //\r\n // $instance = $.fancybox.getInstance();\r\n // $.fancybox.getInstance().jumpTo( 1 );\r\n // $.fancybox.getInstance( 'jumpTo', 1 );\r\n // $.fancybox.getInstance( function() {\r\n // console.info( this.currIndex );\r\n // });\r\n // ======================================================\r\n\r\n getInstance: function (command) {\r\n var instance = $('.fancybox-container:not(\".fancybox-is-closing\"):last').data(\"FancyBox\"),\r\n args = Array.prototype.slice.call(arguments, 1);\r\n\r\n if (instance instanceof FancyBox) {\r\n if ($.type(command) === \"string\") {\r\n instance[command].apply(instance, args);\r\n } else if ($.type(command) === \"function\") {\r\n command.apply(instance, args);\r\n }\r\n\r\n return instance;\r\n }\r\n\r\n return false;\r\n },\r\n\r\n // Create new instance\r\n // ===================\r\n\r\n open: function (items, opts, index) {\r\n return new FancyBox(items, opts, index);\r\n },\r\n\r\n // Close current or all instances\r\n // ==============================\r\n\r\n close: function (all) {\r\n var instance = this.getInstance();\r\n\r\n if (instance) {\r\n instance.close();\r\n\r\n // Try to find and close next instance\r\n if (all === true) {\r\n this.close(all);\r\n }\r\n }\r\n },\r\n\r\n // Close all instances and unbind all events\r\n // =========================================\r\n\r\n destroy: function () {\r\n this.close(true);\r\n\r\n $D.add(\"body\").off(\"click.fb-start\", \"**\");\r\n },\r\n\r\n // Try to detect mobile devices\r\n // ============================\r\n\r\n isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),\r\n\r\n // Detect if 'translate3d' support is available\r\n // ============================================\r\n\r\n use3d: (function () {\r\n var div = document.createElement(\"div\");\r\n\r\n return (\r\n window.getComputedStyle &&\r\n window.getComputedStyle(div) &&\r\n window.getComputedStyle(div).getPropertyValue(\"transform\") &&\r\n !(document.documentMode && document.documentMode < 11)\r\n );\r\n })(),\r\n\r\n // Helper function to get current visual state of an element\r\n // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]\r\n // =====================================================================\r\n\r\n getTranslate: function ($el) {\r\n var domRect;\r\n\r\n if (!$el || !$el.length) {\r\n return false;\r\n }\r\n\r\n domRect = $el[0].getBoundingClientRect();\r\n\r\n return {\r\n top: domRect.top || 0,\r\n left: domRect.left || 0,\r\n width: domRect.width,\r\n height: domRect.height,\r\n opacity: parseFloat($el.css(\"opacity\"))\r\n };\r\n },\r\n\r\n // Shortcut for setting \"translate3d\" properties for element\r\n // Can set be used to set opacity, too\r\n // ========================================================\r\n\r\n setTranslate: function ($el, props) {\r\n var str = \"\",\r\n css = {};\r\n\r\n if (!$el || !props) {\r\n return;\r\n }\r\n\r\n if (props.left !== undefined || props.top !== undefined) {\r\n str =\r\n (props.left === undefined ? $el.position().left : props.left) +\r\n \"px, \" +\r\n (props.top === undefined ? $el.position().top : props.top) +\r\n \"px\";\r\n\r\n if (this.use3d) {\r\n str = \"translate3d(\" + str + \", 0px)\";\r\n } else {\r\n str = \"translate(\" + str + \")\";\r\n }\r\n }\r\n\r\n if (props.scaleX !== undefined && props.scaleY !== undefined) {\r\n str += \" scale(\" + props.scaleX + \", \" + props.scaleY + \")\";\r\n } else if (props.scaleX !== undefined) {\r\n str += \" scaleX(\" + props.scaleX + \")\";\r\n }\r\n\r\n if (str.length) {\r\n css.transform = str;\r\n }\r\n\r\n if (props.opacity !== undefined) {\r\n css.opacity = props.opacity;\r\n }\r\n\r\n if (props.width !== undefined) {\r\n css.width = props.width;\r\n }\r\n\r\n if (props.height !== undefined) {\r\n css.height = props.height;\r\n }\r\n\r\n return $el.css(css);\r\n },\r\n\r\n // Simple CSS transition handler\r\n // =============================\r\n\r\n animate: function ($el, to, duration, callback, leaveAnimationName) {\r\n var self = this,\r\n from;\r\n\r\n if ($.isFunction(duration)) {\r\n callback = duration;\r\n duration = null;\r\n }\r\n\r\n self.stop($el);\r\n\r\n from = self.getTranslate($el);\r\n\r\n $el.on(transitionEnd, function (e) {\r\n // Skip events from child elements and z-index change\r\n if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == \"z-index\")) {\r\n return;\r\n }\r\n\r\n self.stop($el);\r\n\r\n if ($.isNumeric(duration)) {\r\n $el.css(\"transition-duration\", \"\");\r\n }\r\n\r\n if ($.isPlainObject(to)) {\r\n if (to.scaleX !== undefined && to.scaleY !== undefined) {\r\n self.setTranslate($el, {\r\n top: to.top,\r\n left: to.left,\r\n width: from.width * to.scaleX,\r\n height: from.height * to.scaleY,\r\n scaleX: 1,\r\n scaleY: 1\r\n });\r\n }\r\n } else if (leaveAnimationName !== true) {\r\n $el.removeClass(to);\r\n }\r\n\r\n if ($.isFunction(callback)) {\r\n callback(e);\r\n }\r\n });\r\n\r\n if ($.isNumeric(duration)) {\r\n $el.css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n // Start animation by changing CSS properties or class name\r\n if ($.isPlainObject(to)) {\r\n if (to.scaleX !== undefined && to.scaleY !== undefined) {\r\n delete to.width;\r\n delete to.height;\r\n\r\n if ($el.parent().hasClass(\"fancybox-slide--image\")) {\r\n $el.parent().addClass(\"fancybox-is-scaling\");\r\n }\r\n }\r\n\r\n $.fancybox.setTranslate($el, to);\r\n } else {\r\n $el.addClass(to);\r\n }\r\n\r\n // Make sure that `transitionend` callback gets fired\r\n $el.data(\r\n \"timer\",\r\n setTimeout(function () {\r\n $el.trigger(transitionEnd);\r\n }, duration + 33)\r\n );\r\n },\r\n\r\n stop: function ($el, callCallback) {\r\n if ($el && $el.length) {\r\n clearTimeout($el.data(\"timer\"));\r\n\r\n if (callCallback) {\r\n $el.trigger(transitionEnd);\r\n }\r\n\r\n $el.off(transitionEnd).css(\"transition-duration\", \"\");\r\n\r\n $el.parent().removeClass(\"fancybox-is-scaling\");\r\n }\r\n }\r\n };\r\n\r\n // Default click handler for \"fancyboxed\" links\r\n // ============================================\r\n\r\n function _run(e, opts) {\r\n var items = [],\r\n index = 0,\r\n $target,\r\n value,\r\n instance;\r\n\r\n // Avoid opening multiple times\r\n if (e && e.isDefaultPrevented()) {\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n\r\n opts = opts || {};\r\n\r\n if (e && e.data) {\r\n opts = mergeOpts(e.data.options, opts);\r\n }\r\n\r\n $target = opts.$target || $(e.currentTarget).trigger(\"blur\");\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance && instance.$trigger && instance.$trigger.is($target)) {\r\n return;\r\n }\r\n\r\n if (opts.selector) {\r\n items = $(opts.selector);\r\n } else {\r\n // Get all related items and find index for clicked one\r\n value = $target.attr(\"data-fancybox\") || \"\";\r\n\r\n if (value) {\r\n items = e.data ? e.data.items : [];\r\n items = items.length ? items.filter('[data-fancybox=\"' + value + '\"]') : $('[data-fancybox=\"' + value + '\"]');\r\n } else {\r\n items = [$target];\r\n }\r\n }\r\n\r\n index = $(items).index($target);\r\n\r\n // Sometimes current item can not be found\r\n if (index < 0) {\r\n index = 0;\r\n }\r\n\r\n instance = $.fancybox.open(items, opts, index);\r\n\r\n // Save last active element\r\n instance.$trigger = $target;\r\n }\r\n\r\n // Create a jQuery plugin\r\n // ======================\r\n\r\n $.fn.fancybox = function (options) {\r\n var selector;\r\n\r\n options = options || {};\r\n selector = options.selector || false;\r\n\r\n if (selector) {\r\n // Use body element instead of document so it executes first\r\n $(\"body\")\r\n .off(\"click.fb-start\", selector)\r\n .on(\"click.fb-start\", selector, {\r\n options: options\r\n }, _run);\r\n } else {\r\n this.off(\"click.fb-start\").on(\r\n \"click.fb-start\", {\r\n items: this,\r\n options: options\r\n },\r\n _run\r\n );\r\n }\r\n\r\n return this;\r\n };\r\n\r\n // Self initializing plugin for all elements having `data-fancybox` attribute\r\n // ==========================================================================\r\n\r\n $D.on(\"click.fb-start\", \"[data-fancybox]\", _run);\r\n\r\n // Enable \"trigger elements\"\r\n // =========================\r\n\r\n $D.on(\"click.fb-start\", \"[data-fancybox-trigger]\", function (e) {\r\n $('[data-fancybox=\"' + $(this).attr(\"data-fancybox-trigger\") + '\"]')\r\n .eq($(this).attr(\"data-fancybox-index\") || 0)\r\n .trigger(\"click.fb-start\", {\r\n $trigger: $(this)\r\n });\r\n });\r\n\r\n // Track focus event for better accessibility styling\r\n // ==================================================\r\n (function () {\r\n var buttonStr = \".fancybox-button\",\r\n focusStr = \"fancybox-focus\",\r\n $pressed = null;\r\n\r\n $D.on(\"mousedown mouseup focus blur\", buttonStr, function (e) {\r\n switch (e.type) {\r\n case \"mousedown\":\r\n $pressed = $(this);\r\n break;\r\n case \"mouseup\":\r\n $pressed = null;\r\n break;\r\n case \"focusin\":\r\n $(buttonStr).removeClass(focusStr);\r\n\r\n if (!$(this).is($pressed) && !$(this).is(\"[disabled]\")) {\r\n $(this).addClass(focusStr);\r\n }\r\n break;\r\n case \"focusout\":\r\n $(buttonStr).removeClass(focusStr);\r\n break;\r\n }\r\n });\r\n })();\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// Media\r\n// Adds additional media type support\r\n//\r\n// ==========================================================================\r\n(function ($) {\r\n \"use strict\";\r\n\r\n // Object containing properties for each media type\r\n var defaults = {\r\n youtube: {\r\n matcher: /(youtube\\.com|youtu\\.be|youtube\\-nocookie\\.com)\\/(watch\\?(.*&)?v=|v\\/|u\\/|embed\\/?)?(videoseries\\?list=(.*)|[\\w-]{11}|\\?listType=(.*)&list=(.*))(.*)/i,\r\n params: {\r\n autoplay: 1,\r\n autohide: 1,\r\n fs: 1,\r\n rel: 0,\r\n hd: 1,\r\n wmode: \"transparent\",\r\n enablejsapi: 1,\r\n html5: 1\r\n },\r\n paramPlace: 8,\r\n type: \"iframe\",\r\n url: \"https://www.youtube-nocookie.com/embed/$4\",\r\n thumb: \"https://img.youtube.com/vi/$4/hqdefault.jpg\"\r\n },\r\n\r\n vimeo: {\r\n matcher: /^.+vimeo.com\\/(.*\\/)?([\\d]+)(.*)?/,\r\n params: {\r\n autoplay: 1,\r\n hd: 1,\r\n show_title: 1,\r\n show_byline: 1,\r\n show_portrait: 0,\r\n fullscreen: 1\r\n },\r\n paramPlace: 3,\r\n type: \"iframe\",\r\n url: \"//player.vimeo.com/video/$2\"\r\n },\r\n\r\n instagram: {\r\n matcher: /(instagr\\.am|instagram\\.com)\\/p\\/([a-zA-Z0-9_\\-]+)\\/?/i,\r\n type: \"image\",\r\n url: \"//$1/p/$2/media/?size=l\"\r\n },\r\n\r\n // Examples:\r\n // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16\r\n // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z\r\n // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en\r\n // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572\r\n gmap_place: {\r\n matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(((maps\\/(place\\/(.*)\\/)?\\@(.*),(\\d+.?\\d+?)z))|(\\?ll=))(.*)?/i,\r\n type: \"iframe\",\r\n url: function (rez) {\r\n return (\r\n \"//maps.google.\" +\r\n rez[2] +\r\n \"/?ll=\" +\r\n (rez[9] ? rez[9] + \"&z=\" + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\\//, \"&\") : \"\") : rez[12] + \"\").replace(/\\?/, \"&\") +\r\n \"&output=\" +\r\n (rez[12] && rez[12].indexOf(\"layer=c\") > 0 ? \"svembed\" : \"embed\")\r\n );\r\n }\r\n },\r\n\r\n // Examples:\r\n // https://www.google.com/maps/search/Empire+State+Building/\r\n // https://www.google.com/maps/search/?api=1&query=centurylink+field\r\n // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393\r\n gmap_search: {\r\n matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(maps\\/search\\/)(.*)/i,\r\n type: \"iframe\",\r\n url: function (rez) {\r\n return \"//maps.google.\" + rez[2] + \"/maps?q=\" + rez[5].replace(\"query=\", \"q=\").replace(\"api=1\", \"\") + \"&output=embed\";\r\n }\r\n }\r\n };\r\n\r\n // Formats matching url to final form\r\n var format = function (url, rez, params) {\r\n if (!url) {\r\n return;\r\n }\r\n\r\n params = params || \"\";\r\n\r\n if ($.type(params) === \"object\") {\r\n params = $.param(params, true);\r\n }\r\n\r\n $.each(rez, function (key, value) {\r\n url = url.replace(\"$\" + key, value || \"\");\r\n });\r\n\r\n if (params.length) {\r\n url += (url.indexOf(\"?\") > 0 ? \"&\" : \"?\") + params;\r\n }\r\n\r\n return url;\r\n };\r\n\r\n $(document).on(\"objectNeedsType.fb\", function (e, instance, item) {\r\n var url = item.src || \"\",\r\n type = false,\r\n media,\r\n thumb,\r\n rez,\r\n params,\r\n urlParams,\r\n paramObj,\r\n provider;\r\n\r\n media = $.extend(true, {}, defaults, item.opts.media);\r\n\r\n // Look for any matching media type\r\n $.each(media, function (providerName, providerOpts) {\r\n rez = url.match(providerOpts.matcher);\r\n\r\n if (!rez) {\r\n return;\r\n }\r\n\r\n type = providerOpts.type;\r\n provider = providerName;\r\n paramObj = {};\r\n\r\n if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {\r\n urlParams = rez[providerOpts.paramPlace];\r\n\r\n if (urlParams[0] == \"?\") {\r\n urlParams = urlParams.substring(1);\r\n }\r\n\r\n urlParams = urlParams.split(\"&\");\r\n\r\n for (var m = 0; m < urlParams.length; ++m) {\r\n var p = urlParams[m].split(\"=\", 2);\r\n\r\n if (p.length == 2) {\r\n paramObj[p[0]] = decodeURIComponent(p[1].replace(/\\+/g, \" \"));\r\n }\r\n }\r\n }\r\n\r\n params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj);\r\n\r\n url =\r\n $.type(providerOpts.url) === \"function\" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params);\r\n\r\n thumb =\r\n $.type(providerOpts.thumb) === \"function\" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez);\r\n\r\n if (providerName === \"youtube\") {\r\n url = url.replace(/&t=((\\d+)m)?(\\d+)s/, function (match, p1, m, s) {\r\n return \"&start=\" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10));\r\n });\r\n } else if (providerName === \"vimeo\") {\r\n url = url.replace(\"&%23\", \"#\");\r\n }\r\n\r\n return false;\r\n });\r\n\r\n // If it is found, then change content type and update the url\r\n\r\n if (type) {\r\n if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {\r\n item.opts.thumb = thumb;\r\n }\r\n\r\n if (type === \"iframe\") {\r\n item.opts = $.extend(true, item.opts, {\r\n iframe: {\r\n preload: false,\r\n attr: {\r\n scrolling: \"no\"\r\n }\r\n }\r\n });\r\n }\r\n\r\n $.extend(item, {\r\n type: type,\r\n src: url,\r\n origSrc: item.src,\r\n contentSource: provider,\r\n contentType: type === \"image\" ? \"image\" : provider == \"gmap_place\" || provider == \"gmap_search\" ? \"map\" : \"video\"\r\n });\r\n } else if (url) {\r\n item.type = item.opts.defaultType;\r\n }\r\n });\r\n\r\n // Load YouTube/Video API on request to detect when video finished playing\r\n var VideoAPILoader = {\r\n youtube: {\r\n src: \"https://www.youtube.com/iframe_api\",\r\n class: \"YT\",\r\n loading: false,\r\n loaded: false\r\n },\r\n\r\n vimeo: {\r\n src: \"https://player.vimeo.com/api/player.js\",\r\n class: \"Vimeo\",\r\n loading: false,\r\n loaded: false\r\n },\r\n\r\n load: function (vendor) {\r\n var _this = this,\r\n script;\r\n\r\n if (this[vendor].loaded) {\r\n setTimeout(function () {\r\n _this.done(vendor);\r\n });\r\n return;\r\n }\r\n\r\n if (this[vendor].loading) {\r\n return;\r\n }\r\n\r\n this[vendor].loading = true;\r\n\r\n script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = this[vendor].src;\r\n\r\n if (vendor === \"youtube\") {\r\n window.onYouTubeIframeAPIReady = function () {\r\n _this[vendor].loaded = true;\r\n _this.done(vendor);\r\n };\r\n } else {\r\n script.onload = function () {\r\n _this[vendor].loaded = true;\r\n _this.done(vendor);\r\n };\r\n }\r\n\r\n document.body.appendChild(script);\r\n },\r\n done: function (vendor) {\r\n var instance, $el, player;\r\n\r\n if (vendor === \"youtube\") {\r\n delete window.onYouTubeIframeAPIReady;\r\n }\r\n\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n $el = instance.current.$content.find(\"iframe\");\r\n\r\n if (vendor === \"youtube\" && YT !== undefined && YT) {\r\n player = new YT.Player($el.attr(\"id\"), {\r\n events: {\r\n onStateChange: function (e) {\r\n if (e.data == 0) {\r\n instance.next();\r\n }\r\n }\r\n }\r\n });\r\n } else if (vendor === \"vimeo\" && Vimeo !== undefined && Vimeo) {\r\n player = new Vimeo.Player($el);\r\n\r\n player.on(\"ended\", function () {\r\n instance.next();\r\n });\r\n }\r\n }\r\n }\r\n };\r\n\r\n $(document).on({\r\n \"afterShow.fb\": function (e, instance, current) {\r\n if (instance.group.length > 1 && (current.contentSource === \"youtube\" || current.contentSource === \"vimeo\")) {\r\n VideoAPILoader.load(current.contentSource);\r\n }\r\n }\r\n });\r\n})(jQuery);\n// ==========================================================================\r\n//\r\n// Guestures\r\n// Adds touch guestures, handles click and tap events\r\n//\r\n// ==========================================================================\r\n(function (window, document, $) {\r\n \"use strict\";\r\n\r\n var requestAFrame = (function () {\r\n return (\r\n window.requestAnimationFrame ||\r\n window.webkitRequestAnimationFrame ||\r\n window.mozRequestAnimationFrame ||\r\n window.oRequestAnimationFrame ||\r\n // if all else fails, use setTimeout\r\n function (callback) {\r\n return window.setTimeout(callback, 1000 / 60);\r\n }\r\n );\r\n })();\r\n\r\n var cancelAFrame = (function () {\r\n return (\r\n window.cancelAnimationFrame ||\r\n window.webkitCancelAnimationFrame ||\r\n window.mozCancelAnimationFrame ||\r\n window.oCancelAnimationFrame ||\r\n function (id) {\r\n window.clearTimeout(id);\r\n }\r\n );\r\n })();\r\n\r\n var getPointerXY = function (e) {\r\n var result = [];\r\n\r\n e = e.originalEvent || e || window.e;\r\n e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];\r\n\r\n for (var key in e) {\r\n if (e[key].pageX) {\r\n result.push({\r\n x: e[key].pageX,\r\n y: e[key].pageY\r\n });\r\n } else if (e[key].clientX) {\r\n result.push({\r\n x: e[key].clientX,\r\n y: e[key].clientY\r\n });\r\n }\r\n }\r\n\r\n return result;\r\n };\r\n\r\n var distance = function (point2, point1, what) {\r\n if (!point1 || !point2) {\r\n return 0;\r\n }\r\n\r\n if (what === \"x\") {\r\n return point2.x - point1.x;\r\n } else if (what === \"y\") {\r\n return point2.y - point1.y;\r\n }\r\n\r\n return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));\r\n };\r\n\r\n var isClickable = function ($el) {\r\n if (\r\n $el.is('a,area,button,[role=\"button\"],input,label,select,summary,textarea,video,audio,iframe') ||\r\n $.isFunction($el.get(0).onclick) ||\r\n $el.data(\"selectable\")\r\n ) {\r\n return true;\r\n }\r\n\r\n // Check for attributes like data-fancybox-next or data-fancybox-close\r\n for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {\r\n if (atts[i].nodeName.substr(0, 14) === \"data-fancybox-\") {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n };\r\n\r\n var hasScrollbars = function (el) {\r\n var overflowY = window.getComputedStyle(el)[\"overflow-y\"],\r\n overflowX = window.getComputedStyle(el)[\"overflow-x\"],\r\n vertical = (overflowY === \"scroll\" || overflowY === \"auto\") && el.scrollHeight > el.clientHeight,\r\n horizontal = (overflowX === \"scroll\" || overflowX === \"auto\") && el.scrollWidth > el.clientWidth;\r\n\r\n return vertical || horizontal;\r\n };\r\n\r\n var isScrollable = function ($el) {\r\n var rez = false;\r\n\r\n while (true) {\r\n rez = hasScrollbars($el.get(0));\r\n\r\n if (rez) {\r\n break;\r\n }\r\n\r\n $el = $el.parent();\r\n\r\n if (!$el.length || $el.hasClass(\"fancybox-stage\") || $el.is(\"body\")) {\r\n break;\r\n }\r\n }\r\n\r\n return rez;\r\n };\r\n\r\n var Guestures = function (instance) {\r\n var self = this;\r\n\r\n self.instance = instance;\r\n\r\n self.$bg = instance.$refs.bg;\r\n self.$stage = instance.$refs.stage;\r\n self.$container = instance.$refs.container;\r\n\r\n self.destroy();\r\n\r\n self.$container.on(\"touchstart.fb.touch mousedown.fb.touch\", $.proxy(self, \"ontouchstart\"));\r\n };\r\n\r\n Guestures.prototype.destroy = function () {\r\n var self = this;\r\n\r\n self.$container.off(\".fb.touch\");\r\n\r\n $(document).off(\".fb.touch\");\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n self.requestId = null;\r\n }\r\n\r\n if (self.tapped) {\r\n clearTimeout(self.tapped);\r\n self.tapped = null;\r\n }\r\n };\r\n\r\n Guestures.prototype.ontouchstart = function (e) {\r\n var self = this,\r\n $target = $(e.target),\r\n instance = self.instance,\r\n current = instance.current,\r\n $slide = current.$slide,\r\n $content = current.$content,\r\n isTouchDevice = e.type == \"touchstart\";\r\n\r\n // Do not respond to both (touch and mouse) events\r\n if (isTouchDevice) {\r\n self.$container.off(\"mousedown.fb.touch\");\r\n }\r\n\r\n // Ignore right click\r\n if (e.originalEvent && e.originalEvent.button == 2) {\r\n return;\r\n }\r\n\r\n // Ignore taping on links, buttons, input elements\r\n if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) {\r\n return;\r\n }\r\n // Ignore clicks on the scrollbar\r\n if (!$target.is(\"img\") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {\r\n return;\r\n }\r\n\r\n // Ignore clicks while zooming or closing\r\n if (!current || instance.isAnimating || current.$slide.hasClass(\"fancybox-animated\")) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n return;\r\n }\r\n\r\n self.realPoints = self.startPoints = getPointerXY(e);\r\n\r\n if (!self.startPoints.length) {\r\n return;\r\n }\r\n\r\n // Allow other scripts to catch touch event if \"touch\" is set to false\r\n if (current.touch) {\r\n e.stopPropagation();\r\n }\r\n\r\n self.startEvent = e;\r\n\r\n self.canTap = true;\r\n self.$target = $target;\r\n self.$content = $content;\r\n self.opts = current.opts.touch;\r\n\r\n self.isPanning = false;\r\n self.isSwiping = false;\r\n self.isZooming = false;\r\n self.isScrolling = false;\r\n self.canPan = instance.canPan();\r\n\r\n self.startTime = new Date().getTime();\r\n self.distanceX = self.distanceY = self.distance = 0;\r\n\r\n self.canvasWidth = Math.round($slide[0].clientWidth);\r\n self.canvasHeight = Math.round($slide[0].clientHeight);\r\n\r\n self.contentLastPos = null;\r\n self.contentStartPos = $.fancybox.getTranslate(self.$content) || {\r\n top: 0,\r\n left: 0\r\n };\r\n self.sliderStartPos = $.fancybox.getTranslate($slide);\r\n\r\n // Since position will be absolute, but we need to make it relative to the stage\r\n self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);\r\n\r\n self.sliderStartPos.top -= self.stagePos.top;\r\n self.sliderStartPos.left -= self.stagePos.left;\r\n\r\n self.contentStartPos.top -= self.stagePos.top;\r\n self.contentStartPos.left -= self.stagePos.left;\r\n\r\n $(document)\r\n .off(\".fb.touch\")\r\n .on(isTouchDevice ? \"touchend.fb.touch touchcancel.fb.touch\" : \"mouseup.fb.touch mouseleave.fb.touch\", $.proxy(self, \"ontouchend\"))\r\n .on(isTouchDevice ? \"touchmove.fb.touch\" : \"mousemove.fb.touch\", $.proxy(self, \"ontouchmove\"));\r\n\r\n if ($.fancybox.isMobile) {\r\n document.addEventListener(\"scroll\", self.onscroll, true);\r\n }\r\n\r\n // Skip if clicked outside the sliding area\r\n if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) {\r\n if ($target.is(\".fancybox-image\")) {\r\n e.preventDefault();\r\n }\r\n\r\n if (!($.fancybox.isMobile && $target.parents(\".fancybox-caption\").length)) {\r\n return;\r\n }\r\n }\r\n\r\n self.isScrollable = isScrollable($target) || isScrollable($target.parent());\r\n\r\n // Check if element is scrollable and try to prevent default behavior (scrolling)\r\n if (!($.fancybox.isMobile && self.isScrollable)) {\r\n e.preventDefault();\r\n }\r\n\r\n // One finger or mouse click - swipe or pan an image\r\n if (self.startPoints.length === 1 || current.hasError) {\r\n if (self.canPan) {\r\n $.fancybox.stop(self.$content);\r\n\r\n self.isPanning = true;\r\n } else {\r\n self.isSwiping = true;\r\n }\r\n\r\n self.$container.addClass(\"fancybox-is-grabbing\");\r\n }\r\n\r\n // Two fingers - zoom image\r\n if (self.startPoints.length === 2 && current.type === \"image\" && (current.isLoaded || current.$ghost)) {\r\n self.canTap = false;\r\n self.isSwiping = false;\r\n self.isPanning = false;\r\n\r\n self.isZooming = true;\r\n\r\n $.fancybox.stop(self.$content);\r\n\r\n self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();\r\n self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();\r\n\r\n self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;\r\n self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;\r\n\r\n self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);\r\n }\r\n };\r\n\r\n Guestures.prototype.onscroll = function (e) {\r\n var self = this;\r\n\r\n self.isScrolling = true;\r\n\r\n document.removeEventListener(\"scroll\", self.onscroll, true);\r\n };\r\n\r\n Guestures.prototype.ontouchmove = function (e) {\r\n var self = this;\r\n\r\n // Make sure user has not released over iframe or disabled element\r\n if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {\r\n self.ontouchend(e);\r\n return;\r\n }\r\n\r\n if (self.isScrolling) {\r\n self.canTap = false;\r\n return;\r\n }\r\n\r\n self.newPoints = getPointerXY(e);\r\n\r\n if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) {\r\n return;\r\n }\r\n\r\n if (!(self.isSwiping && self.isSwiping === true)) {\r\n e.preventDefault();\r\n }\r\n\r\n self.distanceX = distance(self.newPoints[0], self.startPoints[0], \"x\");\r\n self.distanceY = distance(self.newPoints[0], self.startPoints[0], \"y\");\r\n\r\n self.distance = distance(self.newPoints[0], self.startPoints[0]);\r\n\r\n // Skip false ontouchmove events (Chrome)\r\n if (self.distance > 0) {\r\n if (self.isSwiping) {\r\n self.onSwipe(e);\r\n } else if (self.isPanning) {\r\n self.onPan();\r\n } else if (self.isZooming) {\r\n self.onZoom();\r\n }\r\n }\r\n };\r\n\r\n Guestures.prototype.onSwipe = function (e) {\r\n var self = this,\r\n instance = self.instance,\r\n swiping = self.isSwiping,\r\n left = self.sliderStartPos.left || 0,\r\n angle;\r\n\r\n // If direction is not yet determined\r\n if (swiping === true) {\r\n // We need at least 10px distance to correctly calculate an angle\r\n if (Math.abs(self.distance) > 10) {\r\n self.canTap = false;\r\n\r\n if (instance.group.length < 2 && self.opts.vertical) {\r\n self.isSwiping = \"y\";\r\n } else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === \"auto\" && $(window).width() > 800)) {\r\n self.isSwiping = \"x\";\r\n } else {\r\n angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI);\r\n\r\n self.isSwiping = angle > 45 && angle < 135 ? \"y\" : \"x\";\r\n }\r\n\r\n if (self.isSwiping === \"y\" && $.fancybox.isMobile && self.isScrollable) {\r\n self.isScrolling = true;\r\n\r\n return;\r\n }\r\n\r\n instance.isDragging = self.isSwiping;\r\n\r\n // Reset points to avoid jumping, because we dropped first swipes to calculate the angle\r\n self.startPoints = self.newPoints;\r\n\r\n $.each(instance.slides, function (index, slide) {\r\n var slidePos, stagePos;\r\n\r\n $.fancybox.stop(slide.$slide);\r\n\r\n slidePos = $.fancybox.getTranslate(slide.$slide);\r\n stagePos = $.fancybox.getTranslate(instance.$refs.stage);\r\n\r\n slide.$slide\r\n .css({\r\n transform: \"\",\r\n opacity: \"\",\r\n \"transition-duration\": \"\"\r\n })\r\n .removeClass(\"fancybox-animated\")\r\n .removeClass(function (index, className) {\r\n return (className.match(/(^|\\s)fancybox-fx-\\S+/g) || []).join(\" \");\r\n });\r\n\r\n if (slide.pos === instance.current.pos) {\r\n self.sliderStartPos.top = slidePos.top - stagePos.top;\r\n self.sliderStartPos.left = slidePos.left - stagePos.left;\r\n }\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: slidePos.top - stagePos.top,\r\n left: slidePos.left - stagePos.left\r\n });\r\n });\r\n\r\n // Stop slideshow\r\n if (instance.SlideShow && instance.SlideShow.isActive) {\r\n instance.SlideShow.stop();\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Sticky edges\r\n if (swiping == \"x\") {\r\n if (\r\n self.distanceX > 0 &&\r\n (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))\r\n ) {\r\n left = left + Math.pow(self.distanceX, 0.8);\r\n } else if (\r\n self.distanceX < 0 &&\r\n (self.instance.group.length < 2 ||\r\n (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))\r\n ) {\r\n left = left - Math.pow(-self.distanceX, 0.8);\r\n } else {\r\n left = left + self.distanceX;\r\n }\r\n }\r\n\r\n self.sliderLastPos = {\r\n top: swiping == \"x\" ? 0 : self.sliderStartPos.top + self.distanceY,\r\n left: left\r\n };\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n\r\n self.requestId = null;\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n if (self.sliderLastPos) {\r\n $.each(self.instance.slides, function (index, slide) {\r\n var pos = slide.pos - self.instance.currPos;\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: self.sliderLastPos.top,\r\n left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter\r\n });\r\n });\r\n\r\n self.$container.addClass(\"fancybox-is-sliding\");\r\n }\r\n });\r\n };\r\n\r\n Guestures.prototype.onPan = function () {\r\n var self = this;\r\n\r\n // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)\r\n if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {\r\n self.startPoints = self.newPoints;\r\n return;\r\n }\r\n\r\n self.canTap = false;\r\n\r\n self.contentLastPos = self.limitMovement();\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n $.fancybox.setTranslate(self.$content, self.contentLastPos);\r\n });\r\n };\r\n\r\n // Make panning sticky to the edges\r\n Guestures.prototype.limitMovement = function () {\r\n var self = this;\r\n\r\n var canvasWidth = self.canvasWidth;\r\n var canvasHeight = self.canvasHeight;\r\n\r\n var distanceX = self.distanceX;\r\n var distanceY = self.distanceY;\r\n\r\n var contentStartPos = self.contentStartPos;\r\n\r\n var currentOffsetX = contentStartPos.left;\r\n var currentOffsetY = contentStartPos.top;\r\n\r\n var currentWidth = contentStartPos.width;\r\n var currentHeight = contentStartPos.height;\r\n\r\n var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;\r\n\r\n if (currentWidth > canvasWidth) {\r\n newOffsetX = currentOffsetX + distanceX;\r\n } else {\r\n newOffsetX = currentOffsetX;\r\n }\r\n\r\n newOffsetY = currentOffsetY + distanceY;\r\n\r\n // Slow down proportionally to traveled distance\r\n minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);\r\n minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);\r\n\r\n maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);\r\n maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);\r\n\r\n // ->\r\n if (distanceX > 0 && newOffsetX > minTranslateX) {\r\n newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;\r\n }\r\n\r\n // <-\r\n if (distanceX < 0 && newOffsetX < maxTranslateX) {\r\n newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;\r\n }\r\n\r\n // \\/\r\n if (distanceY > 0 && newOffsetY > minTranslateY) {\r\n newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;\r\n }\r\n\r\n // /\\\r\n if (distanceY < 0 && newOffsetY < maxTranslateY) {\r\n newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;\r\n }\r\n\r\n return {\r\n top: newOffsetY,\r\n left: newOffsetX\r\n };\r\n };\r\n\r\n Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) {\r\n var self = this;\r\n\r\n var canvasWidth = self.canvasWidth;\r\n var canvasHeight = self.canvasHeight;\r\n\r\n if (newWidth > canvasWidth) {\r\n newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;\r\n newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;\r\n } else {\r\n // Center horizontally\r\n newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);\r\n }\r\n\r\n if (newHeight > canvasHeight) {\r\n newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;\r\n newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;\r\n } else {\r\n // Center vertically\r\n newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);\r\n }\r\n\r\n return {\r\n top: newOffsetY,\r\n left: newOffsetX\r\n };\r\n };\r\n\r\n Guestures.prototype.onZoom = function () {\r\n var self = this;\r\n\r\n // Calculate current distance between points to get pinch ratio and new width and height\r\n var contentStartPos = self.contentStartPos;\r\n\r\n var currentWidth = contentStartPos.width;\r\n var currentHeight = contentStartPos.height;\r\n\r\n var currentOffsetX = contentStartPos.left;\r\n var currentOffsetY = contentStartPos.top;\r\n\r\n var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);\r\n\r\n var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;\r\n\r\n var newWidth = Math.floor(currentWidth * pinchRatio);\r\n var newHeight = Math.floor(currentHeight * pinchRatio);\r\n\r\n // This is the translation due to pinch-zooming\r\n var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;\r\n var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;\r\n\r\n // Point between the two touches\r\n var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();\r\n var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();\r\n\r\n // And this is the translation due to translation of the centerpoint\r\n // between the two fingers\r\n var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;\r\n var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;\r\n\r\n // The new offset is the old/current one plus the total translation\r\n var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);\r\n var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);\r\n\r\n var newPos = {\r\n top: newOffsetY,\r\n left: newOffsetX,\r\n scaleX: pinchRatio,\r\n scaleY: pinchRatio\r\n };\r\n\r\n self.canTap = false;\r\n\r\n self.newWidth = newWidth;\r\n self.newHeight = newHeight;\r\n\r\n self.contentLastPos = newPos;\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n $.fancybox.setTranslate(self.$content, self.contentLastPos);\r\n });\r\n };\r\n\r\n Guestures.prototype.ontouchend = function (e) {\r\n var self = this;\r\n\r\n var swiping = self.isSwiping;\r\n var panning = self.isPanning;\r\n var zooming = self.isZooming;\r\n var scrolling = self.isScrolling;\r\n\r\n self.endPoints = getPointerXY(e);\r\n self.dMs = Math.max(new Date().getTime() - self.startTime, 1);\r\n\r\n self.$container.removeClass(\"fancybox-is-grabbing\");\r\n\r\n $(document).off(\".fb.touch\");\r\n\r\n document.removeEventListener(\"scroll\", self.onscroll, true);\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n\r\n self.requestId = null;\r\n }\r\n\r\n self.isSwiping = false;\r\n self.isPanning = false;\r\n self.isZooming = false;\r\n self.isScrolling = false;\r\n\r\n self.instance.isDragging = false;\r\n\r\n if (self.canTap) {\r\n return self.onTap(e);\r\n }\r\n\r\n self.speed = 100;\r\n\r\n // Speed in px/ms\r\n self.velocityX = (self.distanceX / self.dMs) * 0.5;\r\n self.velocityY = (self.distanceY / self.dMs) * 0.5;\r\n\r\n if (panning) {\r\n self.endPanning();\r\n } else if (zooming) {\r\n self.endZooming();\r\n } else {\r\n self.endSwiping(swiping, scrolling);\r\n }\r\n\r\n return;\r\n };\r\n\r\n Guestures.prototype.endSwiping = function (swiping, scrolling) {\r\n var self = this,\r\n ret = false,\r\n len = self.instance.group.length,\r\n distanceX = Math.abs(self.distanceX),\r\n canAdvance = swiping == \"x\" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50),\r\n speedX = 300;\r\n\r\n self.sliderLastPos = null;\r\n\r\n // Close if swiped vertically / navigate if horizontally\r\n if (swiping == \"y\" && !scrolling && Math.abs(self.distanceY) > 50) {\r\n // Continue vertical movement\r\n $.fancybox.animate(\r\n self.instance.current.$slide, {\r\n top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,\r\n opacity: 0\r\n },\r\n 200\r\n );\r\n ret = self.instance.close(true, 250);\r\n } else if (canAdvance && self.distanceX > 0) {\r\n ret = self.instance.previous(speedX);\r\n } else if (canAdvance && self.distanceX < 0) {\r\n ret = self.instance.next(speedX);\r\n }\r\n\r\n if (ret === false && (swiping == \"x\" || swiping == \"y\")) {\r\n self.instance.centerSlide(200);\r\n }\r\n\r\n self.$container.removeClass(\"fancybox-is-sliding\");\r\n };\r\n\r\n // Limit panning from edges\r\n // ========================\r\n Guestures.prototype.endPanning = function () {\r\n var self = this,\r\n newOffsetX,\r\n newOffsetY,\r\n newPos;\r\n\r\n if (!self.contentLastPos) {\r\n return;\r\n }\r\n\r\n if (self.opts.momentum === false || self.dMs > 350) {\r\n newOffsetX = self.contentLastPos.left;\r\n newOffsetY = self.contentLastPos.top;\r\n } else {\r\n // Continue movement\r\n newOffsetX = self.contentLastPos.left + self.velocityX * 500;\r\n newOffsetY = self.contentLastPos.top + self.velocityY * 500;\r\n }\r\n\r\n newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);\r\n\r\n newPos.width = self.contentStartPos.width;\r\n newPos.height = self.contentStartPos.height;\r\n\r\n $.fancybox.animate(self.$content, newPos, 366);\r\n };\r\n\r\n Guestures.prototype.endZooming = function () {\r\n var self = this;\r\n\r\n var current = self.instance.current;\r\n\r\n var newOffsetX, newOffsetY, newPos, reset;\r\n\r\n var newWidth = self.newWidth;\r\n var newHeight = self.newHeight;\r\n\r\n if (!self.contentLastPos) {\r\n return;\r\n }\r\n\r\n newOffsetX = self.contentLastPos.left;\r\n newOffsetY = self.contentLastPos.top;\r\n\r\n reset = {\r\n top: newOffsetY,\r\n left: newOffsetX,\r\n width: newWidth,\r\n height: newHeight,\r\n scaleX: 1,\r\n scaleY: 1\r\n };\r\n\r\n // Reset scalex/scaleY values; this helps for perfomance and does not break animation\r\n $.fancybox.setTranslate(self.$content, reset);\r\n\r\n if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {\r\n self.instance.scaleToFit(150);\r\n } else if (newWidth > current.width || newHeight > current.height) {\r\n self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);\r\n } else {\r\n newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);\r\n\r\n $.fancybox.animate(self.$content, newPos, 150);\r\n }\r\n };\r\n\r\n Guestures.prototype.onTap = function (e) {\r\n var self = this;\r\n var $target = $(e.target);\r\n\r\n var instance = self.instance;\r\n var current = instance.current;\r\n\r\n var endPoints = (e && getPointerXY(e)) || self.startPoints;\r\n\r\n var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;\r\n var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;\r\n\r\n var where;\r\n\r\n var process = function (prefix) {\r\n var action = current.opts[prefix];\r\n\r\n if ($.isFunction(action)) {\r\n action = action.apply(instance, [current, e]);\r\n }\r\n\r\n if (!action) {\r\n return;\r\n }\r\n\r\n switch (action) {\r\n case \"close\":\r\n instance.close(self.startEvent);\r\n\r\n break;\r\n\r\n case \"toggleControls\":\r\n instance.toggleControls();\r\n\r\n break;\r\n\r\n case \"next\":\r\n instance.next();\r\n\r\n break;\r\n\r\n case \"nextOrClose\":\r\n if (instance.group.length > 1) {\r\n instance.next();\r\n } else {\r\n instance.close(self.startEvent);\r\n }\r\n\r\n break;\r\n\r\n case \"zoom\":\r\n if (current.type == \"image\" && (current.isLoaded || current.$ghost)) {\r\n if (instance.canPan()) {\r\n instance.scaleToFit();\r\n } else if (instance.isScaledDown()) {\r\n instance.scaleToActual(tapX, tapY);\r\n } else if (instance.group.length < 2) {\r\n instance.close(self.startEvent);\r\n }\r\n }\r\n\r\n break;\r\n }\r\n };\r\n\r\n // Ignore right click\r\n if (e.originalEvent && e.originalEvent.button == 2) {\r\n return;\r\n }\r\n\r\n // Skip if clicked on the scrollbar\r\n if (!$target.is(\"img\") && tapX > $target[0].clientWidth + $target.offset().left) {\r\n return;\r\n }\r\n\r\n // Check where is clicked\r\n if ($target.is(\".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container\")) {\r\n where = \"Outside\";\r\n } else if ($target.is(\".fancybox-slide\")) {\r\n where = \"Slide\";\r\n } else if (\r\n instance.current.$content &&\r\n instance.current.$content\r\n .find($target)\r\n .addBack()\r\n .filter($target).length\r\n ) {\r\n where = \"Content\";\r\n } else {\r\n return;\r\n }\r\n\r\n // Check if this is a double tap\r\n if (self.tapped) {\r\n // Stop previously created single tap\r\n clearTimeout(self.tapped);\r\n self.tapped = null;\r\n\r\n // Skip if distance between taps is too big\r\n if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {\r\n return this;\r\n }\r\n\r\n // OK, now we assume that this is a double-tap\r\n process(\"dblclick\" + where);\r\n } else {\r\n // Single tap will be processed if user has not clicked second time within 300ms\r\n // or there is no need to wait for double-tap\r\n self.tapX = tapX;\r\n self.tapY = tapY;\r\n\r\n if (current.opts[\"dblclick\" + where] && current.opts[\"dblclick\" + where] !== current.opts[\"click\" + where]) {\r\n self.tapped = setTimeout(function () {\r\n self.tapped = null;\r\n\r\n if (!instance.isAnimating) {\r\n process(\"click\" + where);\r\n }\r\n }, 500);\r\n } else {\r\n process(\"click\" + where);\r\n }\r\n }\r\n\r\n return this;\r\n };\r\n\r\n $(document)\r\n .on(\"onActivate.fb\", function (e, instance) {\r\n if (instance && !instance.Guestures) {\r\n instance.Guestures = new Guestures(instance);\r\n }\r\n })\r\n .on(\"beforeClose.fb\", function (e, instance) {\r\n if (instance && instance.Guestures) {\r\n instance.Guestures.destroy();\r\n }\r\n });\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// SlideShow\r\n// Enables slideshow functionality\r\n//\r\n// Example of usage:\r\n// $.fancybox.getInstance().SlideShow.start()\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n slideShow: '\"\r\n },\r\n slideShow: {\r\n autoStart: false,\r\n speed: 3000,\r\n progress: true\r\n }\r\n });\r\n\r\n var SlideShow = function (instance) {\r\n this.instance = instance;\r\n this.init();\r\n };\r\n\r\n $.extend(SlideShow.prototype, {\r\n timer: null,\r\n isActive: false,\r\n $button: null,\r\n\r\n init: function () {\r\n var self = this,\r\n instance = self.instance,\r\n opts = instance.group[instance.currIndex].opts.slideShow;\r\n\r\n self.$button = instance.$refs.toolbar.find(\"[data-fancybox-play]\").on(\"click\", function () {\r\n self.toggle();\r\n });\r\n\r\n if (instance.group.length < 2 || !opts) {\r\n self.$button.hide();\r\n } else if (opts.progress) {\r\n self.$progress = $('
').appendTo(instance.$refs.inner);\r\n }\r\n },\r\n\r\n set: function (force) {\r\n var self = this,\r\n instance = self.instance,\r\n current = instance.current;\r\n\r\n // Check if reached last element\r\n if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) {\r\n if (self.isActive && current.contentType !== \"video\") {\r\n if (self.$progress) {\r\n $.fancybox.animate(self.$progress.show(), {\r\n scaleX: 1\r\n }, current.opts.slideShow.speed);\r\n }\r\n\r\n self.timer = setTimeout(function () {\r\n if (!instance.current.opts.loop && instance.current.index == instance.group.length - 1) {\r\n instance.jumpTo(0);\r\n } else {\r\n instance.next();\r\n }\r\n }, current.opts.slideShow.speed);\r\n }\r\n } else {\r\n self.stop();\r\n instance.idleSecondsCounter = 0;\r\n instance.showControls();\r\n }\r\n },\r\n\r\n clear: function () {\r\n var self = this;\r\n\r\n clearTimeout(self.timer);\r\n\r\n self.timer = null;\r\n\r\n if (self.$progress) {\r\n self.$progress.removeAttr(\"style\").hide();\r\n }\r\n },\r\n\r\n start: function () {\r\n var self = this,\r\n current = self.instance.current;\r\n\r\n if (current) {\r\n self.$button\r\n .attr(\"title\", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_STOP)\r\n .removeClass(\"fancybox-button--play\")\r\n .addClass(\"fancybox-button--pause\");\r\n\r\n self.isActive = true;\r\n\r\n if (current.isComplete) {\r\n self.set(true);\r\n }\r\n\r\n self.instance.trigger(\"onSlideShowChange\", true);\r\n }\r\n },\r\n\r\n stop: function () {\r\n var self = this,\r\n current = self.instance.current;\r\n\r\n self.clear();\r\n\r\n self.$button\r\n .attr(\"title\", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_START)\r\n .removeClass(\"fancybox-button--pause\")\r\n .addClass(\"fancybox-button--play\");\r\n\r\n self.isActive = false;\r\n\r\n self.instance.trigger(\"onSlideShowChange\", false);\r\n\r\n if (self.$progress) {\r\n self.$progress.removeAttr(\"style\").hide();\r\n }\r\n },\r\n\r\n toggle: function () {\r\n var self = this;\r\n\r\n if (self.isActive) {\r\n self.stop();\r\n } else {\r\n self.start();\r\n }\r\n }\r\n });\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n if (instance && !instance.SlideShow) {\r\n instance.SlideShow = new SlideShow(instance);\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, current, firstRun) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (firstRun) {\r\n if (SlideShow && current.opts.slideShow.autoStart) {\r\n SlideShow.start();\r\n }\r\n } else if (SlideShow && SlideShow.isActive) {\r\n SlideShow.clear();\r\n }\r\n },\r\n\r\n \"afterShow.fb\": function (e, instance, current) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow && SlideShow.isActive) {\r\n SlideShow.set();\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n // \"P\" or Spacebar\r\n if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is(\"button,a,input\")) {\r\n keypress.preventDefault();\r\n\r\n SlideShow.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb onDeactivate.fb\": function (e, instance) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow) {\r\n SlideShow.stop();\r\n }\r\n }\r\n });\r\n\r\n // Page Visibility API to pause slideshow when window is not active\r\n $(document).on(\"visibilitychange\", function () {\r\n var instance = $.fancybox.getInstance(),\r\n SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow && SlideShow.isActive) {\r\n if (document.hidden) {\r\n SlideShow.clear();\r\n } else {\r\n SlideShow.set();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// FullScreen\r\n// Adds fullscreen functionality\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n // Collection of methods supported by user browser\r\n var fn = (function () {\r\n var fnMap = [\r\n [\"requestFullscreen\", \"exitFullscreen\", \"fullscreenElement\", \"fullscreenEnabled\", \"fullscreenchange\", \"fullscreenerror\"],\r\n // new WebKit\r\n [\r\n \"webkitRequestFullscreen\",\r\n \"webkitExitFullscreen\",\r\n \"webkitFullscreenElement\",\r\n \"webkitFullscreenEnabled\",\r\n \"webkitfullscreenchange\",\r\n \"webkitfullscreenerror\"\r\n ],\r\n // old WebKit (Safari 5.1)\r\n [\r\n \"webkitRequestFullScreen\",\r\n \"webkitCancelFullScreen\",\r\n \"webkitCurrentFullScreenElement\",\r\n \"webkitCancelFullScreen\",\r\n \"webkitfullscreenchange\",\r\n \"webkitfullscreenerror\"\r\n ],\r\n [\r\n \"mozRequestFullScreen\",\r\n \"mozCancelFullScreen\",\r\n \"mozFullScreenElement\",\r\n \"mozFullScreenEnabled\",\r\n \"mozfullscreenchange\",\r\n \"mozfullscreenerror\"\r\n ],\r\n [\"msRequestFullscreen\", \"msExitFullscreen\", \"msFullscreenElement\", \"msFullscreenEnabled\", \"MSFullscreenChange\", \"MSFullscreenError\"]\r\n ];\r\n\r\n var ret = {};\r\n\r\n for (var i = 0; i < fnMap.length; i++) {\r\n var val = fnMap[i];\r\n\r\n if (val && val[1] in document) {\r\n for (var j = 0; j < val.length; j++) {\r\n ret[fnMap[0][j]] = val[j];\r\n }\r\n\r\n return ret;\r\n }\r\n }\r\n\r\n return false;\r\n })();\r\n\r\n if (fn) {\r\n var FullScreen = {\r\n request: function (elem) {\r\n elem = elem || document.documentElement;\r\n\r\n elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);\r\n },\r\n exit: function () {\r\n document[fn.exitFullscreen]();\r\n },\r\n toggle: function (elem) {\r\n elem = elem || document.documentElement;\r\n\r\n if (this.isFullscreen()) {\r\n this.exit();\r\n } else {\r\n this.request(elem);\r\n }\r\n },\r\n isFullscreen: function () {\r\n return Boolean(document[fn.fullscreenElement]);\r\n },\r\n enabled: function () {\r\n return Boolean(document[fn.fullscreenEnabled]);\r\n }\r\n };\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n fullScreen: '\"\r\n },\r\n fullScreen: {\r\n autoStart: false\r\n }\r\n });\r\n\r\n $(document).on(fn.fullscreenchange, function () {\r\n var isFullscreen = FullScreen.isFullscreen(),\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n // If image is zooming, then force to stop and reposition properly\r\n if (instance.current && instance.current.type === \"image\" && instance.isAnimating) {\r\n instance.isAnimating = false;\r\n\r\n instance.update(true, true, 0);\r\n\r\n if (!instance.isComplete) {\r\n instance.complete();\r\n }\r\n }\r\n\r\n instance.trigger(\"onFullscreenChange\", isFullscreen);\r\n\r\n instance.$refs.container.toggleClass(\"fancybox-is-fullscreen\", isFullscreen);\r\n\r\n instance.$refs.toolbar\r\n .find(\"[data-fancybox-fullscreen]\")\r\n .toggleClass(\"fancybox-button--fsenter\", !isFullscreen)\r\n .toggleClass(\"fancybox-button--fsexit\", isFullscreen);\r\n }\r\n });\r\n }\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var $container;\r\n\r\n if (!fn) {\r\n instance.$refs.toolbar.find(\"[data-fancybox-fullscreen]\").remove();\r\n\r\n return;\r\n }\r\n\r\n if (instance && instance.group[instance.currIndex].opts.fullScreen) {\r\n $container = instance.$refs.container;\r\n\r\n $container.on(\"click.fb-fullscreen\", \"[data-fancybox-fullscreen]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n FullScreen.toggle();\r\n });\r\n\r\n if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) {\r\n FullScreen.request();\r\n }\r\n\r\n // Expose API\r\n instance.FullScreen = FullScreen;\r\n } else if (instance) {\r\n instance.$refs.toolbar.find(\"[data-fancybox-fullscreen]\").hide();\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n // \"F\"\r\n if (instance && instance.FullScreen && keycode === 70) {\r\n keypress.preventDefault();\r\n\r\n instance.FullScreen.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance) {\r\n if (instance && instance.FullScreen && instance.$refs.container.hasClass(\"fancybox-is-fullscreen\")) {\r\n FullScreen.exit();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// Thumbs\r\n// Displays thumbnails in a grid\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n var CLASS = \"fancybox-thumbs\",\r\n CLASS_ACTIVE = CLASS + \"-active\";\r\n\r\n // Make sure there are default values\r\n $.fancybox.defaults = $.extend(\r\n true, {\r\n btnTpl: {\r\n thumbs: '\"\r\n },\r\n thumbs: {\r\n autoStart: false, // Display thumbnails on opening\r\n hideOnClose: true, // Hide thumbnail grid when closing animation starts\r\n parentEl: \".fancybox-container\", // Container is injected into this element\r\n axis: \"y\" // Vertical (y) or horizontal (x) scrolling\r\n }\r\n },\r\n $.fancybox.defaults\r\n );\r\n\r\n var FancyThumbs = function (instance) {\r\n this.init(instance);\r\n };\r\n\r\n $.extend(FancyThumbs.prototype, {\r\n $button: null,\r\n $grid: null,\r\n $list: null,\r\n isVisible: false,\r\n isActive: false,\r\n\r\n init: function (instance) {\r\n var self = this,\r\n group = instance.group,\r\n enabled = 0;\r\n\r\n self.instance = instance;\r\n self.opts = group[instance.currIndex].opts.thumbs;\r\n\r\n instance.Thumbs = self;\r\n\r\n self.$button = instance.$refs.toolbar.find(\"[data-fancybox-thumbs]\");\r\n\r\n // Enable thumbs if at least two group items have thumbnails\r\n for (var i = 0, len = group.length; i < len; i++) {\r\n if (group[i].thumb) {\r\n enabled++;\r\n }\r\n\r\n if (enabled > 1) {\r\n break;\r\n }\r\n }\r\n\r\n if (enabled > 1 && !!self.opts) {\r\n self.$button.removeAttr(\"style\").on(\"click\", function () {\r\n self.toggle();\r\n });\r\n\r\n self.isActive = true;\r\n } else {\r\n self.$button.hide();\r\n }\r\n },\r\n\r\n create: function () {\r\n var self = this,\r\n instance = self.instance,\r\n parentEl = self.opts.parentEl,\r\n list = [],\r\n src;\r\n\r\n if (!self.$grid) {\r\n // Create main element\r\n self.$grid = $('
').appendTo(\r\n instance.$refs.container\r\n .find(parentEl)\r\n .addBack()\r\n .filter(parentEl)\r\n );\r\n\r\n // Add \"click\" event that performs gallery navigation\r\n self.$grid.on(\"click\", \"a\", function () {\r\n instance.jumpTo($(this).attr(\"data-index\"));\r\n });\r\n }\r\n\r\n // Build the list\r\n if (!self.$list) {\r\n self.$list = $('
').appendTo(self.$grid);\r\n }\r\n\r\n $.each(instance.group, function (i, item) {\r\n src = item.thumb;\r\n\r\n if (!src && item.type === \"image\") {\r\n src = item.src;\r\n }\r\n\r\n list.push(\r\n '\"\r\n );\r\n });\r\n\r\n self.$list[0].innerHTML = list.join(\"\");\r\n\r\n if (self.opts.axis === \"x\") {\r\n // Set fixed width for list element to enable horizontal scrolling\r\n self.$list.width(\r\n parseInt(self.$grid.css(\"padding-right\"), 10) +\r\n instance.group.length *\r\n self.$list\r\n .children()\r\n .eq(0)\r\n .outerWidth(true)\r\n );\r\n }\r\n },\r\n\r\n focus: function (duration) {\r\n var self = this,\r\n $list = self.$list,\r\n $grid = self.$grid,\r\n thumb,\r\n thumbPos;\r\n\r\n if (!self.instance.current) {\r\n return;\r\n }\r\n\r\n thumb = $list\r\n .children()\r\n .removeClass(CLASS_ACTIVE)\r\n .filter('[data-index=\"' + self.instance.current.index + '\"]')\r\n .addClass(CLASS_ACTIVE);\r\n\r\n thumbPos = thumb.position();\r\n\r\n // Check if need to scroll to make current thumb visible\r\n if (self.opts.axis === \"y\" && (thumbPos.top < 0 || thumbPos.top > $list.height() - thumb.outerHeight())) {\r\n $list.stop().animate({\r\n scrollTop: $list.scrollTop() + thumbPos.top\r\n },\r\n duration\r\n );\r\n } else if (\r\n self.opts.axis === \"x\" &&\r\n (thumbPos.left < $grid.scrollLeft() || thumbPos.left > $grid.scrollLeft() + ($grid.width() - thumb.outerWidth()))\r\n ) {\r\n $list\r\n .parent()\r\n .stop()\r\n .animate({\r\n scrollLeft: thumbPos.left\r\n },\r\n duration\r\n );\r\n }\r\n },\r\n\r\n update: function () {\r\n var that = this;\r\n that.instance.$refs.container.toggleClass(\"fancybox-show-thumbs\", this.isVisible);\r\n\r\n if (that.isVisible) {\r\n if (!that.$grid) {\r\n that.create();\r\n }\r\n\r\n that.instance.trigger(\"onThumbsShow\");\r\n\r\n that.focus(0);\r\n } else if (that.$grid) {\r\n that.instance.trigger(\"onThumbsHide\");\r\n }\r\n\r\n // Update content position\r\n that.instance.update();\r\n },\r\n\r\n hide: function () {\r\n this.isVisible = false;\r\n this.update();\r\n },\r\n\r\n show: function () {\r\n this.isVisible = true;\r\n this.update();\r\n },\r\n\r\n toggle: function () {\r\n this.isVisible = !this.isVisible;\r\n this.update();\r\n }\r\n });\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var Thumbs;\r\n\r\n if (instance && !instance.Thumbs) {\r\n Thumbs = new FancyThumbs(instance);\r\n\r\n if (Thumbs.isActive && Thumbs.opts.autoStart === true) {\r\n Thumbs.show();\r\n }\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, item, firstRun) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n if (Thumbs && Thumbs.isVisible) {\r\n Thumbs.focus(firstRun ? 0 : 250);\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n // \"G\"\r\n if (Thumbs && Thumbs.isActive && keycode === 71) {\r\n keypress.preventDefault();\r\n\r\n Thumbs.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {\r\n Thumbs.$grid.hide();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n//// ==========================================================================\r\n//\r\n// Share\r\n// Displays simple form for sharing current url\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n share: '\"\r\n },\r\n share: {\r\n url: function (instance, item) {\r\n return (\r\n (!instance.currentHash && !(item.type === \"inline\" || item.type === \"html\") ? item.origSrc || item.src : false) || window.location\r\n );\r\n },\r\n tpl: '
' +\r\n \"

{{SHARE}}

\" +\r\n \"

\" +\r\n '' +\r\n '' +\r\n \"Facebook\" +\r\n \"\" +\r\n '' +\r\n '' +\r\n \"Twitter\" +\r\n \"\" +\r\n '' +\r\n '' +\r\n \"Pinterest\" +\r\n \"\" +\r\n \"

\" +\r\n '

' +\r\n \"
\"\r\n }\r\n });\r\n\r\n function escapeHtml(string) {\r\n var entityMap = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n \"/\": \"/\",\r\n \"`\": \"`\",\r\n \"=\": \"=\"\r\n };\r\n\r\n return String(string).replace(/[&<>\"'`=\\/]/g, function (s) {\r\n return entityMap[s];\r\n });\r\n }\r\n\r\n $(document).on(\"click\", \"[data-fancybox-share]\", function () {\r\n var instance = $.fancybox.getInstance(),\r\n current = instance.current || null,\r\n url,\r\n tpl;\r\n\r\n if (!current) {\r\n return;\r\n }\r\n\r\n if ($.type(current.opts.share.url) === \"function\") {\r\n url = current.opts.share.url.apply(current, [instance, current]);\r\n }\r\n\r\n tpl = current.opts.share.tpl\r\n .replace(/\\{\\{media\\}\\}/g, current.type === \"image\" ? encodeURIComponent(current.src) : \"\")\r\n .replace(/\\{\\{url\\}\\}/g, encodeURIComponent(url))\r\n .replace(/\\{\\{url_raw\\}\\}/g, escapeHtml(url))\r\n .replace(/\\{\\{descr\\}\\}/g, instance.$caption ? encodeURIComponent(instance.$caption.text()) : \"\");\r\n\r\n $.fancybox.open({\r\n src: instance.translate(instance, tpl),\r\n type: \"html\",\r\n opts: {\r\n touch: false,\r\n animationEffect: false,\r\n afterLoad: function (shareInstance, shareCurrent) {\r\n // Close self if parent instance is closing\r\n instance.$refs.container.one(\"beforeClose.fb\", function () {\r\n shareInstance.close(null, 0);\r\n });\r\n\r\n // Opening links in a popup window\r\n shareCurrent.$content.find(\".fancybox-share__button\").click(function () {\r\n window.open(this.href, \"Share\", \"width=550, height=450\");\r\n return false;\r\n });\r\n },\r\n mobile: {\r\n autoFocus: false\r\n }\r\n }\r\n });\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// Hash\r\n// Enables linking to each modal\r\n//\r\n// ==========================================================================\r\n(function (window, document, $) {\r\n \"use strict\";\r\n\r\n // Simple $.escapeSelector polyfill (for jQuery prior v3)\r\n if (!$.escapeSelector) {\r\n $.escapeSelector = function (sel) {\r\n var rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\r\n var fcssescape = function (ch, asCodePoint) {\r\n if (asCodePoint) {\r\n // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\r\n if (ch === \"\\0\") {\r\n return \"\\uFFFD\";\r\n }\r\n\r\n // Control characters and (dependent upon position) numbers get escaped as code points\r\n return ch.slice(0, -1) + \"\\\\\" + ch.charCodeAt(ch.length - 1).toString(16) + \" \";\r\n }\r\n\r\n // Other potentially-special ASCII characters get backslash-escaped\r\n return \"\\\\\" + ch;\r\n };\r\n\r\n return (sel + \"\").replace(rcssescape, fcssescape);\r\n };\r\n }\r\n\r\n // Get info about gallery name and current index from url\r\n function parseUrl() {\r\n var hash = window.location.hash.substr(1),\r\n rez = hash.split(\"-\"),\r\n index = rez.length > 1 && /^\\+?\\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1,\r\n gallery = rez.join(\"-\");\r\n\r\n return {\r\n hash: hash,\r\n /* Index is starting from 1 */\r\n index: index < 1 ? 1 : index,\r\n gallery: gallery\r\n };\r\n }\r\n\r\n // Trigger click evnt on links to open new fancyBox instance\r\n function triggerFromUrl(url) {\r\n if (url.gallery !== \"\") {\r\n // If we can find element matching 'data-fancybox' atribute,\r\n // then triggering click event should start fancyBox\r\n $(\"[data-fancybox='\" + $.escapeSelector(url.gallery) + \"']\")\r\n .eq(url.index - 1)\r\n .focus()\r\n .trigger(\"click.fb-start\");\r\n }\r\n }\r\n\r\n // Get gallery name from current instance\r\n function getGalleryID(instance) {\r\n var opts, ret;\r\n\r\n if (!instance) {\r\n return false;\r\n }\r\n\r\n opts = instance.current ? instance.current.opts : instance.opts;\r\n ret = opts.hash || (opts.$orig ? opts.$orig.data(\"fancybox\") || opts.$orig.data(\"fancybox-trigger\") : \"\");\r\n\r\n return ret === \"\" ? false : ret;\r\n }\r\n\r\n // Start when DOM becomes ready\r\n $(function () {\r\n // Check if user has disabled this module\r\n if ($.fancybox.defaults.hash === false) {\r\n return;\r\n }\r\n\r\n // Update hash when opening/closing fancyBox\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var url, gallery;\r\n\r\n if (instance.group[instance.currIndex].opts.hash === false) {\r\n return;\r\n }\r\n\r\n url = parseUrl();\r\n gallery = getGalleryID(instance);\r\n\r\n // Make sure gallery start index matches index from hash\r\n if (gallery && url.gallery && gallery == url.gallery) {\r\n instance.currIndex = url.index - 1;\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, current, firstRun) {\r\n var gallery;\r\n\r\n if (!current || current.opts.hash === false) {\r\n return;\r\n }\r\n\r\n // Check if need to update window hash\r\n gallery = getGalleryID(instance);\r\n\r\n if (!gallery) {\r\n return;\r\n }\r\n\r\n // Variable containing last hash value set by fancyBox\r\n // It will be used to determine if fancyBox needs to close after hash change is detected\r\n instance.currentHash = gallery + (instance.group.length > 1 ? \"-\" + (current.index + 1) : \"\");\r\n\r\n // If current hash is the same (this instance most likely is opened by hashchange), then do nothing\r\n if (window.location.hash === \"#\" + instance.currentHash) {\r\n return;\r\n }\r\n\r\n if (firstRun && !instance.origHash) {\r\n instance.origHash = window.location.hash;\r\n }\r\n\r\n if (instance.hashTimer) {\r\n clearTimeout(instance.hashTimer);\r\n }\r\n\r\n // Update hash\r\n instance.hashTimer = setTimeout(function () {\r\n if (\"replaceState\" in window.history) {\r\n window.history[firstRun ? \"pushState\" : \"replaceState\"]({},\r\n document.title,\r\n window.location.pathname + window.location.search + \"#\" + instance.currentHash\r\n );\r\n\r\n if (firstRun) {\r\n instance.hasCreatedHistory = true;\r\n }\r\n } else {\r\n window.location.hash = instance.currentHash;\r\n }\r\n\r\n instance.hashTimer = null;\r\n }, 300);\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance, current) {\r\n if (!current || current.opts.hash === false) {\r\n return;\r\n }\r\n\r\n clearTimeout(instance.hashTimer);\r\n\r\n // Goto previous history entry\r\n if (instance.currentHash && instance.hasCreatedHistory) {\r\n window.history.back();\r\n } else if (instance.currentHash) {\r\n if (\"replaceState\" in window.history) {\r\n window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (instance.origHash || \"\"));\r\n } else {\r\n window.location.hash = instance.origHash;\r\n }\r\n }\r\n\r\n instance.currentHash = null;\r\n }\r\n });\r\n\r\n // Check if need to start/close after url has changed\r\n $(window).on(\"hashchange.fb\", function () {\r\n var url = parseUrl(),\r\n fb = null;\r\n\r\n // Find last fancyBox instance that has \"hash\"\r\n $.each(\r\n $(\".fancybox-container\")\r\n .get()\r\n .reverse(),\r\n function (index, value) {\r\n var tmp = $(value).data(\"FancyBox\");\r\n\r\n if (tmp && tmp.currentHash) {\r\n fb = tmp;\r\n return false;\r\n }\r\n }\r\n );\r\n\r\n if (fb) {\r\n // Now, compare hash values\r\n if (fb.currentHash !== url.gallery + \"-\" + url.index && !(url.index === 1 && fb.currentHash == url.gallery)) {\r\n fb.currentHash = null;\r\n\r\n fb.close();\r\n }\r\n } else if (url.gallery !== \"\") {\r\n triggerFromUrl(url);\r\n }\r\n });\r\n\r\n // Check current hash and trigger click event on matching element to start fancyBox, if needed\r\n setTimeout(function () {\r\n if (!$.fancybox.getInstance()) {\r\n triggerFromUrl(parseUrl());\r\n }\r\n }, 50);\r\n });\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// Wheel\r\n// Basic mouse weheel support for gallery navigation\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n var prevTime = new Date().getTime();\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance, current) {\r\n instance.$refs.stage.on(\"mousewheel DOMMouseScroll wheel MozMousePixelScroll\", function (e) {\r\n var current = instance.current,\r\n currTime = new Date().getTime();\r\n\r\n if (instance.group.length < 2 || current.opts.wheel === false || (current.opts.wheel === \"auto\" && current.type !== \"image\")) {\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n if (current.$slide.hasClass(\"fancybox-animated\")) {\r\n return;\r\n }\r\n\r\n e = e.originalEvent || e;\r\n\r\n if (currTime - prevTime < 250) {\r\n return;\r\n }\r\n\r\n prevTime = currTime;\r\n\r\n instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? \"next\" : \"previous\"]();\r\n });\r\n }\r\n });\r\n})(document, jQuery);","/*!\n * Flickity PACKAGED v2.3.0\n * Touch, responsive, flickable carousels\n *\n * Licensed GPLv3 for open source use\n * or Flickity Commercial License for commercial use\n *\n * https://flickity.metafizzy.co\n * Copyright 2015-2021 Metafizzy\n */\n\n/**\n * Bridget makes jQuery widgets\n * v2.0.1\n * MIT license\n */\n\n/* jshint browser: true, strict: true, undef: true, unused: true */\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */ /* globals define, module, require */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {\n return factory( window, jQuery );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('jquery')\n );\n } else {\n // browser global\n window.jQueryBridget = factory(\n window,\n window.jQuery\n );\n }\n\n}( window, function factory( window, jQuery ) {\n'use strict';\n\n// ----- utils ----- //\n\nvar arraySlice = Array.prototype.slice;\n\n// helper function for logging errors\n// $.error breaks jQuery chaining\nvar console = window.console;\nvar logError = typeof console == 'undefined' ? function() {} :\n function( message ) {\n console.error( message );\n };\n\n// ----- jQueryBridget ----- //\n\nfunction jQueryBridget( namespace, PluginClass, $ ) {\n $ = $ || jQuery || window.jQuery;\n if ( !$ ) {\n return;\n }\n\n // add option method -> $().plugin('option', {...})\n if ( !PluginClass.prototype.option ) {\n // option setter\n PluginClass.prototype.option = function( opts ) {\n // bail out if not an object\n if ( !$.isPlainObject( opts ) ){\n return;\n }\n this.options = $.extend( true, this.options, opts );\n };\n }\n\n // make jQuery plugin\n $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {\n if ( typeof arg0 == 'string' ) {\n // method call $().plugin( 'methodName', { options } )\n // shift arguments by 1\n var args = arraySlice.call( arguments, 1 );\n return methodCall( this, arg0, args );\n }\n // just $().plugin({ options })\n plainCall( this, arg0 );\n return this;\n };\n\n // $().plugin('methodName')\n function methodCall( $elems, methodName, args ) {\n var returnValue;\n var pluginMethodStr = '$().' + namespace + '(\"' + methodName + '\")';\n\n $elems.each( function( i, elem ) {\n // get instance\n var instance = $.data( elem, namespace );\n if ( !instance ) {\n logError( namespace + ' not initialized. Cannot call methods, i.e. ' +\n pluginMethodStr );\n return;\n }\n\n var method = instance[ methodName ];\n if ( !method || methodName.charAt(0) == '_' ) {\n logError( pluginMethodStr + ' is not a valid method' );\n return;\n }\n\n // apply method, get return value\n var value = method.apply( instance, args );\n // set return value if value is returned, use only first value\n returnValue = returnValue === undefined ? value : returnValue;\n });\n\n return returnValue !== undefined ? returnValue : $elems;\n }\n\n function plainCall( $elems, options ) {\n $elems.each( function( i, elem ) {\n var instance = $.data( elem, namespace );\n if ( instance ) {\n // set options & init\n instance.option( options );\n instance._init();\n } else {\n // initialize new instance\n instance = new PluginClass( elem, options );\n $.data( elem, namespace, instance );\n }\n });\n }\n\n updateJQuery( $ );\n\n}\n\n// ----- updateJQuery ----- //\n\n// set $.bridget for v1 backwards compatibility\nfunction updateJQuery( $ ) {\n if ( !$ || ( $ && $.bridget ) ) {\n return;\n }\n $.bridget = jQueryBridget;\n}\n\nupdateJQuery( jQuery || window.jQuery );\n\n// ----- ----- //\n\nreturn jQueryBridget;\n\n}));\n\n/**\n * EvEmitter v1.1.0\n * Lil' event emitter\n * MIT License\n */\n\n/* jshint unused: true, undef: true, strict: true */\n\n( function( global, factory ) {\n // universal module definition\n /* jshint strict: false */ /* globals define, module, window */\n if ( typeof define == 'function' && define.amd ) {\n // AMD - RequireJS\n define( 'ev-emitter/ev-emitter',factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS - Browserify, Webpack\n module.exports = factory();\n } else {\n // Browser globals\n global.EvEmitter = factory();\n }\n\n}( typeof window != 'undefined' ? window : this, function() {\n\n\n\nfunction EvEmitter() {}\n\nvar proto = EvEmitter.prototype;\n\nproto.on = function( eventName, listener ) {\n if ( !eventName || !listener ) {\n return;\n }\n // set events hash\n var events = this._events = this._events || {};\n // set listeners array\n var listeners = events[ eventName ] = events[ eventName ] || [];\n // only add once\n if ( listeners.indexOf( listener ) == -1 ) {\n listeners.push( listener );\n }\n\n return this;\n};\n\nproto.once = function( eventName, listener ) {\n if ( !eventName || !listener ) {\n return;\n }\n // add event\n this.on( eventName, listener );\n // set once flag\n // set onceEvents hash\n var onceEvents = this._onceEvents = this._onceEvents || {};\n // set onceListeners object\n var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};\n // set flag\n onceListeners[ listener ] = true;\n\n return this;\n};\n\nproto.off = function( eventName, listener ) {\n var listeners = this._events && this._events[ eventName ];\n if ( !listeners || !listeners.length ) {\n return;\n }\n var index = listeners.indexOf( listener );\n if ( index != -1 ) {\n listeners.splice( index, 1 );\n }\n\n return this;\n};\n\nproto.emitEvent = function( eventName, args ) {\n var listeners = this._events && this._events[ eventName ];\n if ( !listeners || !listeners.length ) {\n return;\n }\n // copy over to avoid interference if .off() in listener\n listeners = listeners.slice(0);\n args = args || [];\n // once stuff\n var onceListeners = this._onceEvents && this._onceEvents[ eventName ];\n\n for ( var i=0; i < listeners.length; i++ ) {\n var listener = listeners[i]\n var isOnce = onceListeners && onceListeners[ listener ];\n if ( isOnce ) {\n // remove listener\n // remove before trigger to prevent recursion\n this.off( eventName, listener );\n // unset once flag\n delete onceListeners[ listener ];\n }\n // trigger listener\n listener.apply( this, args );\n }\n\n return this;\n};\n\nproto.allOff = function() {\n delete this._events;\n delete this._onceEvents;\n};\n\nreturn EvEmitter;\n\n}));\n\n/*!\n * getSize v2.0.3\n * measure size of elements\n * MIT license\n */\n\n/* jshint browser: true, strict: true, undef: true, unused: true */\n/* globals console: false */\n\n( function( window, factory ) {\n /* jshint strict: false */ /* globals define, module */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'get-size/get-size',factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory();\n } else {\n // browser global\n window.getSize = factory();\n }\n\n})( window, function factory() {\n'use strict';\n\n// -------------------------- helpers -------------------------- //\n\n// get a number from a string, not a percentage\nfunction getStyleSize( value ) {\n var num = parseFloat( value );\n // not a percent like '100%', and a number\n var isValid = value.indexOf('%') == -1 && !isNaN( num );\n return isValid && num;\n}\n\nfunction noop() {}\n\nvar logError = typeof console == 'undefined' ? noop :\n function( message ) {\n console.error( message );\n };\n\n// -------------------------- measurements -------------------------- //\n\nvar measurements = [\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'paddingBottom',\n 'marginLeft',\n 'marginRight',\n 'marginTop',\n 'marginBottom',\n 'borderLeftWidth',\n 'borderRightWidth',\n 'borderTopWidth',\n 'borderBottomWidth'\n];\n\nvar measurementsLength = measurements.length;\n\nfunction getZeroSize() {\n var size = {\n width: 0,\n height: 0,\n innerWidth: 0,\n innerHeight: 0,\n outerWidth: 0,\n outerHeight: 0\n };\n for ( var i=0; i < measurementsLength; i++ ) {\n var measurement = measurements[i];\n size[ measurement ] = 0;\n }\n return size;\n}\n\n// -------------------------- getStyle -------------------------- //\n\n/**\n * getStyle, get style of element, check for Firefox bug\n * https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n */\nfunction getStyle( elem ) {\n var style = getComputedStyle( elem );\n if ( !style ) {\n logError( 'Style returned ' + style +\n '. Are you running this code in a hidden iframe on Firefox? ' +\n 'See https://bit.ly/getsizebug1' );\n }\n return style;\n}\n\n// -------------------------- setup -------------------------- //\n\nvar isSetup = false;\n\nvar isBoxSizeOuter;\n\n/**\n * setup\n * check isBoxSizerOuter\n * do on first getSize() rather than on page load for Firefox bug\n */\nfunction setup() {\n // setup once\n if ( isSetup ) {\n return;\n }\n isSetup = true;\n\n // -------------------------- box sizing -------------------------- //\n\n /**\n * Chrome & Safari measure the outer-width on style.width on border-box elems\n * IE11 & Firefox<29 measures the inner-width\n */\n var div = document.createElement('div');\n div.style.width = '200px';\n div.style.padding = '1px 2px 3px 4px';\n div.style.borderStyle = 'solid';\n div.style.borderWidth = '1px 2px 3px 4px';\n div.style.boxSizing = 'border-box';\n\n var body = document.body || document.documentElement;\n body.appendChild( div );\n var style = getStyle( div );\n // round value for browser zoom. desandro/masonry#928\n isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;\n getSize.isBoxSizeOuter = isBoxSizeOuter;\n\n body.removeChild( div );\n}\n\n// -------------------------- getSize -------------------------- //\n\nfunction getSize( elem ) {\n setup();\n\n // use querySeletor if elem is string\n if ( typeof elem == 'string' ) {\n elem = document.querySelector( elem );\n }\n\n // do not proceed on non-objects\n if ( !elem || typeof elem != 'object' || !elem.nodeType ) {\n return;\n }\n\n var style = getStyle( elem );\n\n // if hidden, everything is 0\n if ( style.display == 'none' ) {\n return getZeroSize();\n }\n\n var size = {};\n size.width = elem.offsetWidth;\n size.height = elem.offsetHeight;\n\n var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';\n\n // get all measurements\n for ( var i=0; i < measurementsLength; i++ ) {\n var measurement = measurements[i];\n var value = style[ measurement ];\n var num = parseFloat( value );\n // any 'auto', 'medium' value will be 0\n size[ measurement ] = !isNaN( num ) ? num : 0;\n }\n\n var paddingWidth = size.paddingLeft + size.paddingRight;\n var paddingHeight = size.paddingTop + size.paddingBottom;\n var marginWidth = size.marginLeft + size.marginRight;\n var marginHeight = size.marginTop + size.marginBottom;\n var borderWidth = size.borderLeftWidth + size.borderRightWidth;\n var borderHeight = size.borderTopWidth + size.borderBottomWidth;\n\n var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;\n\n // overwrite width and height if we can get it from style\n var styleWidth = getStyleSize( style.width );\n if ( styleWidth !== false ) {\n size.width = styleWidth +\n // add padding and border unless it's already including it\n ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );\n }\n\n var styleHeight = getStyleSize( style.height );\n if ( styleHeight !== false ) {\n size.height = styleHeight +\n // add padding and border unless it's already including it\n ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );\n }\n\n size.innerWidth = size.width - ( paddingWidth + borderWidth );\n size.innerHeight = size.height - ( paddingHeight + borderHeight );\n\n size.outerWidth = size.width + marginWidth;\n size.outerHeight = size.height + marginHeight;\n\n return size;\n}\n\nreturn getSize;\n\n});\n\n/**\n * matchesSelector v2.0.2\n * matchesSelector( element, '.selector' )\n * MIT license\n */\n\n/*jshint browser: true, strict: true, undef: true, unused: true */\n\n( function( window, factory ) {\n /*global define: false, module: false */\n 'use strict';\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'desandro-matches-selector/matches-selector',factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory();\n } else {\n // browser global\n window.matchesSelector = factory();\n }\n\n}( window, function factory() {\n 'use strict';\n\n var matchesMethod = ( function() {\n var ElemProto = window.Element.prototype;\n // check for the standard method name first\n if ( ElemProto.matches ) {\n return 'matches';\n }\n // check un-prefixed\n if ( ElemProto.matchesSelector ) {\n return 'matchesSelector';\n }\n // check vendor prefixes\n var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];\n\n for ( var i=0; i < prefixes.length; i++ ) {\n var prefix = prefixes[i];\n var method = prefix + 'MatchesSelector';\n if ( ElemProto[ method ] ) {\n return method;\n }\n }\n })();\n\n return function matchesSelector( elem, selector ) {\n return elem[ matchesMethod ]( selector );\n };\n\n}));\n\n/**\n * Fizzy UI utils v2.0.7\n * MIT license\n */\n\n/*jshint browser: true, undef: true, unused: true, strict: true */\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */ /*globals define, module, require */\n\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'fizzy-ui-utils/utils',[\n 'desandro-matches-selector/matches-selector'\n ], function( matchesSelector ) {\n return factory( window, matchesSelector );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('desandro-matches-selector')\n );\n } else {\n // browser global\n window.fizzyUIUtils = factory(\n window,\n window.matchesSelector\n );\n }\n\n}( window, function factory( window, matchesSelector ) {\n\n\n\nvar utils = {};\n\n// ----- extend ----- //\n\n// extends objects\nutils.extend = function( a, b ) {\n for ( var prop in b ) {\n a[ prop ] = b[ prop ];\n }\n return a;\n};\n\n// ----- modulo ----- //\n\nutils.modulo = function( num, div ) {\n return ( ( num % div ) + div ) % div;\n};\n\n// ----- makeArray ----- //\n\nvar arraySlice = Array.prototype.slice;\n\n// turn element or nodeList into an array\nutils.makeArray = function( obj ) {\n if ( Array.isArray( obj ) ) {\n // use object if already an array\n return obj;\n }\n // return empty array if undefined or null. #6\n if ( obj === null || obj === undefined ) {\n return [];\n }\n\n var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';\n if ( isArrayLike ) {\n // convert nodeList to array\n return arraySlice.call( obj );\n }\n\n // array of single index\n return [ obj ];\n};\n\n// ----- removeFrom ----- //\n\nutils.removeFrom = function( ary, obj ) {\n var index = ary.indexOf( obj );\n if ( index != -1 ) {\n ary.splice( index, 1 );\n }\n};\n\n// ----- getParent ----- //\n\nutils.getParent = function( elem, selector ) {\n while ( elem.parentNode && elem != document.body ) {\n elem = elem.parentNode;\n if ( matchesSelector( elem, selector ) ) {\n return elem;\n }\n }\n};\n\n// ----- getQueryElement ----- //\n\n// use element as selector string\nutils.getQueryElement = function( elem ) {\n if ( typeof elem == 'string' ) {\n return document.querySelector( elem );\n }\n return elem;\n};\n\n// ----- handleEvent ----- //\n\n// enable .ontype to trigger from .addEventListener( elem, 'type' )\nutils.handleEvent = function( event ) {\n var method = 'on' + event.type;\n if ( this[ method ] ) {\n this[ method ]( event );\n }\n};\n\n// ----- filterFindElements ----- //\n\nutils.filterFindElements = function( elems, selector ) {\n // make array of elems\n elems = utils.makeArray( elems );\n var ffElems = [];\n\n elems.forEach( function( elem ) {\n // check that elem is an actual element\n if ( !( elem instanceof HTMLElement ) ) {\n return;\n }\n // add elem if no selector\n if ( !selector ) {\n ffElems.push( elem );\n return;\n }\n // filter & find items if we have a selector\n // filter\n if ( matchesSelector( elem, selector ) ) {\n ffElems.push( elem );\n }\n // find children\n var childElems = elem.querySelectorAll( selector );\n // concat childElems to filterFound array\n for ( var i=0; i < childElems.length; i++ ) {\n ffElems.push( childElems[i] );\n }\n });\n\n return ffElems;\n};\n\n// ----- debounceMethod ----- //\n\nutils.debounceMethod = function( _class, methodName, threshold ) {\n threshold = threshold || 100;\n // original method\n var method = _class.prototype[ methodName ];\n var timeoutName = methodName + 'Timeout';\n\n _class.prototype[ methodName ] = function() {\n var timeout = this[ timeoutName ];\n clearTimeout( timeout );\n\n var args = arguments;\n var _this = this;\n this[ timeoutName ] = setTimeout( function() {\n method.apply( _this, args );\n delete _this[ timeoutName ];\n }, threshold );\n };\n};\n\n// ----- docReady ----- //\n\nutils.docReady = function( callback ) {\n var readyState = document.readyState;\n if ( readyState == 'complete' || readyState == 'interactive' ) {\n // do async to allow for other scripts to run. metafizzy/flickity#441\n setTimeout( callback );\n } else {\n document.addEventListener( 'DOMContentLoaded', callback );\n }\n};\n\n// ----- htmlInit ----- //\n\n// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/\nutils.toDashed = function( str ) {\n return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {\n return $1 + '-' + $2;\n }).toLowerCase();\n};\n\nvar console = window.console;\n/**\n * allow user to initialize classes via [data-namespace] or .js-namespace class\n * htmlInit( Widget, 'widgetName' )\n * options are parsed from data-namespace-options\n */\nutils.htmlInit = function( WidgetClass, namespace ) {\n utils.docReady( function() {\n var dashedNamespace = utils.toDashed( namespace );\n var dataAttr = 'data-' + dashedNamespace;\n var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );\n var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );\n var elems = utils.makeArray( dataAttrElems )\n .concat( utils.makeArray( jsDashElems ) );\n var dataOptionsAttr = dataAttr + '-options';\n var jQuery = window.jQuery;\n\n elems.forEach( function( elem ) {\n var attr = elem.getAttribute( dataAttr ) ||\n elem.getAttribute( dataOptionsAttr );\n var options;\n try {\n options = attr && JSON.parse( attr );\n } catch ( error ) {\n // log error, do not initialize\n if ( console ) {\n console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +\n ': ' + error );\n }\n return;\n }\n // initialize\n var instance = new WidgetClass( elem, options );\n // make available via $().data('namespace')\n if ( jQuery ) {\n jQuery.data( elem, namespace, instance );\n }\n });\n\n });\n};\n\n// ----- ----- //\n\nreturn utils;\n\n}));\n\n// Flickity.Cell\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/cell',[\n 'get-size/get-size',\n ], function( getSize ) {\n return factory( window, getSize );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('get-size')\n );\n } else {\n // browser global\n window.Flickity = window.Flickity || {};\n window.Flickity.Cell = factory(\n window,\n window.getSize\n );\n }\n\n}( window, function factory( window, getSize ) {\n\n\n\nfunction Cell( elem, parent ) {\n this.element = elem;\n this.parent = parent;\n\n this.create();\n}\n\nvar proto = Cell.prototype;\n\nproto.create = function() {\n this.element.style.position = 'absolute';\n this.element.setAttribute( 'aria-hidden', 'true' );\n this.x = 0;\n this.shift = 0;\n this.element.style[ this.parent.originSide ] = 0;\n};\n\nproto.destroy = function() {\n // reset style\n this.unselect();\n this.element.style.position = '';\n var side = this.parent.originSide;\n this.element.style[ side ] = '';\n this.element.style.transform = '';\n this.element.removeAttribute('aria-hidden');\n};\n\nproto.getSize = function() {\n this.size = getSize( this.element );\n};\n\nproto.setPosition = function( x ) {\n this.x = x;\n this.updateTarget();\n this.renderPosition( x );\n};\n\n// setDefaultTarget v1 method, backwards compatibility, remove in v3\nproto.updateTarget = proto.setDefaultTarget = function() {\n var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight';\n this.target = this.x + this.size[ marginProperty ] +\n this.size.width * this.parent.cellAlign;\n};\n\nproto.renderPosition = function( x ) {\n // render position of cell with in slider\n var sideOffset = this.parent.originSide === 'left' ? 1 : -1;\n\n var adjustedX = this.parent.options.percentPosition ?\n x * sideOffset * ( this.parent.size.innerWidth / this.size.width ) :\n x * sideOffset;\n\n this.element.style.transform = 'translateX(' +\n this.parent.getPositionValue( adjustedX ) + ')';\n};\n\nproto.select = function() {\n this.element.classList.add('is-selected');\n this.element.removeAttribute('aria-hidden');\n};\n\nproto.unselect = function() {\n this.element.classList.remove('is-selected');\n this.element.setAttribute( 'aria-hidden', 'true' );\n};\n\n/**\n * @param {Integer} shift - 0, 1, or -1\n */\nproto.wrapShift = function( shift ) {\n this.shift = shift;\n this.renderPosition( this.x + this.parent.slideableWidth * shift );\n};\n\nproto.remove = function() {\n this.element.parentNode.removeChild( this.element );\n};\n\nreturn Cell;\n\n} ) );\n\n// slide\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/slide',factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory();\n } else {\n // browser global\n window.Flickity = window.Flickity || {};\n window.Flickity.Slide = factory();\n }\n\n}( window, function factory() {\n'use strict';\n\nfunction Slide( parent ) {\n this.parent = parent;\n this.isOriginLeft = parent.originSide == 'left';\n this.cells = [];\n this.outerWidth = 0;\n this.height = 0;\n}\n\nvar proto = Slide.prototype;\n\nproto.addCell = function( cell ) {\n this.cells.push( cell );\n this.outerWidth += cell.size.outerWidth;\n this.height = Math.max( cell.size.outerHeight, this.height );\n // first cell stuff\n if ( this.cells.length == 1 ) {\n this.x = cell.x; // x comes from first cell\n var beginMargin = this.isOriginLeft ? 'marginLeft' : 'marginRight';\n this.firstMargin = cell.size[ beginMargin ];\n }\n};\n\nproto.updateTarget = function() {\n var endMargin = this.isOriginLeft ? 'marginRight' : 'marginLeft';\n var lastCell = this.getLastCell();\n var lastMargin = lastCell ? lastCell.size[ endMargin ] : 0;\n var slideWidth = this.outerWidth - ( this.firstMargin + lastMargin );\n this.target = this.x + this.firstMargin + slideWidth * this.parent.cellAlign;\n};\n\nproto.getLastCell = function() {\n return this.cells[ this.cells.length - 1 ];\n};\n\nproto.select = function() {\n this.cells.forEach( function( cell ) {\n cell.select();\n } );\n};\n\nproto.unselect = function() {\n this.cells.forEach( function( cell ) {\n cell.unselect();\n } );\n};\n\nproto.getCellElements = function() {\n return this.cells.map( function( cell ) {\n return cell.element;\n } );\n};\n\nreturn Slide;\n\n} ) );\n\n// animate\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/animate',[\n 'fizzy-ui-utils/utils',\n ], function( utils ) {\n return factory( window, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n window.Flickity = window.Flickity || {};\n window.Flickity.animatePrototype = factory(\n window,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, utils ) {\n\n\n\n// -------------------------- animate -------------------------- //\n\nvar proto = {};\n\nproto.startAnimation = function() {\n if ( this.isAnimating ) {\n return;\n }\n\n this.isAnimating = true;\n this.restingFrames = 0;\n this.animate();\n};\n\nproto.animate = function() {\n this.applyDragForce();\n this.applySelectedAttraction();\n\n var previousX = this.x;\n\n this.integratePhysics();\n this.positionSlider();\n this.settle( previousX );\n // animate next frame\n if ( this.isAnimating ) {\n var _this = this;\n requestAnimationFrame( function animateFrame() {\n _this.animate();\n } );\n }\n};\n\nproto.positionSlider = function() {\n var x = this.x;\n // wrap position around\n if ( this.options.wrapAround && this.cells.length > 1 ) {\n x = utils.modulo( x, this.slideableWidth );\n x -= this.slideableWidth;\n this.shiftWrapCells( x );\n }\n\n this.setTranslateX( x, this.isAnimating );\n this.dispatchScrollEvent();\n};\n\nproto.setTranslateX = function( x, is3d ) {\n x += this.cursorPosition;\n // reverse if right-to-left and using transform\n x = this.options.rightToLeft ? -x : x;\n var translateX = this.getPositionValue( x );\n // use 3D transforms for hardware acceleration on iOS\n // but use 2D when settled, for better font-rendering\n this.slider.style.transform = is3d ?\n 'translate3d(' + translateX + ',0,0)' : 'translateX(' + translateX + ')';\n};\n\nproto.dispatchScrollEvent = function() {\n var firstSlide = this.slides[0];\n if ( !firstSlide ) {\n return;\n }\n var positionX = -this.x - firstSlide.target;\n var progress = positionX / this.slidesWidth;\n this.dispatchEvent( 'scroll', null, [ progress, positionX ] );\n};\n\nproto.positionSliderAtSelected = function() {\n if ( !this.cells.length ) {\n return;\n }\n this.x = -this.selectedSlide.target;\n this.velocity = 0; // stop wobble\n this.positionSlider();\n};\n\nproto.getPositionValue = function( position ) {\n if ( this.options.percentPosition ) {\n // percent position, round to 2 digits, like 12.34%\n return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%';\n } else {\n // pixel positioning\n return Math.round( position ) + 'px';\n }\n};\n\nproto.settle = function( previousX ) {\n // keep track of frames where x hasn't moved\n var isResting = !this.isPointerDown &&\n Math.round( this.x * 100 ) == Math.round( previousX * 100 );\n if ( isResting ) {\n this.restingFrames++;\n }\n // stop animating if resting for 3 or more frames\n if ( this.restingFrames > 2 ) {\n this.isAnimating = false;\n delete this.isFreeScrolling;\n // render position with translateX when settled\n this.positionSlider();\n this.dispatchEvent( 'settle', null, [ this.selectedIndex ] );\n }\n};\n\nproto.shiftWrapCells = function( x ) {\n // shift before cells\n var beforeGap = this.cursorPosition + x;\n this._shiftCells( this.beforeShiftCells, beforeGap, -1 );\n // shift after cells\n var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition );\n this._shiftCells( this.afterShiftCells, afterGap, 1 );\n};\n\nproto._shiftCells = function( cells, gap, shift ) {\n for ( var i = 0; i < cells.length; i++ ) {\n var cell = cells[i];\n var cellShift = gap > 0 ? shift : 0;\n cell.wrapShift( cellShift );\n gap -= cell.size.outerWidth;\n }\n};\n\nproto._unshiftCells = function( cells ) {\n if ( !cells || !cells.length ) {\n return;\n }\n for ( var i = 0; i < cells.length; i++ ) {\n cells[i].wrapShift( 0 );\n }\n};\n\n// -------------------------- physics -------------------------- //\n\nproto.integratePhysics = function() {\n this.x += this.velocity;\n this.velocity *= this.getFrictionFactor();\n};\n\nproto.applyForce = function( force ) {\n this.velocity += force;\n};\n\nproto.getFrictionFactor = function() {\n return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ];\n};\n\nproto.getRestingPosition = function() {\n // my thanks to Steven Wittens, who simplified this math greatly\n return this.x + this.velocity / ( 1 - this.getFrictionFactor() );\n};\n\nproto.applyDragForce = function() {\n if ( !this.isDraggable || !this.isPointerDown ) {\n return;\n }\n // change the position to drag position by applying force\n var dragVelocity = this.dragX - this.x;\n var dragForce = dragVelocity - this.velocity;\n this.applyForce( dragForce );\n};\n\nproto.applySelectedAttraction = function() {\n // do not attract if pointer down or no slides\n var dragDown = this.isDraggable && this.isPointerDown;\n if ( dragDown || this.isFreeScrolling || !this.slides.length ) {\n return;\n }\n var distance = this.selectedSlide.target * -1 - this.x;\n var force = distance * this.options.selectedAttraction;\n this.applyForce( force );\n};\n\nreturn proto;\n\n} ) );\n\n// Flickity main\n/* eslint-disable max-params */\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/flickity',[\n 'ev-emitter/ev-emitter',\n 'get-size/get-size',\n 'fizzy-ui-utils/utils',\n './cell',\n './slide',\n './animate',\n ], function( EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) {\n return factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('ev-emitter'),\n require('get-size'),\n require('fizzy-ui-utils'),\n require('./cell'),\n require('./slide'),\n require('./animate')\n );\n } else {\n // browser global\n var _Flickity = window.Flickity;\n\n window.Flickity = factory(\n window,\n window.EvEmitter,\n window.getSize,\n window.fizzyUIUtils,\n _Flickity.Cell,\n _Flickity.Slide,\n _Flickity.animatePrototype\n );\n }\n\n}( window, function factory( window, EvEmitter, getSize,\n utils, Cell, Slide, animatePrototype ) {\n\n/* eslint-enable max-params */\n\n\n// vars\nvar jQuery = window.jQuery;\nvar getComputedStyle = window.getComputedStyle;\nvar console = window.console;\n\nfunction moveElements( elems, toElem ) {\n elems = utils.makeArray( elems );\n while ( elems.length ) {\n toElem.appendChild( elems.shift() );\n }\n}\n\n// -------------------------- Flickity -------------------------- //\n\n// globally unique identifiers\nvar GUID = 0;\n// internal store of all Flickity intances\nvar instances = {};\n\nfunction Flickity( element, options ) {\n var queryElement = utils.getQueryElement( element );\n if ( !queryElement ) {\n if ( console ) {\n console.error( 'Bad element for Flickity: ' + ( queryElement || element ) );\n }\n return;\n }\n this.element = queryElement;\n // do not initialize twice on same element\n if ( this.element.flickityGUID ) {\n var instance = instances[ this.element.flickityGUID ];\n if ( instance ) instance.option( options );\n return instance;\n }\n\n // add jQuery\n if ( jQuery ) {\n this.$element = jQuery( this.element );\n }\n // options\n this.options = utils.extend( {}, this.constructor.defaults );\n this.option( options );\n\n // kick things off\n this._create();\n}\n\nFlickity.defaults = {\n accessibility: true,\n // adaptiveHeight: false,\n cellAlign: 'center',\n // cellSelector: undefined,\n // contain: false,\n freeScrollFriction: 0.075, // friction when free-scrolling\n friction: 0.28, // friction when selecting\n namespaceJQueryEvents: true,\n // initialIndex: 0,\n percentPosition: true,\n resize: true,\n selectedAttraction: 0.025,\n setGallerySize: true,\n // watchCSS: false,\n // wrapAround: false\n};\n\n// hash of methods triggered on _create()\nFlickity.createMethods = [];\n\nvar proto = Flickity.prototype;\n// inherit EventEmitter\nutils.extend( proto, EvEmitter.prototype );\n\nproto._create = function() {\n // add id for Flickity.data\n var id = this.guid = ++GUID;\n this.element.flickityGUID = id; // expando\n instances[ id ] = this; // associate via id\n // initial properties\n this.selectedIndex = 0;\n // how many frames slider has been in same position\n this.restingFrames = 0;\n // initial physics properties\n this.x = 0;\n this.velocity = 0;\n this.originSide = this.options.rightToLeft ? 'right' : 'left';\n // create viewport & slider\n this.viewport = document.createElement('div');\n this.viewport.className = 'flickity-viewport';\n this._createSlider();\n\n if ( this.options.resize || this.options.watchCSS ) {\n window.addEventListener( 'resize', this );\n }\n\n // add listeners from on option\n for ( var eventName in this.options.on ) {\n var listener = this.options.on[ eventName ];\n this.on( eventName, listener );\n }\n\n Flickity.createMethods.forEach( function( method ) {\n this[ method ]();\n }, this );\n\n if ( this.options.watchCSS ) {\n this.watchCSS();\n } else {\n this.activate();\n }\n\n};\n\n/**\n * set options\n * @param {Object} opts - options to extend\n */\nproto.option = function( opts ) {\n utils.extend( this.options, opts );\n};\n\nproto.activate = function() {\n if ( this.isActive ) {\n return;\n }\n this.isActive = true;\n this.element.classList.add('flickity-enabled');\n if ( this.options.rightToLeft ) {\n this.element.classList.add('flickity-rtl');\n }\n\n this.getSize();\n // move initial cell elements so they can be loaded as cells\n var cellElems = this._filterFindCellElements( this.element.children );\n moveElements( cellElems, this.slider );\n this.viewport.appendChild( this.slider );\n this.element.appendChild( this.viewport );\n // get cells from children\n this.reloadCells();\n\n if ( this.options.accessibility ) {\n // allow element to focusable\n this.element.tabIndex = 0;\n // listen for key presses\n this.element.addEventListener( 'keydown', this );\n }\n\n this.emitEvent('activate');\n this.selectInitialIndex();\n // flag for initial activation, for using initialIndex\n this.isInitActivated = true;\n // ready event. #493\n this.dispatchEvent('ready');\n};\n\n// slider positions the cells\nproto._createSlider = function() {\n // slider element does all the positioning\n var slider = document.createElement('div');\n slider.className = 'flickity-slider';\n slider.style[ this.originSide ] = 0;\n this.slider = slider;\n};\n\nproto._filterFindCellElements = function( elems ) {\n return utils.filterFindElements( elems, this.options.cellSelector );\n};\n\n// goes through all children\nproto.reloadCells = function() {\n // collection of item elements\n this.cells = this._makeCells( this.slider.children );\n this.positionCells();\n this._getWrapShiftCells();\n this.setGallerySize();\n};\n\n/**\n * turn elements into Flickity.Cells\n * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells\n * @returns {Array} items - collection of new Flickity Cells\n */\nproto._makeCells = function( elems ) {\n var cellElems = this._filterFindCellElements( elems );\n\n // create new Flickity for collection\n var cells = cellElems.map( function( cellElem ) {\n return new Cell( cellElem, this );\n }, this );\n\n return cells;\n};\n\nproto.getLastCell = function() {\n return this.cells[ this.cells.length - 1 ];\n};\n\nproto.getLastSlide = function() {\n return this.slides[ this.slides.length - 1 ];\n};\n\n// positions all cells\nproto.positionCells = function() {\n // size all cells\n this._sizeCells( this.cells );\n // position all cells\n this._positionCells( 0 );\n};\n\n/**\n * position certain cells\n * @param {Integer} index - which cell to start with\n */\nproto._positionCells = function( index ) {\n index = index || 0;\n // also measure maxCellHeight\n // start 0 if positioning all cells\n this.maxCellHeight = index ? this.maxCellHeight || 0 : 0;\n var cellX = 0;\n // get cellX\n if ( index > 0 ) {\n var startCell = this.cells[ index - 1 ];\n cellX = startCell.x + startCell.size.outerWidth;\n }\n var len = this.cells.length;\n for ( var i = index; i < len; i++ ) {\n var cell = this.cells[i];\n cell.setPosition( cellX );\n cellX += cell.size.outerWidth;\n this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight );\n }\n // keep track of cellX for wrap-around\n this.slideableWidth = cellX;\n // slides\n this.updateSlides();\n // contain slides target\n this._containSlides();\n // update slidesWidth\n this.slidesWidth = len ? this.getLastSlide().target - this.slides[0].target : 0;\n};\n\n/**\n * cell.getSize() on multiple cells\n * @param {Array} cells - cells to size\n */\nproto._sizeCells = function( cells ) {\n cells.forEach( function( cell ) {\n cell.getSize();\n } );\n};\n\n// -------------------------- -------------------------- //\n\nproto.updateSlides = function() {\n this.slides = [];\n if ( !this.cells.length ) {\n return;\n }\n\n var slide = new Slide( this );\n this.slides.push( slide );\n var isOriginLeft = this.originSide == 'left';\n var nextMargin = isOriginLeft ? 'marginRight' : 'marginLeft';\n\n var canCellFit = this._getCanCellFit();\n\n this.cells.forEach( function( cell, i ) {\n // just add cell if first cell in slide\n if ( !slide.cells.length ) {\n slide.addCell( cell );\n return;\n }\n\n var slideWidth = ( slide.outerWidth - slide.firstMargin ) +\n ( cell.size.outerWidth - cell.size[ nextMargin ] );\n\n if ( canCellFit.call( this, i, slideWidth ) ) {\n slide.addCell( cell );\n } else {\n // doesn't fit, new slide\n slide.updateTarget();\n\n slide = new Slide( this );\n this.slides.push( slide );\n slide.addCell( cell );\n }\n }, this );\n // last slide\n slide.updateTarget();\n // update .selectedSlide\n this.updateSelectedSlide();\n};\n\nproto._getCanCellFit = function() {\n var groupCells = this.options.groupCells;\n if ( !groupCells ) {\n return function() {\n return false;\n };\n } else if ( typeof groupCells == 'number' ) {\n // group by number. 3 -> [0,1,2], [3,4,5], ...\n var number = parseInt( groupCells, 10 );\n return function( i ) {\n return ( i % number ) !== 0;\n };\n }\n // default, group by width of slide\n // parse '75%\n var percentMatch = typeof groupCells == 'string' &&\n groupCells.match( /^(\\d+)%$/ );\n var percent = percentMatch ? parseInt( percentMatch[1], 10 ) / 100 : 1;\n return function( i, slideWidth ) {\n /* eslint-disable-next-line no-invalid-this */\n return slideWidth <= ( this.size.innerWidth + 1 ) * percent;\n };\n};\n\n// alias _init for jQuery plugin .flickity()\nproto._init =\nproto.reposition = function() {\n this.positionCells();\n this.positionSliderAtSelected();\n};\n\nproto.getSize = function() {\n this.size = getSize( this.element );\n this.setCellAlign();\n this.cursorPosition = this.size.innerWidth * this.cellAlign;\n};\n\nvar cellAlignShorthands = {\n // cell align, then based on origin side\n center: {\n left: 0.5,\n right: 0.5,\n },\n left: {\n left: 0,\n right: 1,\n },\n right: {\n right: 0,\n left: 1,\n },\n};\n\nproto.setCellAlign = function() {\n var shorthand = cellAlignShorthands[ this.options.cellAlign ];\n this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign;\n};\n\nproto.setGallerySize = function() {\n if ( this.options.setGallerySize ) {\n var height = this.options.adaptiveHeight && this.selectedSlide ?\n this.selectedSlide.height : this.maxCellHeight;\n this.viewport.style.height = height + 'px';\n }\n};\n\nproto._getWrapShiftCells = function() {\n // only for wrap-around\n if ( !this.options.wrapAround ) {\n return;\n }\n // unshift previous cells\n this._unshiftCells( this.beforeShiftCells );\n this._unshiftCells( this.afterShiftCells );\n // get before cells\n // initial gap\n var gapX = this.cursorPosition;\n var cellIndex = this.cells.length - 1;\n this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 );\n // get after cells\n // ending gap between last cell and end of gallery viewport\n gapX = this.size.innerWidth - this.cursorPosition;\n // start cloning at first cell, working forwards\n this.afterShiftCells = this._getGapCells( gapX, 0, 1 );\n};\n\nproto._getGapCells = function( gapX, cellIndex, increment ) {\n // keep adding cells until the cover the initial gap\n var cells = [];\n while ( gapX > 0 ) {\n var cell = this.cells[ cellIndex ];\n if ( !cell ) {\n break;\n }\n cells.push( cell );\n cellIndex += increment;\n gapX -= cell.size.outerWidth;\n }\n return cells;\n};\n\n// ----- contain ----- //\n\n// contain cell targets so no excess sliding\nproto._containSlides = function() {\n if ( !this.options.contain || this.options.wrapAround || !this.cells.length ) {\n return;\n }\n var isRightToLeft = this.options.rightToLeft;\n var beginMargin = isRightToLeft ? 'marginRight' : 'marginLeft';\n var endMargin = isRightToLeft ? 'marginLeft' : 'marginRight';\n var contentWidth = this.slideableWidth - this.getLastCell().size[ endMargin ];\n // content is less than gallery size\n var isContentSmaller = contentWidth < this.size.innerWidth;\n // bounds\n var beginBound = this.cursorPosition + this.cells[0].size[ beginMargin ];\n var endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign );\n // contain each cell target\n this.slides.forEach( function( slide ) {\n if ( isContentSmaller ) {\n // all cells fit inside gallery\n slide.target = contentWidth * this.cellAlign;\n } else {\n // contain to bounds\n slide.target = Math.max( slide.target, beginBound );\n slide.target = Math.min( slide.target, endBound );\n }\n }, this );\n};\n\n// ----- ----- //\n\n/**\n * emits events via eventEmitter and jQuery events\n * @param {String} type - name of event\n * @param {Event} event - original event\n * @param {Array} args - extra arguments\n */\nproto.dispatchEvent = function( type, event, args ) {\n var emitArgs = event ? [ event ].concat( args ) : args;\n this.emitEvent( type, emitArgs );\n\n if ( jQuery && this.$element ) {\n // default trigger with type if no event\n type += this.options.namespaceJQueryEvents ? '.flickity' : '';\n var $event = type;\n if ( event ) {\n // create jQuery event\n var jQEvent = new jQuery.Event( event );\n jQEvent.type = type;\n $event = jQEvent;\n }\n this.$element.trigger( $event, args );\n }\n};\n\n// -------------------------- select -------------------------- //\n\n/**\n * @param {Integer} index - index of the slide\n * @param {Boolean} isWrap - will wrap-around to last/first if at the end\n * @param {Boolean} isInstant - will immediately set position at selected cell\n */\nproto.select = function( index, isWrap, isInstant ) {\n if ( !this.isActive ) {\n return;\n }\n index = parseInt( index, 10 );\n this._wrapSelect( index );\n\n if ( this.options.wrapAround || isWrap ) {\n index = utils.modulo( index, this.slides.length );\n }\n // bail if invalid index\n if ( !this.slides[ index ] ) {\n return;\n }\n var prevIndex = this.selectedIndex;\n this.selectedIndex = index;\n this.updateSelectedSlide();\n if ( isInstant ) {\n this.positionSliderAtSelected();\n } else {\n this.startAnimation();\n }\n if ( this.options.adaptiveHeight ) {\n this.setGallerySize();\n }\n // events\n this.dispatchEvent( 'select', null, [ index ] );\n // change event if new index\n if ( index != prevIndex ) {\n this.dispatchEvent( 'change', null, [ index ] );\n }\n // old v1 event name, remove in v3\n this.dispatchEvent('cellSelect');\n};\n\n// wraps position for wrapAround, to move to closest slide. #113\nproto._wrapSelect = function( index ) {\n var len = this.slides.length;\n var isWrapping = this.options.wrapAround && len > 1;\n if ( !isWrapping ) {\n return index;\n }\n var wrapIndex = utils.modulo( index, len );\n // go to shortest\n var delta = Math.abs( wrapIndex - this.selectedIndex );\n var backWrapDelta = Math.abs( ( wrapIndex + len ) - this.selectedIndex );\n var forewardWrapDelta = Math.abs( ( wrapIndex - len ) - this.selectedIndex );\n if ( !this.isDragSelect && backWrapDelta < delta ) {\n index += len;\n } else if ( !this.isDragSelect && forewardWrapDelta < delta ) {\n index -= len;\n }\n // wrap position so slider is within normal area\n if ( index < 0 ) {\n this.x -= this.slideableWidth;\n } else if ( index >= len ) {\n this.x += this.slideableWidth;\n }\n};\n\nproto.previous = function( isWrap, isInstant ) {\n this.select( this.selectedIndex - 1, isWrap, isInstant );\n};\n\nproto.next = function( isWrap, isInstant ) {\n this.select( this.selectedIndex + 1, isWrap, isInstant );\n};\n\nproto.updateSelectedSlide = function() {\n var slide = this.slides[ this.selectedIndex ];\n // selectedIndex could be outside of slides, if triggered before resize()\n if ( !slide ) {\n return;\n }\n // unselect previous selected slide\n this.unselectSelectedSlide();\n // update new selected slide\n this.selectedSlide = slide;\n slide.select();\n this.selectedCells = slide.cells;\n this.selectedElements = slide.getCellElements();\n // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility\n // Remove in v3?\n this.selectedCell = slide.cells[0];\n this.selectedElement = this.selectedElements[0];\n};\n\nproto.unselectSelectedSlide = function() {\n if ( this.selectedSlide ) {\n this.selectedSlide.unselect();\n }\n};\n\nproto.selectInitialIndex = function() {\n var initialIndex = this.options.initialIndex;\n // already activated, select previous selectedIndex\n if ( this.isInitActivated ) {\n this.select( this.selectedIndex, false, true );\n return;\n }\n // select with selector string\n if ( initialIndex && typeof initialIndex == 'string' ) {\n var cell = this.queryCell( initialIndex );\n if ( cell ) {\n this.selectCell( initialIndex, false, true );\n return;\n }\n }\n\n var index = 0;\n // select with number\n if ( initialIndex && this.slides[ initialIndex ] ) {\n index = initialIndex;\n }\n // select instantly\n this.select( index, false, true );\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, Number]} value - zero-based index or element to select\n * @param {Boolean} isWrap - enables wrapping around for extra index\n * @param {Boolean} isInstant - disables slide animation\n */\nproto.selectCell = function( value, isWrap, isInstant ) {\n // get cell\n var cell = this.queryCell( value );\n if ( !cell ) {\n return;\n }\n\n var index = this.getCellSlideIndex( cell );\n this.select( index, isWrap, isInstant );\n};\n\nproto.getCellSlideIndex = function( cell ) {\n // get index of slides that has cell\n for ( var i = 0; i < this.slides.length; i++ ) {\n var slide = this.slides[i];\n var index = slide.cells.indexOf( cell );\n if ( index != -1 ) {\n return i;\n }\n }\n};\n\n// -------------------------- get cells -------------------------- //\n\n/**\n * get Flickity.Cell, given an Element\n * @param {Element} elem - matching cell element\n * @returns {Flickity.Cell} cell - matching cell\n */\nproto.getCell = function( elem ) {\n // loop through cells to get the one that matches\n for ( var i = 0; i < this.cells.length; i++ ) {\n var cell = this.cells[i];\n if ( cell.element == elem ) {\n return cell;\n }\n }\n};\n\n/**\n * get collection of Flickity.Cells, given Elements\n * @param {[Element, Array, NodeList]} elems - multiple elements\n * @returns {Array} cells - Flickity.Cells\n */\nproto.getCells = function( elems ) {\n elems = utils.makeArray( elems );\n var cells = [];\n elems.forEach( function( elem ) {\n var cell = this.getCell( elem );\n if ( cell ) {\n cells.push( cell );\n }\n }, this );\n return cells;\n};\n\n/**\n * get cell elements\n * @returns {Array} cellElems\n */\nproto.getCellElements = function() {\n return this.cells.map( function( cell ) {\n return cell.element;\n } );\n};\n\n/**\n * get parent cell from an element\n * @param {Element} elem - child element\n * @returns {Flickit.Cell} cell - parent cell\n */\nproto.getParentCell = function( elem ) {\n // first check if elem is cell\n var cell = this.getCell( elem );\n if ( cell ) {\n return cell;\n }\n // try to get parent cell elem\n elem = utils.getParent( elem, '.flickity-slider > *' );\n return this.getCell( elem );\n};\n\n/**\n * get cells adjacent to a slide\n * @param {Integer} adjCount - number of adjacent slides\n * @param {Integer} index - index of slide to start\n * @returns {Array} cells - array of Flickity.Cells\n */\nproto.getAdjacentCellElements = function( adjCount, index ) {\n if ( !adjCount ) {\n return this.selectedSlide.getCellElements();\n }\n index = index === undefined ? this.selectedIndex : index;\n\n var len = this.slides.length;\n if ( 1 + ( adjCount * 2 ) >= len ) {\n return this.getCellElements();\n }\n\n var cellElems = [];\n for ( var i = index - adjCount; i <= index + adjCount; i++ ) {\n var slideIndex = this.options.wrapAround ? utils.modulo( i, len ) : i;\n var slide = this.slides[ slideIndex ];\n if ( slide ) {\n cellElems = cellElems.concat( slide.getCellElements() );\n }\n }\n return cellElems;\n};\n\n/**\n * select slide from number or cell element\n * @param {[Element, String, Number]} selector - element, selector string, or index\n * @returns {Flickity.Cell} - matching cell\n */\nproto.queryCell = function( selector ) {\n if ( typeof selector == 'number' ) {\n // use number as index\n return this.cells[ selector ];\n }\n if ( typeof selector == 'string' ) {\n // do not select invalid selectors from hash: #123, #/. #791\n if ( selector.match( /^[#.]?[\\d/]/ ) ) {\n return;\n }\n // use string as selector, get element\n selector = this.element.querySelector( selector );\n }\n // get cell from element\n return this.getCell( selector );\n};\n\n// -------------------------- events -------------------------- //\n\nproto.uiChange = function() {\n this.emitEvent('uiChange');\n};\n\n// keep focus on element when child UI elements are clicked\nproto.childUIPointerDown = function( event ) {\n // HACK iOS does not allow touch events to bubble up?!\n if ( event.type != 'touchstart' ) {\n event.preventDefault();\n }\n this.focus();\n};\n\n// ----- resize ----- //\n\nproto.onresize = function() {\n this.watchCSS();\n this.resize();\n};\n\nutils.debounceMethod( Flickity, 'onresize', 150 );\n\nproto.resize = function() {\n // #1177 disable resize behavior when animating or dragging for iOS 15\n if ( !this.isActive || this.isAnimating || this.isDragging ) {\n return;\n }\n this.getSize();\n // wrap values\n if ( this.options.wrapAround ) {\n this.x = utils.modulo( this.x, this.slideableWidth );\n }\n this.positionCells();\n this._getWrapShiftCells();\n this.setGallerySize();\n this.emitEvent('resize');\n // update selected index for group slides, instant\n // TODO: position can be lost between groups of various numbers\n var selectedElement = this.selectedElements && this.selectedElements[0];\n this.selectCell( selectedElement, false, true );\n};\n\n// watches the :after property, activates/deactivates\nproto.watchCSS = function() {\n var watchOption = this.options.watchCSS;\n if ( !watchOption ) {\n return;\n }\n\n var afterContent = getComputedStyle( this.element, ':after' ).content;\n // activate if :after { content: 'flickity' }\n if ( afterContent.indexOf('flickity') != -1 ) {\n this.activate();\n } else {\n this.deactivate();\n }\n};\n\n// ----- keydown ----- //\n\n// go previous/next if left/right keys pressed\nproto.onkeydown = function( event ) {\n // only work if element is in focus\n var isNotFocused = document.activeElement && document.activeElement != this.element;\n if ( !this.options.accessibility || isNotFocused ) {\n return;\n }\n\n var handler = Flickity.keyboardHandlers[ event.keyCode ];\n if ( handler ) {\n handler.call( this );\n }\n};\n\nFlickity.keyboardHandlers = {\n // left arrow\n 37: function() {\n var leftMethod = this.options.rightToLeft ? 'next' : 'previous';\n this.uiChange();\n this[ leftMethod ]();\n },\n // right arrow\n 39: function() {\n var rightMethod = this.options.rightToLeft ? 'previous' : 'next';\n this.uiChange();\n this[ rightMethod ]();\n },\n};\n\n// ----- focus ----- //\n\nproto.focus = function() {\n // TODO remove scrollTo once focus options gets more support\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus ...\n // #Browser_compatibility\n var prevScrollY = window.pageYOffset;\n this.element.focus({ preventScroll: true });\n // hack to fix scroll jump after focus, #76\n if ( window.pageYOffset != prevScrollY ) {\n window.scrollTo( window.pageXOffset, prevScrollY );\n }\n};\n\n// -------------------------- destroy -------------------------- //\n\n// deactivate all Flickity functionality, but keep stuff available\nproto.deactivate = function() {\n if ( !this.isActive ) {\n return;\n }\n this.element.classList.remove('flickity-enabled');\n this.element.classList.remove('flickity-rtl');\n this.unselectSelectedSlide();\n // destroy cells\n this.cells.forEach( function( cell ) {\n cell.destroy();\n } );\n this.element.removeChild( this.viewport );\n // move child elements back into element\n moveElements( this.slider.children, this.element );\n if ( this.options.accessibility ) {\n this.element.removeAttribute('tabIndex');\n this.element.removeEventListener( 'keydown', this );\n }\n // set flags\n this.isActive = false;\n this.emitEvent('deactivate');\n};\n\nproto.destroy = function() {\n this.deactivate();\n window.removeEventListener( 'resize', this );\n this.allOff();\n this.emitEvent('destroy');\n if ( jQuery && this.$element ) {\n jQuery.removeData( this.element, 'flickity' );\n }\n delete this.element.flickityGUID;\n delete instances[ this.guid ];\n};\n\n// -------------------------- prototype -------------------------- //\n\nutils.extend( proto, animatePrototype );\n\n// -------------------------- extras -------------------------- //\n\n/**\n * get Flickity instance from element\n * @param {[Element, String]} elem - element or selector string\n * @returns {Flickity} - Flickity instance\n */\nFlickity.data = function( elem ) {\n elem = utils.getQueryElement( elem );\n var id = elem && elem.flickityGUID;\n return id && instances[ id ];\n};\n\nutils.htmlInit( Flickity, 'flickity' );\n\nif ( jQuery && jQuery.bridget ) {\n jQuery.bridget( 'flickity', Flickity );\n}\n\n// set internal jQuery, for Webpack + jQuery v3, #478\nFlickity.setJQuery = function( jq ) {\n jQuery = jq;\n};\n\nFlickity.Cell = Cell;\nFlickity.Slide = Slide;\n\nreturn Flickity;\n\n} ) );\n\n/*!\n * Unipointer v2.4.0\n * base class for doing one thing with pointer event\n * MIT license\n */\n\n/*jshint browser: true, undef: true, unused: true, strict: true */\n\n( function( window, factory ) {\n // universal module definition\n /* jshint strict: false */ /*global define, module, require */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'unipointer/unipointer',[\n 'ev-emitter/ev-emitter'\n ], function( EvEmitter ) {\n return factory( window, EvEmitter );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('ev-emitter')\n );\n } else {\n // browser global\n window.Unipointer = factory(\n window,\n window.EvEmitter\n );\n }\n\n}( window, function factory( window, EvEmitter ) {\n\n\n\nfunction noop() {}\n\nfunction Unipointer() {}\n\n// inherit EvEmitter\nvar proto = Unipointer.prototype = Object.create( EvEmitter.prototype );\n\nproto.bindStartEvent = function( elem ) {\n this._bindStartEvent( elem, true );\n};\n\nproto.unbindStartEvent = function( elem ) {\n this._bindStartEvent( elem, false );\n};\n\n/**\n * Add or remove start event\n * @param {Boolean} isAdd - remove if falsey\n */\nproto._bindStartEvent = function( elem, isAdd ) {\n // munge isAdd, default to true\n isAdd = isAdd === undefined ? true : isAdd;\n var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';\n\n // default to mouse events\n var startEvent = 'mousedown';\n if ( 'ontouchstart' in window ) {\n // HACK prefer Touch Events as you can preventDefault on touchstart to\n // disable scroll in iOS & mobile Chrome metafizzy/flickity#1177\n startEvent = 'touchstart';\n } else if ( window.PointerEvent ) {\n // Pointer Events\n startEvent = 'pointerdown';\n }\n elem[ bindMethod ]( startEvent, this );\n};\n\n// trigger handler methods for events\nproto.handleEvent = function( event ) {\n var method = 'on' + event.type;\n if ( this[ method ] ) {\n this[ method ]( event );\n }\n};\n\n// returns the touch that we're keeping track of\nproto.getTouch = function( touches ) {\n for ( var i=0; i < touches.length; i++ ) {\n var touch = touches[i];\n if ( touch.identifier == this.pointerIdentifier ) {\n return touch;\n }\n }\n};\n\n// ----- start event ----- //\n\nproto.onmousedown = function( event ) {\n // dismiss clicks from right or middle buttons\n var button = event.button;\n if ( button && ( button !== 0 && button !== 1 ) ) {\n return;\n }\n this._pointerDown( event, event );\n};\n\nproto.ontouchstart = function( event ) {\n this._pointerDown( event, event.changedTouches[0] );\n};\n\nproto.onpointerdown = function( event ) {\n this._pointerDown( event, event );\n};\n\n/**\n * pointer start\n * @param {Event} event\n * @param {Event or Touch} pointer\n */\nproto._pointerDown = function( event, pointer ) {\n // dismiss right click and other pointers\n // button = 0 is okay, 1-4 not\n if ( event.button || this.isPointerDown ) {\n return;\n }\n\n this.isPointerDown = true;\n // save pointer identifier to match up touch events\n this.pointerIdentifier = pointer.pointerId !== undefined ?\n // pointerId for pointer events, touch.indentifier for touch events\n pointer.pointerId : pointer.identifier;\n\n this.pointerDown( event, pointer );\n};\n\nproto.pointerDown = function( event, pointer ) {\n this._bindPostStartEvents( event );\n this.emitEvent( 'pointerDown', [ event, pointer ] );\n};\n\n// hash of events to be bound after start event\nvar postStartEvents = {\n mousedown: [ 'mousemove', 'mouseup' ],\n touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],\n pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],\n};\n\nproto._bindPostStartEvents = function( event ) {\n if ( !event ) {\n return;\n }\n // get proper events to match start event\n var events = postStartEvents[ event.type ];\n // bind events to node\n events.forEach( function( eventName ) {\n window.addEventListener( eventName, this );\n }, this );\n // save these arguments\n this._boundPointerEvents = events;\n};\n\nproto._unbindPostStartEvents = function() {\n // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)\n if ( !this._boundPointerEvents ) {\n return;\n }\n this._boundPointerEvents.forEach( function( eventName ) {\n window.removeEventListener( eventName, this );\n }, this );\n\n delete this._boundPointerEvents;\n};\n\n// ----- move event ----- //\n\nproto.onmousemove = function( event ) {\n this._pointerMove( event, event );\n};\n\nproto.onpointermove = function( event ) {\n if ( event.pointerId == this.pointerIdentifier ) {\n this._pointerMove( event, event );\n }\n};\n\nproto.ontouchmove = function( event ) {\n var touch = this.getTouch( event.changedTouches );\n if ( touch ) {\n this._pointerMove( event, touch );\n }\n};\n\n/**\n * pointer move\n * @param {Event} event\n * @param {Event or Touch} pointer\n * @private\n */\nproto._pointerMove = function( event, pointer ) {\n this.pointerMove( event, pointer );\n};\n\n// public\nproto.pointerMove = function( event, pointer ) {\n this.emitEvent( 'pointerMove', [ event, pointer ] );\n};\n\n// ----- end event ----- //\n\n\nproto.onmouseup = function( event ) {\n this._pointerUp( event, event );\n};\n\nproto.onpointerup = function( event ) {\n if ( event.pointerId == this.pointerIdentifier ) {\n this._pointerUp( event, event );\n }\n};\n\nproto.ontouchend = function( event ) {\n var touch = this.getTouch( event.changedTouches );\n if ( touch ) {\n this._pointerUp( event, touch );\n }\n};\n\n/**\n * pointer up\n * @param {Event} event\n * @param {Event or Touch} pointer\n * @private\n */\nproto._pointerUp = function( event, pointer ) {\n this._pointerDone();\n this.pointerUp( event, pointer );\n};\n\n// public\nproto.pointerUp = function( event, pointer ) {\n this.emitEvent( 'pointerUp', [ event, pointer ] );\n};\n\n// ----- pointer done ----- //\n\n// triggered on pointer up & pointer cancel\nproto._pointerDone = function() {\n this._pointerReset();\n this._unbindPostStartEvents();\n this.pointerDone();\n};\n\nproto._pointerReset = function() {\n // reset properties\n this.isPointerDown = false;\n delete this.pointerIdentifier;\n};\n\nproto.pointerDone = noop;\n\n// ----- pointer cancel ----- //\n\nproto.onpointercancel = function( event ) {\n if ( event.pointerId == this.pointerIdentifier ) {\n this._pointerCancel( event, event );\n }\n};\n\nproto.ontouchcancel = function( event ) {\n var touch = this.getTouch( event.changedTouches );\n if ( touch ) {\n this._pointerCancel( event, touch );\n }\n};\n\n/**\n * pointer cancel\n * @param {Event} event\n * @param {Event or Touch} pointer\n * @private\n */\nproto._pointerCancel = function( event, pointer ) {\n this._pointerDone();\n this.pointerCancel( event, pointer );\n};\n\n// public\nproto.pointerCancel = function( event, pointer ) {\n this.emitEvent( 'pointerCancel', [ event, pointer ] );\n};\n\n// ----- ----- //\n\n// utility function for getting x/y coords from event\nUnipointer.getPointerPoint = function( pointer ) {\n return {\n x: pointer.pageX,\n y: pointer.pageY\n };\n};\n\n// ----- ----- //\n\nreturn Unipointer;\n\n}));\n\n/*!\n * Unidragger v2.4.0\n * Draggable base class\n * MIT license\n */\n\n/*jshint browser: true, unused: true, undef: true, strict: true */\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */ /*globals define, module, require */\n\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'unidragger/unidragger',[\n 'unipointer/unipointer'\n ], function( Unipointer ) {\n return factory( window, Unipointer );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('unipointer')\n );\n } else {\n // browser global\n window.Unidragger = factory(\n window,\n window.Unipointer\n );\n }\n\n}( window, function factory( window, Unipointer ) {\n\n\n\n// -------------------------- Unidragger -------------------------- //\n\nfunction Unidragger() {}\n\n// inherit Unipointer & EvEmitter\nvar proto = Unidragger.prototype = Object.create( Unipointer.prototype );\n\n// ----- bind start ----- //\n\nproto.bindHandles = function() {\n this._bindHandles( true );\n};\n\nproto.unbindHandles = function() {\n this._bindHandles( false );\n};\n\n/**\n * Add or remove start event\n * @param {Boolean} isAdd\n */\nproto._bindHandles = function( isAdd ) {\n // munge isAdd, default to true\n isAdd = isAdd === undefined ? true : isAdd;\n // bind each handle\n var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';\n var touchAction = isAdd ? this._touchActionValue : '';\n for ( var i=0; i < this.handles.length; i++ ) {\n var handle = this.handles[i];\n this._bindStartEvent( handle, isAdd );\n handle[ bindMethod ]( 'click', this );\n // touch-action: none to override browser touch gestures. metafizzy/flickity#540\n if ( window.PointerEvent ) {\n handle.style.touchAction = touchAction;\n }\n }\n};\n\n// prototype so it can be overwriteable by Flickity\nproto._touchActionValue = 'none';\n\n// ----- start event ----- //\n\n/**\n * pointer start\n * @param {Event} event\n * @param {Event or Touch} pointer\n */\nproto.pointerDown = function( event, pointer ) {\n var isOkay = this.okayPointerDown( event );\n if ( !isOkay ) {\n return;\n }\n // track start event position\n // Safari 9 overrides pageX and pageY. These values needs to be copied. flickity#842\n this.pointerDownPointer = {\n pageX: pointer.pageX,\n pageY: pointer.pageY,\n };\n\n event.preventDefault();\n this.pointerDownBlur();\n // bind move and end events\n this._bindPostStartEvents( event );\n this.emitEvent( 'pointerDown', [ event, pointer ] );\n};\n\n// nodes that have text fields\nvar cursorNodes = {\n TEXTAREA: true,\n INPUT: true,\n SELECT: true,\n OPTION: true,\n};\n\n// input types that do not have text fields\nvar clickTypes = {\n radio: true,\n checkbox: true,\n button: true,\n submit: true,\n image: true,\n file: true,\n};\n\n// dismiss inputs with text fields. flickity#403, flickity#404\nproto.okayPointerDown = function( event ) {\n var isCursorNode = cursorNodes[ event.target.nodeName ];\n var isClickType = clickTypes[ event.target.type ];\n var isOkay = !isCursorNode || isClickType;\n if ( !isOkay ) {\n this._pointerReset();\n }\n return isOkay;\n};\n\n// kludge to blur previously focused input\nproto.pointerDownBlur = function() {\n var focused = document.activeElement;\n // do not blur body for IE10, metafizzy/flickity#117\n var canBlur = focused && focused.blur && focused != document.body;\n if ( canBlur ) {\n focused.blur();\n }\n};\n\n// ----- move event ----- //\n\n/**\n * drag move\n * @param {Event} event\n * @param {Event or Touch} pointer\n */\nproto.pointerMove = function( event, pointer ) {\n var moveVector = this._dragPointerMove( event, pointer );\n this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );\n this._dragMove( event, pointer, moveVector );\n};\n\n// base pointer move logic\nproto._dragPointerMove = function( event, pointer ) {\n var moveVector = {\n x: pointer.pageX - this.pointerDownPointer.pageX,\n y: pointer.pageY - this.pointerDownPointer.pageY\n };\n // start drag if pointer has moved far enough to start drag\n if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {\n this._dragStart( event, pointer );\n }\n return moveVector;\n};\n\n// condition if pointer has moved far enough to start drag\nproto.hasDragStarted = function( moveVector ) {\n return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;\n};\n\n// ----- end event ----- //\n\n/**\n * pointer up\n * @param {Event} event\n * @param {Event or Touch} pointer\n */\nproto.pointerUp = function( event, pointer ) {\n this.emitEvent( 'pointerUp', [ event, pointer ] );\n this._dragPointerUp( event, pointer );\n};\n\nproto._dragPointerUp = function( event, pointer ) {\n if ( this.isDragging ) {\n this._dragEnd( event, pointer );\n } else {\n // pointer didn't move enough for drag to start\n this._staticClick( event, pointer );\n }\n};\n\n// -------------------------- drag -------------------------- //\n\n// dragStart\nproto._dragStart = function( event, pointer ) {\n this.isDragging = true;\n // prevent clicks\n this.isPreventingClicks = true;\n this.dragStart( event, pointer );\n};\n\nproto.dragStart = function( event, pointer ) {\n this.emitEvent( 'dragStart', [ event, pointer ] );\n};\n\n// dragMove\nproto._dragMove = function( event, pointer, moveVector ) {\n // do not drag if not dragging yet\n if ( !this.isDragging ) {\n return;\n }\n\n this.dragMove( event, pointer, moveVector );\n};\n\nproto.dragMove = function( event, pointer, moveVector ) {\n event.preventDefault();\n this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );\n};\n\n// dragEnd\nproto._dragEnd = function( event, pointer ) {\n // set flags\n this.isDragging = false;\n // re-enable clicking async\n setTimeout( function() {\n delete this.isPreventingClicks;\n }.bind( this ) );\n\n this.dragEnd( event, pointer );\n};\n\nproto.dragEnd = function( event, pointer ) {\n this.emitEvent( 'dragEnd', [ event, pointer ] );\n};\n\n// ----- onclick ----- //\n\n// handle all clicks and prevent clicks when dragging\nproto.onclick = function( event ) {\n if ( this.isPreventingClicks ) {\n event.preventDefault();\n }\n};\n\n// ----- staticClick ----- //\n\n// triggered after pointer down & up with no/tiny movement\nproto._staticClick = function( event, pointer ) {\n // ignore emulated mouse up clicks\n if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {\n return;\n }\n\n this.staticClick( event, pointer );\n\n // set flag for emulated clicks 300ms after touchend\n if ( event.type != 'mouseup' ) {\n this.isIgnoringMouseUp = true;\n // reset flag after 300ms\n setTimeout( function() {\n delete this.isIgnoringMouseUp;\n }.bind( this ), 400 );\n }\n};\n\nproto.staticClick = function( event, pointer ) {\n this.emitEvent( 'staticClick', [ event, pointer ] );\n};\n\n// ----- utils ----- //\n\nUnidragger.getPointerPoint = Unipointer.getPointerPoint;\n\n// ----- ----- //\n\nreturn Unidragger;\n\n}));\n\n// drag\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/drag',[\n './flickity',\n 'unidragger/unidragger',\n 'fizzy-ui-utils/utils',\n ], function( Flickity, Unidragger, utils ) {\n return factory( window, Flickity, Unidragger, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('./flickity'),\n require('unidragger'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n window.Flickity = factory(\n window,\n window.Flickity,\n window.Unidragger,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, Flickity, Unidragger, utils ) {\n\n\n\n// ----- defaults ----- //\n\nutils.extend( Flickity.defaults, {\n draggable: '>1',\n dragThreshold: 3,\n} );\n\n// ----- create ----- //\n\nFlickity.createMethods.push('_createDrag');\n\n// -------------------------- drag prototype -------------------------- //\n\nvar proto = Flickity.prototype;\nutils.extend( proto, Unidragger.prototype );\nproto._touchActionValue = 'pan-y';\n\n// -------------------------- -------------------------- //\n\nproto._createDrag = function() {\n this.on( 'activate', this.onActivateDrag );\n this.on( 'uiChange', this._uiChangeDrag );\n this.on( 'deactivate', this.onDeactivateDrag );\n this.on( 'cellChange', this.updateDraggable );\n // TODO updateDraggable on resize? if groupCells & slides change\n};\n\nproto.onActivateDrag = function() {\n this.handles = [ this.viewport ];\n this.bindHandles();\n this.updateDraggable();\n};\n\nproto.onDeactivateDrag = function() {\n this.unbindHandles();\n this.element.classList.remove('is-draggable');\n};\n\nproto.updateDraggable = function() {\n // disable dragging if less than 2 slides. #278\n if ( this.options.draggable == '>1' ) {\n this.isDraggable = this.slides.length > 1;\n } else {\n this.isDraggable = this.options.draggable;\n }\n if ( this.isDraggable ) {\n this.element.classList.add('is-draggable');\n } else {\n this.element.classList.remove('is-draggable');\n }\n};\n\n// backwards compatibility\nproto.bindDrag = function() {\n this.options.draggable = true;\n this.updateDraggable();\n};\n\nproto.unbindDrag = function() {\n this.options.draggable = false;\n this.updateDraggable();\n};\n\nproto._uiChangeDrag = function() {\n delete this.isFreeScrolling;\n};\n\n// -------------------------- pointer events -------------------------- //\n\nproto.pointerDown = function( event, pointer ) {\n if ( !this.isDraggable ) {\n this._pointerDownDefault( event, pointer );\n return;\n }\n var isOkay = this.okayPointerDown( event );\n if ( !isOkay ) {\n return;\n }\n\n this._pointerDownPreventDefault( event );\n this.pointerDownFocus( event );\n // blur\n if ( document.activeElement != this.element ) {\n // do not blur if already focused\n this.pointerDownBlur();\n }\n\n // stop if it was moving\n this.dragX = this.x;\n this.viewport.classList.add('is-pointer-down');\n // track scrolling\n this.pointerDownScroll = getScrollPosition();\n window.addEventListener( 'scroll', this );\n\n this._pointerDownDefault( event, pointer );\n};\n\n// default pointerDown logic, used for staticClick\nproto._pointerDownDefault = function( event, pointer ) {\n // track start event position\n // Safari 9 overrides pageX and pageY. These values needs to be copied. #779\n this.pointerDownPointer = {\n pageX: pointer.pageX,\n pageY: pointer.pageY,\n };\n // bind move and end events\n this._bindPostStartEvents( event );\n this.dispatchEvent( 'pointerDown', event, [ pointer ] );\n};\n\nvar focusNodes = {\n INPUT: true,\n TEXTAREA: true,\n SELECT: true,\n};\n\nproto.pointerDownFocus = function( event ) {\n var isFocusNode = focusNodes[ event.target.nodeName ];\n if ( !isFocusNode ) {\n this.focus();\n }\n};\n\nproto._pointerDownPreventDefault = function( event ) {\n var isTouchStart = event.type == 'touchstart';\n var isTouchPointer = event.pointerType == 'touch';\n var isFocusNode = focusNodes[ event.target.nodeName ];\n if ( !isTouchStart && !isTouchPointer && !isFocusNode ) {\n event.preventDefault();\n }\n};\n\n// ----- move ----- //\n\nproto.hasDragStarted = function( moveVector ) {\n return Math.abs( moveVector.x ) > this.options.dragThreshold;\n};\n\n// ----- up ----- //\n\nproto.pointerUp = function( event, pointer ) {\n delete this.isTouchScrolling;\n this.viewport.classList.remove('is-pointer-down');\n this.dispatchEvent( 'pointerUp', event, [ pointer ] );\n this._dragPointerUp( event, pointer );\n};\n\nproto.pointerDone = function() {\n window.removeEventListener( 'scroll', this );\n delete this.pointerDownScroll;\n};\n\n// -------------------------- dragging -------------------------- //\n\nproto.dragStart = function( event, pointer ) {\n if ( !this.isDraggable ) {\n return;\n }\n this.dragStartPosition = this.x;\n this.startAnimation();\n window.removeEventListener( 'scroll', this );\n this.dispatchEvent( 'dragStart', event, [ pointer ] );\n};\n\nproto.pointerMove = function( event, pointer ) {\n var moveVector = this._dragPointerMove( event, pointer );\n this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );\n this._dragMove( event, pointer, moveVector );\n};\n\nproto.dragMove = function( event, pointer, moveVector ) {\n if ( !this.isDraggable ) {\n return;\n }\n event.preventDefault();\n\n this.previousDragX = this.dragX;\n // reverse if right-to-left\n var direction = this.options.rightToLeft ? -1 : 1;\n if ( this.options.wrapAround ) {\n // wrap around move. #589\n moveVector.x %= this.slideableWidth;\n }\n var dragX = this.dragStartPosition + moveVector.x * direction;\n\n if ( !this.options.wrapAround && this.slides.length ) {\n // slow drag\n var originBound = Math.max( -this.slides[0].target, this.dragStartPosition );\n dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX;\n var endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition );\n dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX;\n }\n\n this.dragX = dragX;\n\n this.dragMoveTime = new Date();\n this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );\n};\n\nproto.dragEnd = function( event, pointer ) {\n if ( !this.isDraggable ) {\n return;\n }\n if ( this.options.freeScroll ) {\n this.isFreeScrolling = true;\n }\n // set selectedIndex based on where flick will end up\n var index = this.dragEndRestingSelect();\n\n if ( this.options.freeScroll && !this.options.wrapAround ) {\n // if free-scroll & not wrap around\n // do not free-scroll if going outside of bounding slides\n // so bounding slides can attract slider, and keep it in bounds\n var restingX = this.getRestingPosition();\n this.isFreeScrolling = -restingX > this.slides[0].target &&\n -restingX < this.getLastSlide().target;\n } else if ( !this.options.freeScroll && index == this.selectedIndex ) {\n // boost selection if selected index has not changed\n index += this.dragEndBoostSelect();\n }\n delete this.previousDragX;\n // apply selection\n // TODO refactor this, selecting here feels weird\n // HACK, set flag so dragging stays in correct direction\n this.isDragSelect = this.options.wrapAround;\n this.select( index );\n delete this.isDragSelect;\n this.dispatchEvent( 'dragEnd', event, [ pointer ] );\n};\n\nproto.dragEndRestingSelect = function() {\n var restingX = this.getRestingPosition();\n // how far away from selected slide\n var distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) );\n // get closet resting going up and going down\n var positiveResting = this._getClosestResting( restingX, distance, 1 );\n var negativeResting = this._getClosestResting( restingX, distance, -1 );\n // use closer resting for wrap-around\n var index = positiveResting.distance < negativeResting.distance ?\n positiveResting.index : negativeResting.index;\n return index;\n};\n\n/**\n * given resting X and distance to selected cell\n * get the distance and index of the closest cell\n * @param {Number} restingX - estimated post-flick resting position\n * @param {Number} distance - distance to selected cell\n * @param {Integer} increment - +1 or -1, going up or down\n * @returns {Object} - { distance: {Number}, index: {Integer} }\n */\nproto._getClosestResting = function( restingX, distance, increment ) {\n var index = this.selectedIndex;\n var minDistance = Infinity;\n var condition = this.options.contain && !this.options.wrapAround ?\n // if contain, keep going if distance is equal to minDistance\n function( dist, minDist ) {\n return dist <= minDist;\n } : function( dist, minDist ) {\n return dist < minDist;\n };\n while ( condition( distance, minDistance ) ) {\n // measure distance to next cell\n index += increment;\n minDistance = distance;\n distance = this.getSlideDistance( -restingX, index );\n if ( distance === null ) {\n break;\n }\n distance = Math.abs( distance );\n }\n return {\n distance: minDistance,\n // selected was previous index\n index: index - increment,\n };\n};\n\n/**\n * measure distance between x and a slide target\n * @param {Number} x - horizontal position\n * @param {Integer} index - slide index\n * @returns {Number} - slide distance\n */\nproto.getSlideDistance = function( x, index ) {\n var len = this.slides.length;\n // wrap around if at least 2 slides\n var isWrapAround = this.options.wrapAround && len > 1;\n var slideIndex = isWrapAround ? utils.modulo( index, len ) : index;\n var slide = this.slides[ slideIndex ];\n if ( !slide ) {\n return null;\n }\n // add distance for wrap-around slides\n var wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0;\n return x - ( slide.target + wrap );\n};\n\nproto.dragEndBoostSelect = function() {\n // do not boost if no previousDragX or dragMoveTime\n if ( this.previousDragX === undefined || !this.dragMoveTime ||\n // or if drag was held for 100 ms\n new Date() - this.dragMoveTime > 100 ) {\n return 0;\n }\n\n var distance = this.getSlideDistance( -this.dragX, this.selectedIndex );\n var delta = this.previousDragX - this.dragX;\n if ( distance > 0 && delta > 0 ) {\n // boost to next if moving towards the right, and positive velocity\n return 1;\n } else if ( distance < 0 && delta < 0 ) {\n // boost to previous if moving towards the left, and negative velocity\n return -1;\n }\n return 0;\n};\n\n// ----- staticClick ----- //\n\nproto.staticClick = function( event, pointer ) {\n // get clickedCell, if cell was clicked\n var clickedCell = this.getParentCell( event.target );\n var cellElem = clickedCell && clickedCell.element;\n var cellIndex = clickedCell && this.cells.indexOf( clickedCell );\n this.dispatchEvent( 'staticClick', event, [ pointer, cellElem, cellIndex ] );\n};\n\n// ----- scroll ----- //\n\nproto.onscroll = function() {\n var scroll = getScrollPosition();\n var scrollMoveX = this.pointerDownScroll.x - scroll.x;\n var scrollMoveY = this.pointerDownScroll.y - scroll.y;\n // cancel click/tap if scroll is too much\n if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) {\n this._pointerDone();\n }\n};\n\n// ----- utils ----- //\n\nfunction getScrollPosition() {\n return {\n x: window.pageXOffset,\n y: window.pageYOffset,\n };\n}\n\n// ----- ----- //\n\nreturn Flickity;\n\n} ) );\n\n// prev/next buttons\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/prev-next-button',[\n './flickity',\n 'unipointer/unipointer',\n 'fizzy-ui-utils/utils',\n ], function( Flickity, Unipointer, utils ) {\n return factory( window, Flickity, Unipointer, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('./flickity'),\n require('unipointer'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n factory(\n window,\n window.Flickity,\n window.Unipointer,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, Flickity, Unipointer, utils ) {\n'use strict';\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\n// -------------------------- PrevNextButton -------------------------- //\n\nfunction PrevNextButton( direction, parent ) {\n this.direction = direction;\n this.parent = parent;\n this._create();\n}\n\nPrevNextButton.prototype = Object.create( Unipointer.prototype );\n\nPrevNextButton.prototype._create = function() {\n // properties\n this.isEnabled = true;\n this.isPrevious = this.direction == -1;\n var leftDirection = this.parent.options.rightToLeft ? 1 : -1;\n this.isLeft = this.direction == leftDirection;\n\n var element = this.element = document.createElement('button');\n element.className = 'flickity-button flickity-prev-next-button';\n element.className += this.isPrevious ? ' previous' : ' next';\n // prevent button from submitting form http://stackoverflow.com/a/10836076/182183\n element.setAttribute( 'type', 'button' );\n // init as disabled\n this.disable();\n\n element.setAttribute( 'aria-label', this.isPrevious ? 'Previous' : 'Next' );\n\n // create arrow\n var svg = this.createSVG();\n element.appendChild( svg );\n // events\n this.parent.on( 'select', this.update.bind( this ) );\n this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );\n};\n\nPrevNextButton.prototype.activate = function() {\n this.bindStartEvent( this.element );\n this.element.addEventListener( 'click', this );\n // add to DOM\n this.parent.element.appendChild( this.element );\n};\n\nPrevNextButton.prototype.deactivate = function() {\n // remove from DOM\n this.parent.element.removeChild( this.element );\n // click events\n this.unbindStartEvent( this.element );\n this.element.removeEventListener( 'click', this );\n};\n\nPrevNextButton.prototype.createSVG = function() {\n var svg = document.createElementNS( svgURI, 'svg' );\n svg.setAttribute( 'class', 'flickity-button-icon' );\n svg.setAttribute( 'viewBox', '0 0 100 100' );\n var path = document.createElementNS( svgURI, 'path' );\n var pathMovements = getArrowMovements( this.parent.options.arrowShape );\n path.setAttribute( 'd', pathMovements );\n path.setAttribute( 'class', 'arrow' );\n // rotate arrow\n if ( !this.isLeft ) {\n path.setAttribute( 'transform', 'translate(100, 100) rotate(180) ' );\n }\n svg.appendChild( path );\n return svg;\n};\n\n// get SVG path movmement\nfunction getArrowMovements( shape ) {\n // use shape as movement if string\n if ( typeof shape == 'string' ) {\n return shape;\n }\n // create movement string\n return 'M ' + shape.x0 + ',50' +\n ' L ' + shape.x1 + ',' + ( shape.y1 + 50 ) +\n ' L ' + shape.x2 + ',' + ( shape.y2 + 50 ) +\n ' L ' + shape.x3 + ',50 ' +\n ' L ' + shape.x2 + ',' + ( 50 - shape.y2 ) +\n ' L ' + shape.x1 + ',' + ( 50 - shape.y1 ) +\n ' Z';\n}\n\nPrevNextButton.prototype.handleEvent = utils.handleEvent;\n\nPrevNextButton.prototype.onclick = function() {\n if ( !this.isEnabled ) {\n return;\n }\n this.parent.uiChange();\n var method = this.isPrevious ? 'previous' : 'next';\n this.parent[ method ]();\n};\n\n// ----- ----- //\n\nPrevNextButton.prototype.enable = function() {\n if ( this.isEnabled ) {\n return;\n }\n this.element.disabled = false;\n this.isEnabled = true;\n};\n\nPrevNextButton.prototype.disable = function() {\n if ( !this.isEnabled ) {\n return;\n }\n this.element.disabled = true;\n this.isEnabled = false;\n};\n\nPrevNextButton.prototype.update = function() {\n // index of first or last slide, if previous or next\n var slides = this.parent.slides;\n // enable is wrapAround and at least 2 slides\n if ( this.parent.options.wrapAround && slides.length > 1 ) {\n this.enable();\n return;\n }\n var lastIndex = slides.length ? slides.length - 1 : 0;\n var boundIndex = this.isPrevious ? 0 : lastIndex;\n var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable';\n this[ method ]();\n};\n\nPrevNextButton.prototype.destroy = function() {\n this.deactivate();\n this.allOff();\n};\n\n// -------------------------- Flickity prototype -------------------------- //\n\nutils.extend( Flickity.defaults, {\n prevNextButtons: true,\n arrowShape: {\n x0: 10,\n x1: 60, y1: 50,\n x2: 70, y2: 40,\n x3: 30,\n },\n} );\n\nFlickity.createMethods.push('_createPrevNextButtons');\nvar proto = Flickity.prototype;\n\nproto._createPrevNextButtons = function() {\n if ( !this.options.prevNextButtons ) {\n return;\n }\n\n this.prevButton = new PrevNextButton( -1, this );\n this.nextButton = new PrevNextButton( 1, this );\n\n this.on( 'activate', this.activatePrevNextButtons );\n};\n\nproto.activatePrevNextButtons = function() {\n this.prevButton.activate();\n this.nextButton.activate();\n this.on( 'deactivate', this.deactivatePrevNextButtons );\n};\n\nproto.deactivatePrevNextButtons = function() {\n this.prevButton.deactivate();\n this.nextButton.deactivate();\n this.off( 'deactivate', this.deactivatePrevNextButtons );\n};\n\n// -------------------------- -------------------------- //\n\nFlickity.PrevNextButton = PrevNextButton;\n\nreturn Flickity;\n\n} ) );\n\n// page dots\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/page-dots',[\n './flickity',\n 'unipointer/unipointer',\n 'fizzy-ui-utils/utils',\n ], function( Flickity, Unipointer, utils ) {\n return factory( window, Flickity, Unipointer, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('./flickity'),\n require('unipointer'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n factory(\n window,\n window.Flickity,\n window.Unipointer,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, Flickity, Unipointer, utils ) {\n\n// -------------------------- PageDots -------------------------- //\n\n\n\nfunction PageDots( parent ) {\n this.parent = parent;\n this._create();\n}\n\nPageDots.prototype = Object.create( Unipointer.prototype );\n\nPageDots.prototype._create = function() {\n // create holder element\n this.holder = document.createElement('ol');\n this.holder.className = 'flickity-page-dots';\n // create dots, array of elements\n this.dots = [];\n // events\n this.handleClick = this.onClick.bind( this );\n this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) );\n};\n\nPageDots.prototype.activate = function() {\n this.setDots();\n this.holder.addEventListener( 'click', this.handleClick );\n this.bindStartEvent( this.holder );\n // add to DOM\n this.parent.element.appendChild( this.holder );\n};\n\nPageDots.prototype.deactivate = function() {\n this.holder.removeEventListener( 'click', this.handleClick );\n this.unbindStartEvent( this.holder );\n // remove from DOM\n this.parent.element.removeChild( this.holder );\n};\n\nPageDots.prototype.setDots = function() {\n // get difference between number of slides and number of dots\n var delta = this.parent.slides.length - this.dots.length;\n if ( delta > 0 ) {\n this.addDots( delta );\n } else if ( delta < 0 ) {\n this.removeDots( -delta );\n }\n};\n\nPageDots.prototype.addDots = function( count ) {\n var fragment = document.createDocumentFragment();\n var newDots = [];\n var length = this.dots.length;\n var max = length + count;\n\n for ( var i = length; i < max; i++ ) {\n var dot = document.createElement('li');\n dot.className = 'dot';\n dot.setAttribute( 'aria-label', 'Page dot ' + ( i + 1 ) );\n fragment.appendChild( dot );\n newDots.push( dot );\n }\n\n this.holder.appendChild( fragment );\n this.dots = this.dots.concat( newDots );\n};\n\nPageDots.prototype.removeDots = function( count ) {\n // remove from this.dots collection\n var removeDots = this.dots.splice( this.dots.length - count, count );\n // remove from DOM\n removeDots.forEach( function( dot ) {\n this.holder.removeChild( dot );\n }, this );\n};\n\nPageDots.prototype.updateSelected = function() {\n // remove selected class on previous\n if ( this.selectedDot ) {\n this.selectedDot.className = 'dot';\n this.selectedDot.removeAttribute('aria-current');\n }\n // don't proceed if no dots\n if ( !this.dots.length ) {\n return;\n }\n this.selectedDot = this.dots[ this.parent.selectedIndex ];\n this.selectedDot.className = 'dot is-selected';\n this.selectedDot.setAttribute( 'aria-current', 'step' );\n};\n\nPageDots.prototype.onTap = // old method name, backwards-compatible\nPageDots.prototype.onClick = function( event ) {\n var target = event.target;\n // only care about dot clicks\n if ( target.nodeName != 'LI' ) {\n return;\n }\n\n this.parent.uiChange();\n var index = this.dots.indexOf( target );\n this.parent.select( index );\n};\n\nPageDots.prototype.destroy = function() {\n this.deactivate();\n this.allOff();\n};\n\nFlickity.PageDots = PageDots;\n\n// -------------------------- Flickity -------------------------- //\n\nutils.extend( Flickity.defaults, {\n pageDots: true,\n} );\n\nFlickity.createMethods.push('_createPageDots');\n\nvar proto = Flickity.prototype;\n\nproto._createPageDots = function() {\n if ( !this.options.pageDots ) {\n return;\n }\n this.pageDots = new PageDots( this );\n // events\n this.on( 'activate', this.activatePageDots );\n this.on( 'select', this.updateSelectedPageDots );\n this.on( 'cellChange', this.updatePageDots );\n this.on( 'resize', this.updatePageDots );\n this.on( 'deactivate', this.deactivatePageDots );\n};\n\nproto.activatePageDots = function() {\n this.pageDots.activate();\n};\n\nproto.updateSelectedPageDots = function() {\n this.pageDots.updateSelected();\n};\n\nproto.updatePageDots = function() {\n this.pageDots.setDots();\n};\n\nproto.deactivatePageDots = function() {\n this.pageDots.deactivate();\n};\n\n// ----- ----- //\n\nFlickity.PageDots = PageDots;\n\nreturn Flickity;\n\n} ) );\n\n// player & autoPlay\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/player',[\n 'ev-emitter/ev-emitter',\n 'fizzy-ui-utils/utils',\n './flickity',\n ], function( EvEmitter, utils, Flickity ) {\n return factory( EvEmitter, utils, Flickity );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n require('ev-emitter'),\n require('fizzy-ui-utils'),\n require('./flickity')\n );\n } else {\n // browser global\n factory(\n window.EvEmitter,\n window.fizzyUIUtils,\n window.Flickity\n );\n }\n\n}( window, function factory( EvEmitter, utils, Flickity ) {\n\n\n\n// -------------------------- Player -------------------------- //\n\nfunction Player( parent ) {\n this.parent = parent;\n this.state = 'stopped';\n // visibility change event handler\n this.onVisibilityChange = this.visibilityChange.bind( this );\n this.onVisibilityPlay = this.visibilityPlay.bind( this );\n}\n\nPlayer.prototype = Object.create( EvEmitter.prototype );\n\n// start play\nPlayer.prototype.play = function() {\n if ( this.state == 'playing' ) {\n return;\n }\n // do not play if page is hidden, start playing when page is visible\n var isPageHidden = document.hidden;\n if ( isPageHidden ) {\n document.addEventListener( 'visibilitychange', this.onVisibilityPlay );\n return;\n }\n\n this.state = 'playing';\n // listen to visibility change\n document.addEventListener( 'visibilitychange', this.onVisibilityChange );\n // start ticking\n this.tick();\n};\n\nPlayer.prototype.tick = function() {\n // do not tick if not playing\n if ( this.state != 'playing' ) {\n return;\n }\n\n var time = this.parent.options.autoPlay;\n // default to 3 seconds\n time = typeof time == 'number' ? time : 3000;\n var _this = this;\n // HACK: reset ticks if stopped and started within interval\n this.clear();\n this.timeout = setTimeout( function() {\n _this.parent.next( true );\n _this.tick();\n }, time );\n};\n\nPlayer.prototype.stop = function() {\n this.state = 'stopped';\n this.clear();\n // remove visibility change event\n document.removeEventListener( 'visibilitychange', this.onVisibilityChange );\n};\n\nPlayer.prototype.clear = function() {\n clearTimeout( this.timeout );\n};\n\nPlayer.prototype.pause = function() {\n if ( this.state == 'playing' ) {\n this.state = 'paused';\n this.clear();\n }\n};\n\nPlayer.prototype.unpause = function() {\n // re-start play if paused\n if ( this.state == 'paused' ) {\n this.play();\n }\n};\n\n// pause if page visibility is hidden, unpause if visible\nPlayer.prototype.visibilityChange = function() {\n var isPageHidden = document.hidden;\n this[ isPageHidden ? 'pause' : 'unpause' ]();\n};\n\nPlayer.prototype.visibilityPlay = function() {\n this.play();\n document.removeEventListener( 'visibilitychange', this.onVisibilityPlay );\n};\n\n// -------------------------- Flickity -------------------------- //\n\nutils.extend( Flickity.defaults, {\n pauseAutoPlayOnHover: true,\n} );\n\nFlickity.createMethods.push('_createPlayer');\nvar proto = Flickity.prototype;\n\nproto._createPlayer = function() {\n this.player = new Player( this );\n\n this.on( 'activate', this.activatePlayer );\n this.on( 'uiChange', this.stopPlayer );\n this.on( 'pointerDown', this.stopPlayer );\n this.on( 'deactivate', this.deactivatePlayer );\n};\n\nproto.activatePlayer = function() {\n if ( !this.options.autoPlay ) {\n return;\n }\n this.player.play();\n this.element.addEventListener( 'mouseenter', this );\n};\n\n// Player API, don't hate the ... thanks I know where the door is\n\nproto.playPlayer = function() {\n this.player.play();\n};\n\nproto.stopPlayer = function() {\n this.player.stop();\n};\n\nproto.pausePlayer = function() {\n this.player.pause();\n};\n\nproto.unpausePlayer = function() {\n this.player.unpause();\n};\n\nproto.deactivatePlayer = function() {\n this.player.stop();\n this.element.removeEventListener( 'mouseenter', this );\n};\n\n// ----- mouseenter/leave ----- //\n\n// pause auto-play on hover\nproto.onmouseenter = function() {\n if ( !this.options.pauseAutoPlayOnHover ) {\n return;\n }\n this.player.pause();\n this.element.addEventListener( 'mouseleave', this );\n};\n\n// resume auto-play on hover off\nproto.onmouseleave = function() {\n this.player.unpause();\n this.element.removeEventListener( 'mouseleave', this );\n};\n\n// ----- ----- //\n\nFlickity.Player = Player;\n\nreturn Flickity;\n\n} ) );\n\n// add, remove cell\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/add-remove-cell',[\n './flickity',\n 'fizzy-ui-utils/utils',\n ], function( Flickity, utils ) {\n return factory( window, Flickity, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('./flickity'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n factory(\n window,\n window.Flickity,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, Flickity, utils ) {\n\n\n\n// append cells to a document fragment\nfunction getCellsFragment( cells ) {\n var fragment = document.createDocumentFragment();\n cells.forEach( function( cell ) {\n fragment.appendChild( cell.element );\n } );\n return fragment;\n}\n\n// -------------------------- add/remove cell prototype -------------------------- //\n\nvar proto = Flickity.prototype;\n\n/**\n * Insert, prepend, or append cells\n * @param {[Element, Array, NodeList]} elems - Elements to insert\n * @param {Integer} index - Zero-based number to insert\n */\nproto.insert = function( elems, index ) {\n var cells = this._makeCells( elems );\n if ( !cells || !cells.length ) {\n return;\n }\n var len = this.cells.length;\n // default to append\n index = index === undefined ? len : index;\n // add cells with document fragment\n var fragment = getCellsFragment( cells );\n // append to slider\n var isAppend = index == len;\n if ( isAppend ) {\n this.slider.appendChild( fragment );\n } else {\n var insertCellElement = this.cells[ index ].element;\n this.slider.insertBefore( fragment, insertCellElement );\n }\n // add to this.cells\n if ( index === 0 ) {\n // prepend, add to start\n this.cells = cells.concat( this.cells );\n } else if ( isAppend ) {\n // append, add to end\n this.cells = this.cells.concat( cells );\n } else {\n // insert in this.cells\n var endCells = this.cells.splice( index, len - index );\n this.cells = this.cells.concat( cells ).concat( endCells );\n }\n\n this._sizeCells( cells );\n this.cellChange( index, true );\n};\n\nproto.append = function( elems ) {\n this.insert( elems, this.cells.length );\n};\n\nproto.prepend = function( elems ) {\n this.insert( elems, 0 );\n};\n\n/**\n * Remove cells\n * @param {[Element, Array, NodeList]} elems - ELements to remove\n */\nproto.remove = function( elems ) {\n var cells = this.getCells( elems );\n if ( !cells || !cells.length ) {\n return;\n }\n\n var minCellIndex = this.cells.length - 1;\n // remove cells from collection & DOM\n cells.forEach( function( cell ) {\n cell.remove();\n var index = this.cells.indexOf( cell );\n minCellIndex = Math.min( index, minCellIndex );\n utils.removeFrom( this.cells, cell );\n }, this );\n\n this.cellChange( minCellIndex, true );\n};\n\n/**\n * logic to be run after a cell's size changes\n * @param {Element} elem - cell's element\n */\nproto.cellSizeChange = function( elem ) {\n var cell = this.getCell( elem );\n if ( !cell ) {\n return;\n }\n cell.getSize();\n\n var index = this.cells.indexOf( cell );\n this.cellChange( index );\n};\n\n/**\n * logic any time a cell is changed: added, removed, or size changed\n * @param {Integer} changedCellIndex - index of the changed cell, optional\n * @param {Boolean} isPositioningSlider - Positions slider after selection\n */\nproto.cellChange = function( changedCellIndex, isPositioningSlider ) {\n var prevSelectedElem = this.selectedElement;\n this._positionCells( changedCellIndex );\n this._getWrapShiftCells();\n this.setGallerySize();\n // update selectedIndex\n // try to maintain position & select previous selected element\n var cell = this.getCell( prevSelectedElem );\n if ( cell ) {\n this.selectedIndex = this.getCellSlideIndex( cell );\n }\n this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex );\n\n this.emitEvent( 'cellChange', [ changedCellIndex ] );\n // position slider\n this.select( this.selectedIndex );\n // do not position slider after lazy load\n if ( isPositioningSlider ) {\n this.positionSliderAtSelected();\n }\n};\n\n// ----- ----- //\n\nreturn Flickity;\n\n} ) );\n\n// lazyload\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/lazyload',[\n './flickity',\n 'fizzy-ui-utils/utils',\n ], function( Flickity, utils ) {\n return factory( window, Flickity, utils );\n } );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('./flickity'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n factory(\n window,\n window.Flickity,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( window, Flickity, utils ) {\n'use strict';\n\nFlickity.createMethods.push('_createLazyload');\nvar proto = Flickity.prototype;\n\nproto._createLazyload = function() {\n this.on( 'select', this.lazyLoad );\n};\n\nproto.lazyLoad = function() {\n var lazyLoad = this.options.lazyLoad;\n if ( !lazyLoad ) {\n return;\n }\n // get adjacent cells, use lazyLoad option for adjacent count\n var adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0;\n var cellElems = this.getAdjacentCellElements( adjCount );\n // get lazy images in those cells\n var lazyImages = [];\n cellElems.forEach( function( cellElem ) {\n var lazyCellImages = getCellLazyImages( cellElem );\n lazyImages = lazyImages.concat( lazyCellImages );\n } );\n // load lazy images\n lazyImages.forEach( function( img ) {\n new LazyLoader( img, this );\n }, this );\n};\n\nfunction getCellLazyImages( cellElem ) {\n // check if cell element is lazy image\n if ( cellElem.nodeName == 'IMG' ) {\n var lazyloadAttr = cellElem.getAttribute('data-flickity-lazyload');\n var srcAttr = cellElem.getAttribute('data-flickity-lazyload-src');\n var srcsetAttr = cellElem.getAttribute('data-flickity-lazyload-srcset');\n if ( lazyloadAttr || srcAttr || srcsetAttr ) {\n return [ cellElem ];\n }\n }\n // select lazy images in cell\n var lazySelector = 'img[data-flickity-lazyload], ' +\n 'img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]';\n var imgs = cellElem.querySelectorAll( lazySelector );\n return utils.makeArray( imgs );\n}\n\n// -------------------------- LazyLoader -------------------------- //\n\n/**\n * class to handle loading images\n * @param {Image} img - Image element\n * @param {Flickity} flickity - Flickity instance\n */\nfunction LazyLoader( img, flickity ) {\n this.img = img;\n this.flickity = flickity;\n this.load();\n}\n\nLazyLoader.prototype.handleEvent = utils.handleEvent;\n\nLazyLoader.prototype.load = function() {\n this.img.addEventListener( 'load', this );\n this.img.addEventListener( 'error', this );\n // get src & srcset\n var src = this.img.getAttribute('data-flickity-lazyload') ||\n this.img.getAttribute('data-flickity-lazyload-src');\n var srcset = this.img.getAttribute('data-flickity-lazyload-srcset');\n // set src & serset\n this.img.src = src;\n if ( srcset ) {\n this.img.setAttribute( 'srcset', srcset );\n }\n // remove attr\n this.img.removeAttribute('data-flickity-lazyload');\n this.img.removeAttribute('data-flickity-lazyload-src');\n this.img.removeAttribute('data-flickity-lazyload-srcset');\n};\n\nLazyLoader.prototype.onload = function( event ) {\n this.complete( event, 'flickity-lazyloaded' );\n};\n\nLazyLoader.prototype.onerror = function( event ) {\n this.complete( event, 'flickity-lazyerror' );\n};\n\nLazyLoader.prototype.complete = function( event, className ) {\n // unbind events\n this.img.removeEventListener( 'load', this );\n this.img.removeEventListener( 'error', this );\n\n var cell = this.flickity.getParentCell( this.img );\n var cellElem = cell && cell.element;\n this.flickity.cellSizeChange( cellElem );\n\n this.img.classList.add( className );\n this.flickity.dispatchEvent( 'lazyLoad', event, cellElem );\n};\n\n// ----- ----- //\n\nFlickity.LazyLoader = LazyLoader;\n\nreturn Flickity;\n\n} ) );\n\n/*!\n * Flickity v2.3.0\n * Touch, responsive, flickable carousels\n *\n * Licensed GPLv3 for open source use\n * or Flickity Commercial License for commercial use\n *\n * https://flickity.metafizzy.co\n * Copyright 2015-2021 Metafizzy\n */\n\n( function( window, factory ) {\n // universal module definition\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity/js/index',[\n './flickity',\n './drag',\n './prev-next-button',\n './page-dots',\n './player',\n './add-remove-cell',\n './lazyload',\n ], factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n require('./flickity'),\n require('./drag'),\n require('./prev-next-button'),\n require('./page-dots'),\n require('./player'),\n require('./add-remove-cell'),\n require('./lazyload')\n );\n }\n\n} )( window, function factory( Flickity ) {\n return Flickity;\n} );\n\n/*!\n * Flickity asNavFor v2.0.2\n * enable asNavFor for Flickity\n */\n\n/*jshint browser: true, undef: true, unused: true, strict: true*/\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */ /*globals define, module, require */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'flickity-as-nav-for/as-nav-for',[\n 'flickity/js/index',\n 'fizzy-ui-utils/utils'\n ], factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n require('flickity'),\n require('fizzy-ui-utils')\n );\n } else {\n // browser global\n window.Flickity = factory(\n window.Flickity,\n window.fizzyUIUtils\n );\n }\n\n}( window, function factory( Flickity, utils ) {\n\n\n\n// -------------------------- asNavFor prototype -------------------------- //\n\n// Flickity.defaults.asNavFor = null;\n\nFlickity.createMethods.push('_createAsNavFor');\n\nvar proto = Flickity.prototype;\n\nproto._createAsNavFor = function() {\n this.on( 'activate', this.activateAsNavFor );\n this.on( 'deactivate', this.deactivateAsNavFor );\n this.on( 'destroy', this.destroyAsNavFor );\n\n var asNavForOption = this.options.asNavFor;\n if ( !asNavForOption ) {\n return;\n }\n // HACK do async, give time for other flickity to be initalized\n var _this = this;\n setTimeout( function initNavCompanion() {\n _this.setNavCompanion( asNavForOption );\n });\n};\n\nproto.setNavCompanion = function( elem ) {\n elem = utils.getQueryElement( elem );\n var companion = Flickity.data( elem );\n // stop if no companion or companion is self\n if ( !companion || companion == this ) {\n return;\n }\n\n this.navCompanion = companion;\n // companion select\n var _this = this;\n this.onNavCompanionSelect = function() {\n _this.navCompanionSelect();\n };\n companion.on( 'select', this.onNavCompanionSelect );\n // click\n this.on( 'staticClick', this.onNavStaticClick );\n\n this.navCompanionSelect( true );\n};\n\nproto.navCompanionSelect = function( isInstant ) {\n // wait for companion & selectedCells first. #8\n var companionCells = this.navCompanion && this.navCompanion.selectedCells;\n if ( !companionCells ) {\n return;\n }\n // select slide that matches first cell of slide\n var selectedCell = companionCells[0];\n var firstIndex = this.navCompanion.cells.indexOf( selectedCell );\n var lastIndex = firstIndex + companionCells.length - 1;\n var selectIndex = Math.floor( lerp( firstIndex, lastIndex,\n this.navCompanion.cellAlign ) );\n this.selectCell( selectIndex, false, isInstant );\n // set nav selected class\n this.removeNavSelectedElements();\n // stop if companion has more cells than this one\n if ( selectIndex >= this.cells.length ) {\n return;\n }\n\n var selectedCells = this.cells.slice( firstIndex, lastIndex + 1 );\n this.navSelectedElements = selectedCells.map( function( cell ) {\n return cell.element;\n });\n this.changeNavSelectedClass('add');\n};\n\nfunction lerp( a, b, t ) {\n return ( b - a ) * t + a;\n}\n\nproto.changeNavSelectedClass = function( method ) {\n this.navSelectedElements.forEach( function( navElem ) {\n navElem.classList[ method ]('is-nav-selected');\n });\n};\n\nproto.activateAsNavFor = function() {\n this.navCompanionSelect( true );\n};\n\nproto.removeNavSelectedElements = function() {\n if ( !this.navSelectedElements ) {\n return;\n }\n this.changeNavSelectedClass('remove');\n delete this.navSelectedElements;\n};\n\nproto.onNavStaticClick = function( event, pointer, cellElement, cellIndex ) {\n if ( typeof cellIndex == 'number' ) {\n this.navCompanion.selectCell( cellIndex );\n }\n};\n\nproto.deactivateAsNavFor = function() {\n this.removeNavSelectedElements();\n};\n\nproto.destroyAsNavFor = function() {\n if ( !this.navCompanion ) {\n return;\n }\n this.navCompanion.off( 'select', this.onNavCompanionSelect );\n this.off( 'staticClick', this.onNavStaticClick );\n delete this.navCompanion;\n};\n\n// ----- ----- //\n\nreturn Flickity;\n\n}));\n\n/*!\n * imagesLoaded v4.1.4\n * JavaScript is all like \"You images are done yet or what?\"\n * MIT License\n */\n\n( function( window, factory ) { 'use strict';\n // universal module definition\n\n /*global define: false, module: false, require: false */\n\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( 'imagesloaded/imagesloaded',[\n 'ev-emitter/ev-emitter'\n ], function( EvEmitter ) {\n return factory( window, EvEmitter );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('ev-emitter')\n );\n } else {\n // browser global\n window.imagesLoaded = factory(\n window,\n window.EvEmitter\n );\n }\n\n})( typeof window !== 'undefined' ? window : this,\n\n// -------------------------- factory -------------------------- //\n\nfunction factory( window, EvEmitter ) {\n\n\n\nvar $ = window.jQuery;\nvar console = window.console;\n\n// -------------------------- helpers -------------------------- //\n\n// extend objects\nfunction extend( a, b ) {\n for ( var prop in b ) {\n a[ prop ] = b[ prop ];\n }\n return a;\n}\n\nvar arraySlice = Array.prototype.slice;\n\n// turn element or nodeList into an array\nfunction makeArray( obj ) {\n if ( Array.isArray( obj ) ) {\n // use object if already an array\n return obj;\n }\n\n var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';\n if ( isArrayLike ) {\n // convert nodeList to array\n return arraySlice.call( obj );\n }\n\n // array of single index\n return [ obj ];\n}\n\n// -------------------------- imagesLoaded -------------------------- //\n\n/**\n * @param {Array, Element, NodeList, String} elem\n * @param {Object or Function} options - if function, use as callback\n * @param {Function} onAlways - callback function\n */\nfunction ImagesLoaded( elem, options, onAlways ) {\n // coerce ImagesLoaded() without new, to be new ImagesLoaded()\n if ( !( this instanceof ImagesLoaded ) ) {\n return new ImagesLoaded( elem, options, onAlways );\n }\n // use elem as selector string\n var queryElem = elem;\n if ( typeof elem == 'string' ) {\n queryElem = document.querySelectorAll( elem );\n }\n // bail if bad element\n if ( !queryElem ) {\n console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );\n return;\n }\n\n this.elements = makeArray( queryElem );\n this.options = extend( {}, this.options );\n // shift arguments if no options set\n if ( typeof options == 'function' ) {\n onAlways = options;\n } else {\n extend( this.options, options );\n }\n\n if ( onAlways ) {\n this.on( 'always', onAlways );\n }\n\n this.getImages();\n\n if ( $ ) {\n // add jQuery Deferred object\n this.jqDeferred = new $.Deferred();\n }\n\n // HACK check async to allow time to bind listeners\n setTimeout( this.check.bind( this ) );\n}\n\nImagesLoaded.prototype = Object.create( EvEmitter.prototype );\n\nImagesLoaded.prototype.options = {};\n\nImagesLoaded.prototype.getImages = function() {\n this.images = [];\n\n // filter & find items if we have an item selector\n this.elements.forEach( this.addElementImages, this );\n};\n\n/**\n * @param {Node} element\n */\nImagesLoaded.prototype.addElementImages = function( elem ) {\n // filter siblings\n if ( elem.nodeName == 'IMG' ) {\n this.addImage( elem );\n }\n // get background image on element\n if ( this.options.background === true ) {\n this.addElementBackgroundImages( elem );\n }\n\n // find children\n // no non-element nodes, #143\n var nodeType = elem.nodeType;\n if ( !nodeType || !elementNodeTypes[ nodeType ] ) {\n return;\n }\n var childImgs = elem.querySelectorAll('img');\n // concat childElems to filterFound array\n for ( var i=0; i < childImgs.length; i++ ) {\n var img = childImgs[i];\n this.addImage( img );\n }\n\n // get child background images\n if ( typeof this.options.background == 'string' ) {\n var children = elem.querySelectorAll( this.options.background );\n for ( i=0; i < children.length; i++ ) {\n var child = children[i];\n this.addElementBackgroundImages( child );\n }\n }\n};\n\nvar elementNodeTypes = {\n 1: true,\n 9: true,\n 11: true\n};\n\nImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {\n var style = getComputedStyle( elem );\n if ( !style ) {\n // Firefox returns null if in a hidden iframe https://bugzil.la/548397\n return;\n }\n // get url inside url(\"...\")\n var reURL = /url\\((['\"])?(.*?)\\1\\)/gi;\n var matches = reURL.exec( style.backgroundImage );\n while ( matches !== null ) {\n var url = matches && matches[2];\n if ( url ) {\n this.addBackground( url, elem );\n }\n matches = reURL.exec( style.backgroundImage );\n }\n};\n\n/**\n * @param {Image} img\n */\nImagesLoaded.prototype.addImage = function( img ) {\n var loadingImage = new LoadingImage( img );\n this.images.push( loadingImage );\n};\n\nImagesLoaded.prototype.addBackground = function( url, elem ) {\n var background = new Background( url, elem );\n this.images.push( background );\n};\n\nImagesLoaded.prototype.check = function() {\n var _this = this;\n this.progressedCount = 0;\n this.hasAnyBroken = false;\n // complete if no images\n if ( !this.images.length ) {\n this.complete();\n return;\n }\n\n function onProgress( image, elem, message ) {\n // HACK - Chrome triggers event before object properties have changed. #83\n setTimeout( function() {\n _this.progress( image, elem, message );\n });\n }\n\n this.images.forEach( function( loadingImage ) {\n loadingImage.once( 'progress', onProgress );\n loadingImage.check();\n });\n};\n\nImagesLoaded.prototype.progress = function( image, elem, message ) {\n this.progressedCount++;\n this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;\n // progress event\n this.emitEvent( 'progress', [ this, image, elem ] );\n if ( this.jqDeferred && this.jqDeferred.notify ) {\n this.jqDeferred.notify( this, image );\n }\n // check if completed\n if ( this.progressedCount == this.images.length ) {\n this.complete();\n }\n\n if ( this.options.debug && console ) {\n console.log( 'progress: ' + message, image, elem );\n }\n};\n\nImagesLoaded.prototype.complete = function() {\n var eventName = this.hasAnyBroken ? 'fail' : 'done';\n this.isComplete = true;\n this.emitEvent( eventName, [ this ] );\n this.emitEvent( 'always', [ this ] );\n if ( this.jqDeferred ) {\n var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';\n this.jqDeferred[ jqMethod ]( this );\n }\n};\n\n// -------------------------- -------------------------- //\n\nfunction LoadingImage( img ) {\n this.img = img;\n}\n\nLoadingImage.prototype = Object.create( EvEmitter.prototype );\n\nLoadingImage.prototype.check = function() {\n // If complete is true and browser supports natural sizes,\n // try to check for image status manually.\n var isComplete = this.getIsImageComplete();\n if ( isComplete ) {\n // report based on naturalWidth\n this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );\n return;\n }\n\n // If none of the checks above matched, simulate loading on detached element.\n this.proxyImage = new Image();\n this.proxyImage.addEventListener( 'load', this );\n this.proxyImage.addEventListener( 'error', this );\n // bind to image as well for Firefox. #191\n this.img.addEventListener( 'load', this );\n this.img.addEventListener( 'error', this );\n this.proxyImage.src = this.img.src;\n};\n\nLoadingImage.prototype.getIsImageComplete = function() {\n // check for non-zero, non-undefined naturalWidth\n // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671\n return this.img.complete && this.img.naturalWidth;\n};\n\nLoadingImage.prototype.confirm = function( isLoaded, message ) {\n this.isLoaded = isLoaded;\n this.emitEvent( 'progress', [ this, this.img, message ] );\n};\n\n// ----- events ----- //\n\n// trigger specified handler for event type\nLoadingImage.prototype.handleEvent = function( event ) {\n var method = 'on' + event.type;\n if ( this[ method ] ) {\n this[ method ]( event );\n }\n};\n\nLoadingImage.prototype.onload = function() {\n this.confirm( true, 'onload' );\n this.unbindEvents();\n};\n\nLoadingImage.prototype.onerror = function() {\n this.confirm( false, 'onerror' );\n this.unbindEvents();\n};\n\nLoadingImage.prototype.unbindEvents = function() {\n this.proxyImage.removeEventListener( 'load', this );\n this.proxyImage.removeEventListener( 'error', this );\n this.img.removeEventListener( 'load', this );\n this.img.removeEventListener( 'error', this );\n};\n\n// -------------------------- Background -------------------------- //\n\nfunction Background( url, element ) {\n this.url = url;\n this.element = element;\n this.img = new Image();\n}\n\n// inherit LoadingImage prototype\nBackground.prototype = Object.create( LoadingImage.prototype );\n\nBackground.prototype.check = function() {\n this.img.addEventListener( 'load', this );\n this.img.addEventListener( 'error', this );\n this.img.src = this.url;\n // check if image is already complete\n var isComplete = this.getIsImageComplete();\n if ( isComplete ) {\n this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );\n this.unbindEvents();\n }\n};\n\nBackground.prototype.unbindEvents = function() {\n this.img.removeEventListener( 'load', this );\n this.img.removeEventListener( 'error', this );\n};\n\nBackground.prototype.confirm = function( isLoaded, message ) {\n this.isLoaded = isLoaded;\n this.emitEvent( 'progress', [ this, this.element, message ] );\n};\n\n// -------------------------- jQuery -------------------------- //\n\nImagesLoaded.makeJQueryPlugin = function( jQuery ) {\n jQuery = jQuery || window.jQuery;\n if ( !jQuery ) {\n return;\n }\n // set local variable\n $ = jQuery;\n // $().imagesLoaded()\n $.fn.imagesLoaded = function( options, callback ) {\n var instance = new ImagesLoaded( this, options, callback );\n return instance.jqDeferred.promise( $(this) );\n };\n};\n// try making plugin\nImagesLoaded.makeJQueryPlugin();\n\n// -------------------------- -------------------------- //\n\nreturn ImagesLoaded;\n\n});\n\n/*!\n * Flickity imagesLoaded v2.0.0\n * enables imagesLoaded option for Flickity\n */\n\n/*jshint browser: true, strict: true, undef: true, unused: true */\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */ /*globals define, module, require */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( [\n 'flickity/js/index',\n 'imagesloaded/imagesloaded'\n ], function( Flickity, imagesLoaded ) {\n return factory( window, Flickity, imagesLoaded );\n });\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory(\n window,\n require('flickity'),\n require('imagesloaded')\n );\n } else {\n // browser global\n window.Flickity = factory(\n window,\n window.Flickity,\n window.imagesLoaded\n );\n }\n\n}( window, function factory( window, Flickity, imagesLoaded ) {\n'use strict';\n\nFlickity.createMethods.push('_createImagesLoaded');\n\nvar proto = Flickity.prototype;\n\nproto._createImagesLoaded = function() {\n this.on( 'activate', this.imagesLoaded );\n};\n\nproto.imagesLoaded = function() {\n if ( !this.options.imagesLoaded ) {\n return;\n }\n var _this = this;\n function onImagesLoadedProgress( instance, image ) {\n var cell = _this.getParentCell( image.img );\n _this.cellSizeChange( cell && cell.element );\n if ( !_this.options.freeScroll ) {\n _this.positionSliderAtSelected();\n }\n }\n imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress );\n};\n\nreturn Flickity;\n\n}));\n\n","/*!\n * Colcade v0.2.0\n * Lightweight masonry layout\n * by David DeSandro\n * MIT license\n */\n\n/*jshint browser: true, undef: true, unused: true */\n\n( function( window, factory ) {\n // universal module definition\n /*jshint strict: false */\n /*global define: false, module: false */\n if ( typeof define == 'function' && define.amd ) {\n // AMD\n define( factory );\n } else if ( typeof module == 'object' && module.exports ) {\n // CommonJS\n module.exports = factory();\n } else {\n // browser global\n window.Colcade = factory();\n }\n\n}( window, function factory() {\n\n// -------------------------- Colcade -------------------------- //\n\nfunction Colcade( element, options ) {\n element = getQueryElement( element );\n\n // do not initialize twice on same element\n if ( element && element.colcadeGUID ) {\n var instance = instances[ element.colcadeGUID ];\n instance.option( options );\n return instance;\n }\n\n this.element = element;\n // options\n this.options = {};\n this.option( options );\n // kick things off\n this.create();\n}\n\nvar proto = Colcade.prototype;\n\nproto.option = function( options ) {\n this.options = extend( this.options, options );\n};\n\n// globally unique identifiers\nvar GUID = 0;\n// internal store of all Colcade intances\nvar instances = {};\n\nproto.create = function() {\n this.errorCheck();\n // add guid for Colcade.data\n var guid = this.guid = ++GUID;\n this.element.colcadeGUID = guid;\n instances[ guid ] = this; // associate via id\n // update initial properties & layout\n this.reload();\n // events\n this._windowResizeHandler = this.onWindowResize.bind( this );\n this._loadHandler = this.onLoad.bind( this );\n window.addEventListener( 'resize', this._windowResizeHandler );\n this.element.addEventListener( 'load', this._loadHandler, true );\n};\n\nproto.errorCheck = function() {\n var errors = [];\n if ( !this.element ) {\n errors.push( 'Bad element: ' + this.element );\n }\n if ( !this.options.columns ) {\n errors.push( 'columns option required: ' + this.options.columns );\n }\n if ( !this.options.items ) {\n errors.push( 'items option required: ' + this.options.items );\n }\n\n if ( errors.length ) {\n throw new Error( '[Colcade error] ' + errors.join('. ') );\n }\n};\n\n// update properties and do layout\nproto.reload = function() {\n this.updateColumns();\n this.updateItems();\n this.layout();\n};\n\nproto.updateColumns = function() {\n this.columns = querySelect( this.options.columns, this.element );\n};\n\nproto.updateItems = function() {\n this.items = querySelect( this.options.items, this.element );\n};\n\nproto.getActiveColumns = function() {\n return this.columns.filter( function( column ) {\n var style = getComputedStyle( column );\n return style.display != 'none';\n });\n};\n\n// ----- layout ----- //\n\n// public, updates activeColumns\nproto.layout = function() {\n this.activeColumns = this.getActiveColumns();\n this._layout();\n};\n\n// private, does not update activeColumns\nproto._layout = function() {\n // reset column heights\n this.columnHeights = this.activeColumns.map( function() {\n return 0;\n });\n // layout all items\n this.layoutItems( this.items );\n};\n\nproto.layoutItems = function( items ) {\n items.forEach( this.layoutItem, this );\n};\n\nproto.layoutItem = function( item ) {\n // layout item by appending to column\n var minHeight = Math.min.apply( Math, this.columnHeights );\n var index = this.columnHeights.indexOf( minHeight );\n this.activeColumns[ index ].appendChild( item );\n // at least 1px, if item hasn't loaded\n // Not exactly accurate, but it's cool\n this.columnHeights[ index ] += item.offsetHeight || 1;\n};\n\n// ----- adding items ----- //\n\nproto.append = function( elems ) {\n var items = this.getQueryItems( elems );\n // add items to collection\n this.items = this.items.concat( items );\n // lay them out\n this.layoutItems( items );\n};\n\nproto.prepend = function( elems ) {\n var items = this.getQueryItems( elems );\n // add items to collection\n this.items = items.concat( this.items );\n // lay out everything\n this._layout();\n};\n\nproto.getQueryItems = function( elems ) {\n elems = makeArray( elems );\n var fragment = document.createDocumentFragment();\n elems.forEach( function( elem ) {\n fragment.appendChild( elem );\n });\n return querySelect( this.options.items, fragment );\n};\n\n// ----- measure column height ----- //\n\nproto.measureColumnHeight = function( elem ) {\n var boundingRect = this.element.getBoundingClientRect();\n this.activeColumns.forEach( function( column, i ) {\n // if elem, measure only that column\n // if no elem, measure all columns\n if ( !elem || column.contains( elem ) ) {\n var lastChildRect = column.lastElementChild.getBoundingClientRect();\n // not an exact calculation as it includes top border, and excludes item bottom margin\n this.columnHeights[ i ] = lastChildRect.bottom - boundingRect.top;\n }\n }, this );\n};\n\n// ----- events ----- //\n\nproto.onWindowResize = function() {\n clearTimeout( this.resizeTimeout );\n this.resizeTimeout = setTimeout( function() {\n this.onDebouncedResize();\n }.bind( this ), 100 );\n};\n\nproto.onDebouncedResize = function() {\n var activeColumns = this.getActiveColumns();\n // check if columns changed\n var isSameLength = activeColumns.length == this.activeColumns.length;\n var isSameColumns = true;\n this.activeColumns.forEach( function( column, i ) {\n isSameColumns = isSameColumns && column == activeColumns[i];\n });\n if ( isSameLength && isSameColumns ) {\n return;\n }\n // activeColumns changed\n this.activeColumns = activeColumns;\n this._layout();\n};\n\nproto.onLoad = function( event ) {\n this.measureColumnHeight( event.target );\n};\n\n// ----- destroy ----- //\n\nproto.destroy = function() {\n // move items back to container\n this.items.forEach( function( item ) {\n this.element.appendChild( item );\n }, this );\n // remove events\n window.removeEventListener( 'resize', this._windowResizeHandler );\n this.element.removeEventListener( 'load', this._loadHandler, true );\n // remove data\n delete this.element.colcadeGUID;\n delete instances[ this.guid ];\n};\n\n// -------------------------- HTML init -------------------------- //\n\ndocReady( function() {\n var dataElems = querySelect('[data-colcade]');\n dataElems.forEach( htmlInit );\n});\n\nfunction htmlInit( elem ) {\n // convert attribute \"foo: bar, qux: baz\" into object\n var attr = elem.getAttribute('data-colcade');\n var attrParts = attr.split(',');\n var options = {};\n attrParts.forEach( function( part ) {\n var pair = part.split(':');\n var key = pair[0].trim();\n var value = pair[1].trim();\n options[ key ] = value;\n });\n\n new Colcade( elem, options );\n}\n\nColcade.data = function( elem ) {\n elem = getQueryElement( elem );\n var id = elem && elem.colcadeGUID;\n return id && instances[ id ];\n};\n\n// -------------------------- jQuery -------------------------- //\n\nColcade.makeJQueryPlugin = function( $ ) {\n $ = $ || window.jQuery;\n if ( !$ ) {\n return;\n }\n\n $.fn.colcade = function( arg0 /*, arg1 */) {\n // method call $().colcade( 'method', { options } )\n if ( typeof arg0 == 'string' ) {\n // shift arguments by 1\n var args = Array.prototype.slice.call( arguments, 1 );\n return methodCall( this, arg0, args );\n }\n // just $().colcade({ options })\n plainCall( this, arg0 );\n return this;\n };\n\n function methodCall( $elems, methodName, args ) {\n var returnValue;\n $elems.each( function( i, elem ) {\n // get instance\n var colcade = $.data( elem, 'colcade' );\n if ( !colcade ) {\n return;\n }\n // apply method, get return value\n var value = colcade[ methodName ].apply( colcade, args );\n // set return value if value is returned, use only first value\n returnValue = returnValue === undefined ? value : returnValue;\n });\n return returnValue !== undefined ? returnValue : $elems;\n }\n\n function plainCall( $elems, options ) {\n $elems.each( function( i, elem ) {\n var colcade = $.data( elem, 'colcade' );\n if ( colcade ) {\n // set options & init\n colcade.option( options );\n colcade.layout();\n } else {\n // initialize new instance\n colcade = new Colcade( elem, options );\n $.data( elem, 'colcade', colcade );\n }\n });\n }\n};\n\n// try making plugin\nColcade.makeJQueryPlugin();\n\n// -------------------------- utils -------------------------- //\n\nfunction extend( a, b ) {\n for ( var prop in b ) {\n a[ prop ] = b[ prop ];\n }\n return a;\n}\n\n// turn element or nodeList into an array\nfunction makeArray( obj ) {\n var ary = [];\n if ( Array.isArray( obj ) ) {\n // use object if already an array\n ary = obj;\n } else if ( obj && typeof obj.length == 'number' ) {\n // convert nodeList to array\n for ( var i=0; i < obj.length; i++ ) {\n ary.push( obj[i] );\n }\n } else {\n // array of single index\n ary.push( obj );\n }\n return ary;\n}\n\n// get array of elements\nfunction querySelect( selector, elem ) {\n elem = elem || document;\n var elems = elem.querySelectorAll( selector );\n return makeArray( elems );\n}\n\nfunction getQueryElement( elem ) {\n if ( typeof elem == 'string' ) {\n elem = document.querySelector( elem );\n }\n return elem;\n}\n\nfunction docReady( onReady ) {\n if ( document.readyState == 'complete' ) {\n onReady();\n return;\n }\n document.addEventListener( 'DOMContentLoaded', onReady );\n}\n\n// -------------------------- end -------------------------- //\n\nreturn Colcade;\n\n}));\n","typeof navigator === \"object\" && (function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define('Plyr', factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Plyr = factory());\n})(this, (function () { 'use strict';\n\n function _defineProperty$1(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n }\n\n function _classCallCheck(e, t) {\n if (!(e instanceof t)) throw new TypeError(\"Cannot call a class as a function\");\n }\n function _defineProperties(e, t) {\n for (var n = 0; n < t.length; n++) {\n var r = t[n];\n r.enumerable = r.enumerable || !1, r.configurable = !0, \"value\" in r && (r.writable = !0), Object.defineProperty(e, r.key, r);\n }\n }\n function _createClass(e, t, n) {\n return t && _defineProperties(e.prototype, t), n && _defineProperties(e, n), e;\n }\n function _defineProperty(e, t, n) {\n return t in e ? Object.defineProperty(e, t, {\n value: n,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }) : e[t] = n, e;\n }\n function ownKeys(e, t) {\n var n = Object.keys(e);\n if (Object.getOwnPropertySymbols) {\n var r = Object.getOwnPropertySymbols(e);\n t && (r = r.filter(function (t) {\n return Object.getOwnPropertyDescriptor(e, t).enumerable;\n })), n.push.apply(n, r);\n }\n return n;\n }\n function _objectSpread2(e) {\n for (var t = 1; t < arguments.length; t++) {\n var n = null != arguments[t] ? arguments[t] : {};\n t % 2 ? ownKeys(Object(n), !0).forEach(function (t) {\n _defineProperty(e, t, n[t]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : ownKeys(Object(n)).forEach(function (t) {\n Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t));\n });\n }\n return e;\n }\n var defaults$1 = {\n addCSS: !0,\n thumbWidth: 15,\n watch: !0\n };\n function matches$1(e, t) {\n return function () {\n return Array.from(document.querySelectorAll(t)).includes(this);\n }.call(e, t);\n }\n function trigger(e, t) {\n if (e && t) {\n var n = new Event(t, {\n bubbles: !0\n });\n e.dispatchEvent(n);\n }\n }\n var getConstructor$1 = function (e) {\n return null != e ? e.constructor : null;\n },\n instanceOf$1 = function (e, t) {\n return !!(e && t && e instanceof t);\n },\n isNullOrUndefined$1 = function (e) {\n return null == e;\n },\n isObject$1 = function (e) {\n return getConstructor$1(e) === Object;\n },\n isNumber$1 = function (e) {\n return getConstructor$1(e) === Number && !Number.isNaN(e);\n },\n isString$1 = function (e) {\n return getConstructor$1(e) === String;\n },\n isBoolean$1 = function (e) {\n return getConstructor$1(e) === Boolean;\n },\n isFunction$1 = function (e) {\n return getConstructor$1(e) === Function;\n },\n isArray$1 = function (e) {\n return Array.isArray(e);\n },\n isNodeList$1 = function (e) {\n return instanceOf$1(e, NodeList);\n },\n isElement$1 = function (e) {\n return instanceOf$1(e, Element);\n },\n isEvent$1 = function (e) {\n return instanceOf$1(e, Event);\n },\n isEmpty$1 = function (e) {\n return isNullOrUndefined$1(e) || (isString$1(e) || isArray$1(e) || isNodeList$1(e)) && !e.length || isObject$1(e) && !Object.keys(e).length;\n },\n is$1 = {\n nullOrUndefined: isNullOrUndefined$1,\n object: isObject$1,\n number: isNumber$1,\n string: isString$1,\n boolean: isBoolean$1,\n function: isFunction$1,\n array: isArray$1,\n nodeList: isNodeList$1,\n element: isElement$1,\n event: isEvent$1,\n empty: isEmpty$1\n };\n function getDecimalPlaces(e) {\n var t = \"\".concat(e).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n return t ? Math.max(0, (t[1] ? t[1].length : 0) - (t[2] ? +t[2] : 0)) : 0;\n }\n function round(e, t) {\n if (1 > t) {\n var n = getDecimalPlaces(t);\n return parseFloat(e.toFixed(n));\n }\n return Math.round(e / t) * t;\n }\n var RangeTouch = function () {\n function e(t, n) {\n _classCallCheck(this, e), is$1.element(t) ? this.element = t : is$1.string(t) && (this.element = document.querySelector(t)), is$1.element(this.element) && is$1.empty(this.element.rangeTouch) && (this.config = _objectSpread2({}, defaults$1, {}, n), this.init());\n }\n return _createClass(e, [{\n key: \"init\",\n value: function () {\n e.enabled && (this.config.addCSS && (this.element.style.userSelect = \"none\", this.element.style.webKitUserSelect = \"none\", this.element.style.touchAction = \"manipulation\"), this.listeners(!0), this.element.rangeTouch = this);\n }\n }, {\n key: \"destroy\",\n value: function () {\n e.enabled && (this.config.addCSS && (this.element.style.userSelect = \"\", this.element.style.webKitUserSelect = \"\", this.element.style.touchAction = \"\"), this.listeners(!1), this.element.rangeTouch = null);\n }\n }, {\n key: \"listeners\",\n value: function (e) {\n var t = this,\n n = e ? \"addEventListener\" : \"removeEventListener\";\n [\"touchstart\", \"touchmove\", \"touchend\"].forEach(function (e) {\n t.element[n](e, function (e) {\n return t.set(e);\n }, !1);\n });\n }\n }, {\n key: \"get\",\n value: function (t) {\n if (!e.enabled || !is$1.event(t)) return null;\n var n,\n r = t.target,\n i = t.changedTouches[0],\n o = parseFloat(r.getAttribute(\"min\")) || 0,\n s = parseFloat(r.getAttribute(\"max\")) || 100,\n u = parseFloat(r.getAttribute(\"step\")) || 1,\n c = r.getBoundingClientRect(),\n a = 100 / c.width * (this.config.thumbWidth / 2) / 100;\n return 0 > (n = 100 / c.width * (i.clientX - c.left)) ? n = 0 : 100 < n && (n = 100), 50 > n ? n -= (100 - 2 * n) * a : 50 < n && (n += 2 * (n - 50) * a), o + round(n / 100 * (s - o), u);\n }\n }, {\n key: \"set\",\n value: function (t) {\n e.enabled && is$1.event(t) && !t.target.disabled && (t.preventDefault(), t.target.value = this.get(t), trigger(t.target, \"touchend\" === t.type ? \"change\" : \"input\"));\n }\n }], [{\n key: \"setup\",\n value: function (t) {\n var n = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : {},\n r = null;\n if (is$1.empty(t) || is$1.string(t) ? r = Array.from(document.querySelectorAll(is$1.string(t) ? t : 'input[type=\"range\"]')) : is$1.element(t) ? r = [t] : is$1.nodeList(t) ? r = Array.from(t) : is$1.array(t) && (r = t.filter(is$1.element)), is$1.empty(r)) return null;\n var i = _objectSpread2({}, defaults$1, {}, n);\n if (is$1.string(t) && i.watch) {\n var o = new MutationObserver(function (n) {\n Array.from(n).forEach(function (n) {\n Array.from(n.addedNodes).forEach(function (n) {\n is$1.element(n) && matches$1(n, t) && new e(n, i);\n });\n });\n });\n o.observe(document.body, {\n childList: !0,\n subtree: !0\n });\n }\n return r.map(function (t) {\n return new e(t, n);\n });\n }\n }, {\n key: \"enabled\",\n get: function () {\n return \"ontouchstart\" in document.documentElement;\n }\n }]), e;\n }();\n\n // ==========================================================================\n // Type checking utils\n // ==========================================================================\n\n const getConstructor = input => input !== null && typeof input !== 'undefined' ? input.constructor : null;\n const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);\n const isNullOrUndefined = input => input === null || typeof input === 'undefined';\n const isObject = input => getConstructor(input) === Object;\n const isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);\n const isString = input => getConstructor(input) === String;\n const isBoolean = input => getConstructor(input) === Boolean;\n const isFunction = input => typeof input === 'function';\n const isArray = input => Array.isArray(input);\n const isWeakMap = input => instanceOf(input, WeakMap);\n const isNodeList = input => instanceOf(input, NodeList);\n const isTextNode = input => getConstructor(input) === Text;\n const isEvent = input => instanceOf(input, Event);\n const isKeyboardEvent = input => instanceOf(input, KeyboardEvent);\n const isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);\n const isTrack = input => instanceOf(input, TextTrack) || !isNullOrUndefined(input) && isString(input.kind);\n const isPromise = input => instanceOf(input, Promise) && isFunction(input.then);\n const isElement = input => input !== null && typeof input === 'object' && input.nodeType === 1 && typeof input.style === 'object' && typeof input.ownerDocument === 'object';\n const isEmpty = input => isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length;\n const isUrl = input => {\n // Accept a URL object\n if (instanceOf(input, window.URL)) {\n return true;\n }\n\n // Must be string from here\n if (!isString(input)) {\n return false;\n }\n\n // Add the protocol if required\n let string = input;\n if (!input.startsWith('http://') || !input.startsWith('https://')) {\n string = `http://${input}`;\n }\n try {\n return !isEmpty(new URL(string).hostname);\n } catch (_) {\n return false;\n }\n };\n var is = {\n nullOrUndefined: isNullOrUndefined,\n object: isObject,\n number: isNumber,\n string: isString,\n boolean: isBoolean,\n function: isFunction,\n array: isArray,\n weakMap: isWeakMap,\n nodeList: isNodeList,\n element: isElement,\n textNode: isTextNode,\n event: isEvent,\n keyboardEvent: isKeyboardEvent,\n cue: isCue,\n track: isTrack,\n promise: isPromise,\n url: isUrl,\n empty: isEmpty\n };\n\n // ==========================================================================\n const transitionEndEvent = (() => {\n const element = document.createElement('span');\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend'\n };\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n return is.string(type) ? events[type] : false;\n })();\n\n // Force repaint of element\n function repaint(element, delay) {\n setTimeout(() => {\n try {\n // eslint-disable-next-line no-param-reassign\n element.hidden = true;\n\n // eslint-disable-next-line no-unused-expressions\n element.offsetHeight;\n\n // eslint-disable-next-line no-param-reassign\n element.hidden = false;\n } catch (_) {\n // Do nothing\n }\n }, delay);\n }\n\n // ==========================================================================\n // Browser sniffing\n // Unfortunately, due to mixed support, UA sniffing is required\n // ==========================================================================\n\n const browser = {\n isIE: Boolean(window.document.documentMode),\n isEdge: /Edge/g.test(navigator.userAgent),\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/g.test(navigator.userAgent),\n isIPhone: /iPhone|iPod/gi.test(navigator.userAgent) && navigator.maxTouchPoints > 1,\n isIos: /iPad|iPhone|iPod/gi.test(navigator.userAgent) && navigator.maxTouchPoints > 1\n };\n\n // ==========================================================================\n\n // Clone nested objects\n function cloneDeep(object) {\n return JSON.parse(JSON.stringify(object));\n }\n\n // Get a nested value in an object\n function getDeep(object, path) {\n return path.split('.').reduce((obj, key) => obj && obj[key], object);\n }\n\n // Deep extend destination object with N more objects\n function extend(target = {}, ...sources) {\n if (!sources.length) {\n return target;\n }\n const source = sources.shift();\n if (!is.object(source)) {\n return target;\n }\n Object.keys(source).forEach(key => {\n if (is.object(source[key])) {\n if (!Object.keys(target).includes(key)) {\n Object.assign(target, {\n [key]: {}\n });\n }\n extend(target[key], source[key]);\n } else {\n Object.assign(target, {\n [key]: source[key]\n });\n }\n });\n return extend(target, ...sources);\n }\n\n // ==========================================================================\n\n // Wrap an element\n function wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets).reverse().forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n }\n\n // Set attributes\n function setAttributes(element, attributes) {\n if (!is.element(element) || is.empty(attributes)) {\n return;\n }\n\n // Assume null and undefined attributes should be left out,\n // Setting them would otherwise convert them to \"null\" and \"undefined\"\n Object.entries(attributes).filter(([, value]) => !is.nullOrUndefined(value)).forEach(([key, value]) => element.setAttribute(key, value));\n }\n\n // Create a DocumentFragment\n function createElement(type, attributes, text) {\n // Create a new \n const element = document.createElement(type);\n\n // Set all passed attributes\n if (is.object(attributes)) {\n setAttributes(element, attributes);\n }\n\n // Add text node\n if (is.string(text)) {\n element.innerText = text;\n }\n\n // Return built element\n return element;\n }\n\n // Inaert an element after another\n function insertAfter(element, target) {\n if (!is.element(element) || !is.element(target)) {\n return;\n }\n target.parentNode.insertBefore(element, target.nextSibling);\n }\n\n // Insert a DocumentFragment\n function insertElement(type, parent, attributes, text) {\n if (!is.element(parent)) {\n return;\n }\n parent.appendChild(createElement(type, attributes, text));\n }\n\n // Remove element(s)\n function removeElement(element) {\n if (is.nodeList(element) || is.array(element)) {\n Array.from(element).forEach(removeElement);\n return;\n }\n if (!is.element(element) || !is.element(element.parentNode)) {\n return;\n }\n element.parentNode.removeChild(element);\n }\n\n // Remove all child elements\n function emptyElement(element) {\n if (!is.element(element)) {\n return;\n }\n let {\n length\n } = element.childNodes;\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n }\n\n // Replace element\n function replaceElement(newChild, oldChild) {\n if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) {\n return null;\n }\n oldChild.parentNode.replaceChild(newChild, oldChild);\n return newChild;\n }\n\n // Get an attribute object from a string selector\n function getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!is.string(sel) || is.empty(sel)) {\n return {};\n }\n const attributes = {};\n const existing = extend({}, existingAttributes);\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n // Get the parts and value\n const parts = stripped.split('=');\n const [key] = parts;\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n // Get the first character\n const start = selector.charAt(0);\n switch (start) {\n case '.':\n // Add to existing classname\n if (is.string(existing.class)) {\n attributes.class = `${existing.class} ${className}`;\n } else {\n attributes.class = className;\n }\n break;\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n case '[':\n // Attribute selector\n attributes[key] = value;\n break;\n }\n });\n return extend(existing, attributes);\n }\n\n // Toggle hidden\n function toggleHidden(element, hidden) {\n if (!is.element(element)) {\n return;\n }\n let hide = hidden;\n if (!is.boolean(hide)) {\n hide = !element.hidden;\n }\n\n // eslint-disable-next-line no-param-reassign\n element.hidden = hide;\n }\n\n // Mirror Element.classList.toggle, with IE compatibility for \"force\" argument\n function toggleClass(element, className, force) {\n if (is.nodeList(element)) {\n return Array.from(element).map(e => toggleClass(e, className, force));\n }\n if (is.element(element)) {\n let method = 'toggle';\n if (typeof force !== 'undefined') {\n method = force ? 'add' : 'remove';\n }\n element.classList[method](className);\n return element.classList.contains(className);\n }\n return false;\n }\n\n // Has class name\n function hasClass(element, className) {\n return is.element(element) && element.classList.contains(className);\n }\n\n // Element matches selector\n function matches(element, selector) {\n const {\n prototype\n } = Element;\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n const method = prototype.matches || prototype.webkitMatchesSelector || prototype.mozMatchesSelector || prototype.msMatchesSelector || match;\n return method.call(element, selector);\n }\n\n // Closest ancestor element matching selector (also tests element itself)\n function closest$1(element, selector) {\n const {\n prototype\n } = Element;\n\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill\n function closestElement() {\n let el = this;\n do {\n if (matches.matches(el, selector)) return el;\n el = el.parentElement || el.parentNode;\n } while (el !== null && el.nodeType === 1);\n return null;\n }\n const method = prototype.closest || closestElement;\n return method.call(element, selector);\n }\n\n // Find all elements\n function getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n }\n\n // Find a single element\n function getElement(selector) {\n return this.elements.container.querySelector(selector);\n }\n\n // Set focus and tab focus class\n function setFocus(element = null, tabFocus = false) {\n if (!is.element(element)) {\n return;\n }\n\n // Set regular focus\n element.focus({\n preventScroll: true\n });\n\n // If we want to mimic keyboard focus via tab\n if (tabFocus) {\n toggleClass(element, this.config.classNames.tabFocus);\n }\n }\n\n // ==========================================================================\n\n // Default codecs for checking mimetype support\n const defaultCodecs = {\n 'audio/ogg': 'vorbis',\n 'audio/wav': '1',\n 'video/webm': 'vp8, vorbis',\n 'video/mp4': 'avc1.42E01E, mp4a.40.2',\n 'video/ogg': 'theora'\n };\n\n // Check for feature support\n const support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n // Check for support\n // Basic functionality vs full UI\n check(type, provider, playsinline) {\n const canPlayInline = browser.isIPhone && playsinline && support.playsinline;\n const api = support[type] || provider !== 'html5';\n const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline);\n return {\n api,\n ui\n };\n },\n // Picture-in-picture support\n // Safari & Chrome only currently\n pip: (() => {\n // While iPhone's support picture-in-picture for some apps, seemingly Safari isn't one of them\n // It will throw the following error when trying to enter picture-in-picture\n // `NotSupportedError: The Picture-in-Picture mode is not supported.`\n if (browser.isIPhone) {\n return false;\n }\n\n // Safari\n // https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls\n if (is.function(createElement('video').webkitSetPresentationMode)) {\n return true;\n }\n\n // Chrome\n // https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture\n if (document.pictureInPictureEnabled && !createElement('video').disablePictureInPicture) {\n return true;\n }\n return false;\n })(),\n // Airplay support\n // Safari only currently\n airplay: is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n playsinline: 'playsInline' in document.createElement('video'),\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(input) {\n if (is.empty(input)) {\n return false;\n }\n const [mediaType] = input.split('/');\n let type = input;\n\n // Verify we're using HTML5 and there's no media type mismatch\n if (!this.isHTML5 || mediaType !== this.type) {\n return false;\n }\n\n // Add codec if required\n if (Object.keys(defaultCodecs).includes(type)) {\n type += `; codecs=\"${defaultCodecs[input]}\"`;\n }\n try {\n return Boolean(type && this.media.canPlayType(type).replace(/no/, ''));\n } catch (_) {\n return false;\n }\n },\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n // Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n // Touch\n // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event\n touch: 'ontouchstart' in document.documentElement,\n // Detect transitions support\n transitions: transitionEndEvent !== false,\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches\n };\n\n // ==========================================================================\n\n // Check for passive event listener support\n // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n // https://www.youtube.com/watch?v=NPM6172J22g\n const supportsPassiveListeners = (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n }\n });\n window.addEventListener('test', null, options);\n window.removeEventListener('test', null, options);\n } catch (_) {\n // Do nothing\n }\n return supported;\n })();\n\n // Toggle event listener\n function toggleListener(element, event, callback, toggle = false, passive = true, capture = false) {\n // Bail if no element, event, or callback\n if (!element || !('addEventListener' in element) || is.empty(event) || !is.function(callback)) {\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n // Build options\n // Default to just the capture boolean for browsers with no passive listener support\n let options = capture;\n\n // If passive events listeners are supported\n if (supportsPassiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive,\n // Whether the listener is a capturing listener or not\n capture\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n if (this && this.eventListeners && toggle) {\n // Cache event listener\n this.eventListeners.push({\n element,\n type,\n callback,\n options\n });\n }\n element[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n }\n\n // Bind event handler\n function on(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, true, passive, capture);\n }\n\n // Unbind event handler\n function off(element, events = '', callback, passive = true, capture = false) {\n toggleListener.call(this, element, events, callback, false, passive, capture);\n }\n\n // Bind once-only event handler\n function once(element, events = '', callback, passive = true, capture = false) {\n const onceCallback = (...args) => {\n off(element, events, onceCallback, passive, capture);\n callback.apply(this, args);\n };\n toggleListener.call(this, element, events, onceCallback, true, passive, capture);\n }\n\n // Trigger event\n function triggerEvent(element, type = '', bubbles = false, detail = {}) {\n // Bail if no element\n if (!is.element(element) || is.empty(type)) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles,\n detail: {\n ...detail,\n plyr: this\n }\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n }\n\n // Unbind all cached event listeners\n function unbindListeners() {\n if (this && this.eventListeners) {\n this.eventListeners.forEach(item => {\n const {\n element,\n type,\n callback,\n options\n } = item;\n element.removeEventListener(type, callback, options);\n });\n this.eventListeners = [];\n }\n }\n\n // Run method when / if player is ready\n function ready() {\n return new Promise(resolve => this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve)).then(() => {});\n }\n\n /**\n * Silence a Promise-like object.\n * This is useful for avoiding non-harmful, but potentially confusing \"uncaught\n * play promise\" rejection error messages.\n * @param {Object} value An object that may or may not be `Promise`-like.\n */\n function silencePromise(value) {\n if (is.promise(value)) {\n value.then(null, () => {});\n }\n }\n\n // ==========================================================================\n\n // Remove duplicates in an array\n function dedupe(array) {\n if (!is.array(array)) {\n return array;\n }\n return array.filter((item, index) => array.indexOf(item) === index);\n }\n\n // Get the closest value in an array\n function closest(array, value) {\n if (!is.array(array) || !array.length) {\n return null;\n }\n return array.reduce((prev, curr) => Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev);\n }\n\n // ==========================================================================\n\n // Check support for a CSS declaration\n function supportsCSS(declaration) {\n if (!window || !window.CSS) {\n return false;\n }\n return window.CSS.supports(declaration);\n }\n\n // Standard/common aspect ratios\n const standardRatios = [[1, 1], [4, 3], [3, 4], [5, 4], [4, 5], [3, 2], [2, 3], [16, 10], [10, 16], [16, 9], [9, 16], [21, 9], [9, 21], [32, 9], [9, 32]].reduce((out, [x, y]) => ({\n ...out,\n [x / y]: [x, y]\n }), {});\n\n // Validate an aspect ratio\n function validateAspectRatio(input) {\n if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {\n return false;\n }\n const ratio = is.array(input) ? input : input.split(':');\n return ratio.map(Number).every(is.number);\n }\n\n // Reduce an aspect ratio to it's lowest form\n function reduceAspectRatio(ratio) {\n if (!is.array(ratio) || !ratio.every(is.number)) {\n return null;\n }\n const [width, height] = ratio;\n const getDivider = (w, h) => h === 0 ? w : getDivider(h, w % h);\n const divider = getDivider(width, height);\n return [width / divider, height / divider];\n }\n\n // Calculate an aspect ratio\n function getAspectRatio(input) {\n const parse = ratio => validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null;\n // Try provided ratio\n let ratio = parse(input);\n\n // Get from config\n if (ratio === null) {\n ratio = parse(this.config.ratio);\n }\n\n // Get from embed\n if (ratio === null && !is.empty(this.embed) && is.array(this.embed.ratio)) {\n ({\n ratio\n } = this.embed);\n }\n\n // Get from HTML5 video\n if (ratio === null && this.isHTML5) {\n const {\n videoWidth,\n videoHeight\n } = this.media;\n ratio = [videoWidth, videoHeight];\n }\n return reduceAspectRatio(ratio);\n }\n\n // Set aspect ratio for responsive container\n function setAspectRatio(input) {\n if (!this.isVideo) {\n return {};\n }\n const {\n wrapper\n } = this.elements;\n const ratio = getAspectRatio.call(this, input);\n if (!is.array(ratio)) {\n return {};\n }\n const [x, y] = reduceAspectRatio(ratio);\n const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`);\n const padding = 100 / x * y;\n if (useNative) {\n wrapper.style.aspectRatio = `${x}/${y}`;\n } else {\n wrapper.style.paddingBottom = `${padding}%`;\n }\n\n // For Vimeo we have an extra
to hide the standard controls and UI\n if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {\n const height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);\n const offset = (height - padding) / (height / 50);\n if (this.fullscreen.active) {\n wrapper.style.paddingBottom = null;\n } else {\n this.media.style.transform = `translateY(-${offset}%)`;\n }\n } else if (this.isHTML5) {\n wrapper.classList.add(this.config.classNames.videoFixedRatio);\n }\n return {\n padding,\n ratio\n };\n }\n\n // Round an aspect ratio to closest standard ratio\n function roundAspectRatio(x, y, tolerance = 0.05) {\n const ratio = x / y;\n const closestRatio = closest(Object.keys(standardRatios), ratio);\n\n // Check match is within tolerance\n if (Math.abs(closestRatio - ratio) <= tolerance) {\n return standardRatios[closestRatio];\n }\n\n // No match\n return [x, y];\n }\n\n // Get the size of the viewport\n // https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions\n function getViewportSize() {\n const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);\n const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);\n return [width, height];\n }\n\n // ==========================================================================\n const html5 = {\n getSources() {\n if (!this.isHTML5) {\n return [];\n }\n const sources = Array.from(this.media.querySelectorAll('source'));\n\n // Filter out unsupported sources (if type is specified)\n return sources.filter(source => {\n const type = source.getAttribute('type');\n if (is.empty(type)) {\n return true;\n }\n return support.mime.call(this, type);\n });\n },\n // Get quality levels\n getQualityOptions() {\n // Whether we're forcing all options (e.g. for streaming)\n if (this.config.quality.forced) {\n return this.config.quality.options;\n }\n\n // Get sizes from elements\n return html5.getSources.call(this).map(source => Number(source.getAttribute('size'))).filter(Boolean);\n },\n setup() {\n if (!this.isHTML5) {\n return;\n }\n const player = this;\n\n // Set speed options from config\n player.options.speed = player.config.speed.options;\n\n // Set aspect ratio if fixed\n if (!is.empty(this.config.ratio)) {\n setAspectRatio.call(player);\n }\n\n // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n // Get sources\n const sources = html5.getSources.call(player);\n const source = sources.find(s => s.getAttribute('src') === player.source);\n\n // Return size, if match is found\n return source && Number(source.getAttribute('size'));\n },\n set(input) {\n if (player.quality === input) {\n return;\n }\n\n // If we're using an external handler...\n if (player.config.quality.forced && is.function(player.config.quality.onChange)) {\n player.config.quality.onChange(input);\n } else {\n // Get sources\n const sources = html5.getSources.call(player);\n // Get first match for requested size\n const source = sources.find(s => Number(s.getAttribute('size')) === input);\n\n // No matching source found\n if (!source) {\n return;\n }\n\n // Get current state\n const {\n currentTime,\n paused,\n preload,\n readyState,\n playbackRate\n } = player.media;\n\n // Set new source\n player.media.src = source.getAttribute('src');\n\n // Prevent loading if preload=\"none\" and the current source isn't loaded (#1044)\n if (preload !== 'none' || readyState) {\n // Restore time\n player.once('loadedmetadata', () => {\n player.speed = playbackRate;\n player.currentTime = currentTime;\n\n // Resume playing\n if (!paused) {\n silencePromise(player.play());\n }\n });\n\n // Load new source\n player.media.load();\n }\n }\n\n // Trigger change event\n triggerEvent.call(player, player.media, 'qualitychange', false, {\n quality: input\n });\n }\n });\n },\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n removeElement(html5.getSources.call(this));\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.debug.log('Cancelled network requests');\n }\n };\n\n // ==========================================================================\n\n // Generate a random ID\n function generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n }\n\n // Format string\n function format(input, ...args) {\n if (is.empty(input)) return input;\n return input.toString().replace(/{(\\d+)}/g, (match, i) => args[i].toString());\n }\n\n // Get percentage\n function getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n }\n\n // Replace all occurrences of a string in a string\n const replaceAll = (input = '', find = '', replace = '') => input.replace(new RegExp(find.toString().replace(/([.*+?^=!:${}()|[\\]/\\\\])/g, '\\\\$1'), 'g'), replace.toString());\n\n // Convert to title case\n const toTitleCase = (input = '') => input.toString().replace(/\\w\\S*/g, text => text.charAt(0).toUpperCase() + text.slice(1).toLowerCase());\n\n // Convert string to pascalCase\n function toPascalCase(input = '') {\n let string = input.toString();\n\n // Convert kebab case\n string = replaceAll(string, '-', ' ');\n\n // Convert snake case\n string = replaceAll(string, '_', ' ');\n\n // Convert to title case\n string = toTitleCase(string);\n\n // Convert to pascal case\n return replaceAll(string, ' ', '');\n }\n\n // Convert string to pascalCase\n function toCamelCase(input = '') {\n let string = input.toString();\n\n // Convert to pascal case\n string = toPascalCase(string);\n\n // Convert first character to lowercase\n return string.charAt(0).toLowerCase() + string.slice(1);\n }\n\n // Remove HTML from a string\n function stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n }\n\n // Like outerHTML, but also works for DocumentFragment\n function getHTML(element) {\n const wrapper = document.createElement('div');\n wrapper.appendChild(element);\n return wrapper.innerHTML;\n }\n\n // ==========================================================================\n\n // Skip i18n for abbreviations and brand names\n const resources = {\n pip: 'PIP',\n airplay: 'AirPlay',\n html5: 'HTML5',\n vimeo: 'Vimeo',\n youtube: 'YouTube'\n };\n const i18n = {\n get(key = '', config = {}) {\n if (is.empty(key) || is.empty(config)) {\n return '';\n }\n let string = getDeep(config.i18n, key);\n if (is.empty(string)) {\n if (Object.keys(resources).includes(key)) {\n return resources[key];\n }\n return '';\n }\n const replace = {\n '{seektime}': config.seekTime,\n '{title}': config.title\n };\n Object.entries(replace).forEach(([k, v]) => {\n string = replaceAll(string, k, v);\n });\n return string;\n }\n };\n\n class Storage {\n constructor(player) {\n _defineProperty$1(this, \"get\", key => {\n if (!Storage.supported || !this.enabled) {\n return null;\n }\n const store = window.localStorage.getItem(this.key);\n if (is.empty(store)) {\n return null;\n }\n const json = JSON.parse(store);\n return is.string(key) && key.length ? json[key] : json;\n });\n _defineProperty$1(this, \"set\", object => {\n // Bail if we don't have localStorage support or it's disabled\n if (!Storage.supported || !this.enabled) {\n return;\n }\n\n // Can only store objectst\n if (!is.object(object)) {\n return;\n }\n\n // Get current storage\n let storage = this.get();\n\n // Default to empty object\n if (is.empty(storage)) {\n storage = {};\n }\n\n // Update the working copy of the values\n extend(storage, object);\n\n // Update storage\n try {\n window.localStorage.setItem(this.key, JSON.stringify(storage));\n } catch (_) {\n // Do nothing\n }\n });\n this.enabled = player.config.storage.enabled;\n this.key = player.config.storage.key;\n }\n\n // Check for actual support (see if we can use it)\n static get supported() {\n try {\n if (!('localStorage' in window)) {\n return false;\n }\n const test = '___test';\n\n // Try to use it (it might be disabled, e.g. user is in private mode)\n // see: https://github.com/sampotts/plyr/issues/131\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (_) {\n return false;\n }\n }\n }\n\n // ==========================================================================\n // Fetch wrapper\n // Using XHR to avoid issues with older browsers\n // ==========================================================================\n\n function fetch(url, responseType = 'text') {\n return new Promise((resolve, reject) => {\n try {\n const request = new XMLHttpRequest();\n\n // Check for CORS support\n if (!('withCredentials' in request)) {\n return;\n }\n request.addEventListener('load', () => {\n if (responseType === 'text') {\n try {\n resolve(JSON.parse(request.responseText));\n } catch (_) {\n resolve(request.responseText);\n }\n } else {\n resolve(request.response);\n }\n });\n request.addEventListener('error', () => {\n throw new Error(request.status);\n });\n request.open('GET', url, true);\n\n // Set the required response type\n request.responseType = responseType;\n request.send();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n // ==========================================================================\n\n // Load an external SVG sprite\n function loadSprite(url, id) {\n if (!is.string(url)) {\n return;\n }\n const prefix = 'cache';\n const hasId = is.string(id);\n let isCached = false;\n const exists = () => document.getElementById(id) !== null;\n const update = (container, data) => {\n // eslint-disable-next-line no-param-reassign\n container.innerHTML = data;\n\n // Check again incase of race condition\n if (hasId && exists()) {\n return;\n }\n\n // Inject the SVG to the body\n document.body.insertAdjacentElement('afterbegin', container);\n };\n\n // Only load once if ID set\n if (!hasId || !exists()) {\n const useStorage = Storage.supported;\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (useStorage) {\n const cached = window.localStorage.getItem(`${prefix}-${id}`);\n isCached = cached !== null;\n if (isCached) {\n const data = JSON.parse(cached);\n update(container, data.content);\n }\n }\n\n // Get the sprite\n fetch(url).then(result => {\n if (is.empty(result)) {\n return;\n }\n if (useStorage) {\n try {\n window.localStorage.setItem(`${prefix}-${id}`, JSON.stringify({\n content: result\n }));\n } catch (_) {\n // Do nothing\n }\n }\n update(container, result);\n }).catch(() => {});\n }\n }\n\n // ==========================================================================\n\n // Time helpers\n const getHours = value => Math.trunc(value / 60 / 60 % 60, 10);\n const getMinutes = value => Math.trunc(value / 60 % 60, 10);\n const getSeconds = value => Math.trunc(value % 60, 10);\n\n // Format time to UI friendly string\n function formatTime(time = 0, displayHours = false, inverted = false) {\n // Bail if the value isn't a number\n if (!is.number(time)) {\n return formatTime(undefined, displayHours, inverted);\n }\n\n // Format time component to add leading zero\n const format = value => `0${value}`.slice(-2);\n // Breakdown to hours, mins, secs\n let hours = getHours(time);\n const mins = getMinutes(time);\n const secs = getSeconds(time);\n\n // Do we need to display hours?\n if (displayHours || hours > 0) {\n hours = `${hours}:`;\n } else {\n hours = '';\n }\n\n // Render\n return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n }\n\n // ==========================================================================\n\n // TODO: Don't export a massive object - break down and create class\n const controls = {\n // Get icon URL\n getIconUrl() {\n const url = new URL(this.config.iconUrl, window.location);\n const host = window.location.host ? window.location.host : window.top.location.host;\n const cors = url.host !== host || browser.isIE && !window.svg4everybody;\n return {\n url: this.config.iconUrl,\n cors\n };\n },\n // Find the UI controls\n findElements() {\n try {\n this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: getElements.call(this, this.config.selectors.buttons.play),\n pause: getElement.call(this, this.config.selectors.buttons.pause),\n restart: getElement.call(this, this.config.selectors.buttons.restart),\n rewind: getElement.call(this, this.config.selectors.buttons.rewind),\n fastForward: getElement.call(this, this.config.selectors.buttons.fastForward),\n mute: getElement.call(this, this.config.selectors.buttons.mute),\n pip: getElement.call(this, this.config.selectors.buttons.pip),\n airplay: getElement.call(this, this.config.selectors.buttons.airplay),\n settings: getElement.call(this, this.config.selectors.buttons.settings),\n captions: getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: getElement.call(this, this.config.selectors.buttons.fullscreen)\n };\n\n // Progress\n this.elements.progress = getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: getElement.call(this, this.config.selectors.inputs.seek),\n volume: getElement.call(this, this.config.selectors.inputs.volume)\n };\n\n // Display\n this.elements.display = {\n buffer: getElement.call(this, this.config.selectors.display.buffer),\n currentTime: getElement.call(this, this.config.selectors.display.currentTime),\n duration: getElement.call(this, this.config.selectors.display.duration)\n };\n\n // Seek tooltip\n if (is.element(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(`.${this.config.classNames.tooltip}`);\n }\n return true;\n } catch (error) {\n // Log it\n this.debug.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n return false;\n }\n },\n // Create icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.cors ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n // Create \n const icon = document.createElementNS(namespace, 'svg');\n setAttributes(icon, extend(attributes, {\n 'aria-hidden': 'true',\n focusable: 'false'\n }));\n\n // Create the to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n if ('href' in use) {\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n }\n\n // Always set the older attribute even though it's \"deprecated\" (it'll be around for ages)\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n\n // Add to \n icon.appendChild(use);\n return icon;\n },\n // Create hidden text label\n createLabel(key, attr = {}) {\n const text = i18n.get(key, this.config);\n const attributes = {\n ...attr,\n class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ')\n };\n return createElement('span', attributes, text);\n },\n // Create a badge\n createBadge(text) {\n if (is.empty(text)) {\n return null;\n }\n const badge = createElement('span', {\n class: this.config.classNames.menu.value\n });\n badge.appendChild(createElement('span', {\n class: this.config.classNames.menu.badge\n }, text));\n return badge;\n },\n // Create a
`);\n }\n\n // Set position\n tipElement.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n toggle(event.type === 'mouseenter');\n }\n },\n // Handle time change event\n timeUpdate(event) {\n // Only invert if only one time element is displayed and used for both duration and currentTime\n const invert = !is.element(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n controls.updateTimeDisplay.call(this, this.elements.display.currentTime, invert ? this.duration - this.currentTime : this.currentTime, invert);\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n controls.updateProgress.call(this, event);\n },\n // Show the duration on metadataloaded or durationchange events\n durationUpdate() {\n // Bail if no UI or durationchange event triggered after playing/seek when invertTime is false\n if (!this.supported.ui || !this.config.invertTime && this.currentTime) {\n return;\n }\n\n // If duration is the 2**32 (shaka), Infinity (HLS), DASH-IF (Number.MAX_SAFE_INTEGER || Number.MAX_VALUE) indicating live we hide the currentTime and progressbar.\n // https://github.com/video-dev/hls.js/blob/5820d29d3c4c8a46e8b75f1e3afa3e68c1a9a2db/src/controller/buffer-controller.js#L415\n // https://github.com/google/shaka-player/blob/4d889054631f4e1cf0fbd80ddd2b71887c02e232/lib/media/streaming_engine.js#L1062\n // https://github.com/Dash-Industry-Forum/dash.js/blob/69859f51b969645b234666800d4cb596d89c602d/src/dash/models/DashManifestModel.js#L338\n if (this.duration >= 2 ** 32) {\n toggleHidden(this.elements.display.currentTime, true);\n toggleHidden(this.elements.progress, true);\n return;\n }\n\n // Update ARIA values\n if (is.element(this.elements.inputs.seek)) {\n this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration);\n }\n\n // If there's a spot to display duration\n const hasDuration = is.element(this.elements.display.duration);\n\n // If there's only one time display, display duration there\n if (!hasDuration && this.config.displayDuration && this.paused) {\n controls.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (hasDuration) {\n controls.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);\n }\n if (this.config.markers.enabled) {\n controls.setMarkers.call(this);\n }\n\n // Update the tooltip (if visible)\n controls.updateSeekTooltip.call(this);\n },\n // Hide/show a tab\n toggleMenuButton(setting, toggle) {\n toggleHidden(this.elements.settings.buttons[setting], !toggle);\n },\n // Update the selected setting\n updateSetting(setting, container, input) {\n const pane = this.elements.settings.panels[setting];\n let value = null;\n let list = container;\n if (setting === 'captions') {\n value = this.currentTrack;\n } else {\n value = !is.empty(input) ? input : this[setting];\n\n // Get default\n if (is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) {\n this.debug.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.debug.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n }\n\n // Get the list if we need to\n if (!is.element(list)) {\n list = pane && pane.querySelector('[role=\"menu\"]');\n }\n\n // If there's no list it means it's not been rendered...\n if (!is.element(list)) {\n return;\n }\n\n // Update the label\n const label = this.elements.settings.buttons[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n\n // Find the radio option and check it\n const target = list && list.querySelector(`[value=\"${value}\"]`);\n if (is.element(target)) {\n target.checked = true;\n }\n },\n // Translate a value into a nice label\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? i18n.get('normal', this.config) : `${value}×`;\n case 'quality':\n if (is.number(value)) {\n const label = i18n.get(`qualityLabel.${value}`, this.config);\n if (!label.length) {\n return `${value}p`;\n }\n return label;\n }\n return toTitleCase(value);\n case 'captions':\n return captions.getLabel.call(this);\n default:\n return null;\n }\n },\n // Set the quality menu\n setQualityMenu(options) {\n // Menu required\n if (!is.element(this.elements.settings.panels.quality)) {\n return;\n }\n const type = 'quality';\n const list = this.elements.settings.panels.quality.querySelector('[role=\"menu\"]');\n\n // Set options if passed and filter based on uniqueness and config\n if (is.array(options)) {\n this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));\n }\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.quality) && this.options.quality.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n const label = i18n.get(`qualityBadge.${quality}`, this.config);\n if (!label.length) {\n return null;\n }\n return controls.createBadge.call(this, label);\n };\n\n // Sort options by the config and then render options\n this.options.quality.sort((a, b) => {\n const sorting = this.config.quality.options;\n return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;\n }).forEach(quality => {\n controls.createMenuItem.call(this, {\n value: quality,\n list,\n type,\n title: controls.getLabel.call(this, 'quality', quality),\n badge: getBadge(quality)\n });\n });\n controls.updateSetting.call(this, type, list);\n },\n // Set the looping options\n /* setLoopMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.loop)) {\n return;\n }\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panels.loop.querySelector('[role=\"menu\"]');\n // Show the pane and tab\n toggleHidden(this.elements.settings.buttons.loop, false);\n toggleHidden(this.elements.settings.panels.loop, false);\n // Toggle the pane and tab\n const toggle = !is.empty(this.loop.options);\n controls.toggleMenuButton.call(this, 'loop', toggle);\n // Empty the menu\n emptyElement(list);\n options.forEach(option => {\n const item = createElement('li');\n const button = createElement(\n 'button',\n extend(getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n i18n.get(option, this.config)\n );\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n item.appendChild(button);\n list.appendChild(item);\n });\n }, */\n\n // Get current selected caption language\n // TODO: rework this to user the getter in the API?\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.captions)) {\n return;\n }\n\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panels.captions.querySelector('[role=\"menu\"]');\n const tracks = captions.getTracks.call(this);\n const toggle = Boolean(tracks.length);\n\n // Toggle the pane and tab\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If there's no captions, bail\n if (!toggle) {\n return;\n }\n\n // Generate options data\n const options = tracks.map((track, value) => ({\n value,\n checked: this.captions.toggled && this.currentTrack === value,\n title: captions.getLabel.call(this, track),\n badge: track.language && controls.createBadge.call(this, track.language.toUpperCase()),\n list,\n type: 'language'\n }));\n\n // Add the \"Disabled\" option to turn off captions\n options.unshift({\n value: -1,\n checked: !this.captions.toggled,\n title: i18n.get('disabled', this.config),\n list,\n type: 'language'\n });\n\n // Generate options\n options.forEach(controls.createMenuItem.bind(this));\n controls.updateSetting.call(this, type, list);\n },\n // Set a list of available captions languages\n setSpeedMenu() {\n // Menu required\n if (!is.element(this.elements.settings.panels.speed)) {\n return;\n }\n const type = 'speed';\n const list = this.elements.settings.panels.speed.querySelector('[role=\"menu\"]');\n\n // Filter out invalid speeds\n this.options.speed = this.options.speed.filter(o => o >= this.minimumSpeed && o <= this.maximumSpeed);\n\n // Toggle the pane and tab\n const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;\n controls.toggleMenuButton.call(this, type, toggle);\n\n // Empty the menu\n emptyElement(list);\n\n // Check if we need to toggle the parent\n controls.checkMenu.call(this);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Create items\n this.options.speed.forEach(speed => {\n controls.createMenuItem.call(this, {\n value: speed,\n list,\n type,\n title: controls.getLabel.call(this, 'speed', speed)\n });\n });\n controls.updateSetting.call(this, type, list);\n },\n // Check if we need to hide/show the settings menu\n checkMenu() {\n const {\n buttons\n } = this.elements.settings;\n const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden);\n toggleHidden(this.elements.settings.menu, !visible);\n },\n // Focus the first menu item in a given (or visible) menu\n focusFirstMenuItem(pane, tabFocus = false) {\n if (this.elements.settings.popup.hidden) {\n return;\n }\n let target = pane;\n if (!is.element(target)) {\n target = Object.values(this.elements.settings.panels).find(p => !p.hidden);\n }\n const firstItem = target.querySelector('[role^=\"menuitem\"]');\n setFocus.call(this, firstItem, tabFocus);\n },\n // Show/hide menu\n toggleMenu(input) {\n const {\n popup\n } = this.elements.settings;\n const button = this.elements.buttons.settings;\n\n // Menu and button are required\n if (!is.element(popup) || !is.element(button)) {\n return;\n }\n\n // True toggle by default\n const {\n hidden\n } = popup;\n let show = hidden;\n if (is.boolean(input)) {\n show = input;\n } else if (is.keyboardEvent(input) && input.key === 'Escape') {\n show = false;\n } else if (is.event(input)) {\n // If Plyr is in a shadowDOM, the event target is set to the component, instead of the\n // Element in the shadowDOM. The path, if available, is complete.\n const target = is.function(input.composedPath) ? input.composedPath()[0] : input.target;\n const isMenuItem = popup.contains(target);\n\n // If the click was inside the menu or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || !isMenuItem && input.target !== button && show) {\n return;\n }\n }\n\n // Set button attributes\n button.setAttribute('aria-expanded', show);\n\n // Show the actual popup\n toggleHidden(popup, !show);\n\n // Add class hook\n toggleClass(this.elements.container, this.config.classNames.menu.open, show);\n\n // Focus the first item if key interaction\n if (show && is.keyboardEvent(input)) {\n controls.focusFirstMenuItem.call(this, null, true);\n } else if (!show && !hidden) {\n // If closing, re-focus the button\n setFocus.call(this, button, is.keyboardEvent(input));\n }\n },\n // Get the natural size of a menu panel\n getMenuSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.removeAttribute('hidden');\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n removeElement(clone);\n return {\n width,\n height\n };\n },\n // Show a panel in the menu\n showMenuPanel(type = '', tabFocus = false) {\n const target = this.elements.container.querySelector(`#plyr-settings-${this.id}-${type}`);\n\n // Nothing to show, bail\n if (!is.element(target)) {\n return;\n }\n\n // Hide all other panels\n const container = target.parentNode;\n const current = Array.from(container.children).find(node => !node.hidden);\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getMenuSize.call(this, target);\n\n // Restore auto height/width\n const restore = event => {\n // We're only bothered about height and width on the container\n if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n off.call(this, container, transitionEndEvent, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n on.call(this, container, transitionEndEvent, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n toggleHidden(current, true);\n\n // Set attributes on target\n toggleHidden(target, false);\n\n // Focus the first item\n controls.focusFirstMenuItem.call(this, target, tabFocus);\n },\n // Set the download URL\n setDownloadUrl() {\n const button = this.elements.buttons.download;\n\n // Bail if no button\n if (!is.element(button)) {\n return;\n }\n\n // Set attribute\n button.setAttribute('href', this.download);\n },\n // Build the default HTML\n create(data) {\n const {\n bindMenuItemShortcuts,\n createButton,\n createProgress,\n createRange,\n createTime,\n setQualityMenu,\n setSpeedMenu,\n showMenuPanel\n } = controls;\n this.elements.controls = null;\n\n // Larger overlaid play button\n if (is.array(this.config.controls) && this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(createButton.call(this, 'play-large'));\n }\n\n // Create the container\n const container = createElement('div', getAttributesFromSelector(this.config.selectors.controls.wrapper));\n this.elements.controls = container;\n\n // Default item attributes\n const defaultAttributes = {\n class: 'plyr__controls__item'\n };\n\n // Loop through controls in order\n dedupe(is.array(this.config.controls) ? this.config.controls : []).forEach(control => {\n // Restart button\n if (control === 'restart') {\n container.appendChild(createButton.call(this, 'restart', defaultAttributes));\n }\n\n // Rewind button\n if (control === 'rewind') {\n container.appendChild(createButton.call(this, 'rewind', defaultAttributes));\n }\n\n // Play/Pause button\n if (control === 'play') {\n container.appendChild(createButton.call(this, 'play', defaultAttributes));\n }\n\n // Fast forward button\n if (control === 'fast-forward') {\n container.appendChild(createButton.call(this, 'fast-forward', defaultAttributes));\n }\n\n // Progress\n if (control === 'progress') {\n const progressContainer = createElement('div', {\n class: `${defaultAttributes.class} plyr__progress__container`\n });\n const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress));\n\n // Seek range slider\n progress.appendChild(createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`\n }));\n\n // Buffer progress\n progress.appendChild(createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = createElement('span', {\n class: this.config.classNames.tooltip\n }, '00:00');\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n this.elements.progress = progress;\n progressContainer.appendChild(this.elements.progress);\n container.appendChild(progressContainer);\n }\n\n // Media current time display\n if (control === 'current-time') {\n container.appendChild(createTime.call(this, 'currentTime', defaultAttributes));\n }\n\n // Media duration display\n if (control === 'duration') {\n container.appendChild(createTime.call(this, 'duration', defaultAttributes));\n }\n\n // Volume controls\n if (control === 'mute' || control === 'volume') {\n let {\n volume\n } = this.elements;\n\n // Create the volume container if needed\n if (!is.element(volume) || !container.contains(volume)) {\n volume = createElement('div', extend({}, defaultAttributes, {\n class: `${defaultAttributes.class} plyr__volume`.trim()\n }));\n this.elements.volume = volume;\n container.appendChild(volume);\n }\n\n // Toggle mute button\n if (control === 'mute') {\n volume.appendChild(createButton.call(this, 'mute'));\n }\n\n // Volume range control\n // Ignored on iOS as it's handled globally\n // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html\n if (control === 'volume' && !browser.isIos) {\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume\n };\n\n // Create the volume range slider\n volume.appendChild(createRange.call(this, 'volume', extend(attributes, {\n id: `plyr-volume-${data.id}`\n })));\n }\n }\n\n // Toggle captions button\n if (control === 'captions') {\n container.appendChild(createButton.call(this, 'captions', defaultAttributes));\n }\n\n // Settings button / menu\n if (control === 'settings' && !is.empty(this.config.settings)) {\n const wrapper = createElement('div', extend({}, defaultAttributes, {\n class: `${defaultAttributes.class} plyr__menu`.trim(),\n hidden: ''\n }));\n wrapper.appendChild(createButton.call(this, 'settings', {\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false\n }));\n const popup = createElement('div', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n hidden: ''\n });\n const inner = createElement('div');\n const home = createElement('div', {\n id: `plyr-settings-${data.id}-home`\n });\n\n // Create the menu\n const menu = createElement('div', {\n role: 'menu'\n });\n home.appendChild(menu);\n inner.appendChild(home);\n this.elements.settings.panels.home = home;\n\n // Build the menu items\n this.config.settings.forEach(type => {\n // TODO: bundle this with the createMenuItem helper and bindings\n const menuItem = createElement('button', extend(getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n role: 'menuitem',\n 'aria-haspopup': true,\n hidden: ''\n }));\n\n // Bind menu shortcuts for keyboard users\n bindMenuItemShortcuts.call(this, menuItem, type);\n\n // Show menu on click\n on.call(this, menuItem, 'click', () => {\n showMenuPanel.call(this, type, false);\n });\n const flex = createElement('span', null, i18n.get(type, this.config));\n const value = createElement('span', {\n class: this.config.classNames.menu.value\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n flex.appendChild(value);\n menuItem.appendChild(flex);\n menu.appendChild(menuItem);\n\n // Build the panes\n const pane = createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n hidden: ''\n });\n\n // Back button\n const backButton = createElement('button', {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`\n });\n\n // Visible label\n backButton.appendChild(createElement('span', {\n 'aria-hidden': true\n }, i18n.get(type, this.config)));\n\n // Screen reader label\n backButton.appendChild(createElement('span', {\n class: this.config.classNames.hidden\n }, i18n.get('menuBack', this.config)));\n\n // Go back via keyboard\n on.call(this, pane, 'keydown', event => {\n if (event.key !== 'ArrowLeft') return;\n\n // Prevent seek\n event.preventDefault();\n event.stopPropagation();\n\n // Show the respective menu\n showMenuPanel.call(this, 'home', true);\n }, false);\n\n // Go back via button click\n on.call(this, backButton, 'click', () => {\n showMenuPanel.call(this, 'home', false);\n });\n\n // Add to pane\n pane.appendChild(backButton);\n\n // Menu\n pane.appendChild(createElement('div', {\n role: 'menu'\n }));\n inner.appendChild(pane);\n this.elements.settings.buttons[type] = menuItem;\n this.elements.settings.panels[type] = pane;\n });\n popup.appendChild(inner);\n wrapper.appendChild(popup);\n container.appendChild(wrapper);\n this.elements.settings.popup = popup;\n this.elements.settings.menu = wrapper;\n }\n\n // Picture in picture button\n if (control === 'pip' && support.pip) {\n container.appendChild(createButton.call(this, 'pip', defaultAttributes));\n }\n\n // Airplay button\n if (control === 'airplay' && support.airplay) {\n container.appendChild(createButton.call(this, 'airplay', defaultAttributes));\n }\n\n // Download button\n if (control === 'download') {\n const attributes = extend({}, defaultAttributes, {\n element: 'a',\n href: this.download,\n target: '_blank'\n });\n\n // Set download attribute for HTML5 only\n if (this.isHTML5) {\n attributes.download = '';\n }\n const {\n download\n } = this.config.urls;\n if (!is.url(download) && this.isEmbed) {\n extend(attributes, {\n icon: `logo-${this.provider}`,\n label: this.provider\n });\n }\n container.appendChild(createButton.call(this, 'download', attributes));\n }\n\n // Toggle fullscreen button\n if (control === 'fullscreen') {\n container.appendChild(createButton.call(this, 'fullscreen', defaultAttributes));\n }\n });\n\n // Set available quality levels\n if (this.isHTML5) {\n setQualityMenu.call(this, html5.getQualityOptions.call(this));\n }\n setSpeedMenu.call(this);\n return container;\n },\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const icon = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (icon.cors) {\n loadSprite(icon.url, 'sprite-plyr');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n this.elements.controls = null;\n\n // Set template properties\n const props = {\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title\n };\n let update = true;\n\n // If function, run it and use output\n if (is.function(this.config.controls)) {\n this.config.controls = this.config.controls.call(this, props);\n }\n\n // Convert falsy controls to empty array (primarily for empty strings)\n if (!this.config.controls) {\n this.config.controls = [];\n }\n if (is.element(this.config.controls) || is.string(this.config.controls)) {\n // HTMLElement or Non-empty string passed as the option\n container = this.config.controls;\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: this.speed,\n quality: this.quality,\n captions: captions.getLabel.call(this)\n // TODO: Looping\n // loop: 'None',\n });\n\n update = false;\n }\n\n // Replace props with their value\n const replace = input => {\n let result = input;\n Object.entries(props).forEach(([key, value]) => {\n result = replaceAll(result, `{${key}}`, value);\n });\n return result;\n };\n\n // Update markup\n if (update) {\n if (is.string(this.config.controls)) {\n container = replace(container);\n }\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!is.element(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML (needs to be before captions, hence \"afterbegin\")\n const insertMethod = is.element(container) ? 'insertAdjacentElement' : 'insertAdjacentHTML';\n target[insertMethod]('afterbegin', container);\n\n // Find the elements if need be\n if (!is.element(this.elements.controls)) {\n controls.findElements.call(this);\n }\n\n // Add pressed property to buttons\n if (!is.empty(this.elements.buttons)) {\n const addProperty = button => {\n const className = this.config.classNames.controlPressed;\n button.setAttribute('aria-pressed', 'false');\n Object.defineProperty(button, 'pressed', {\n configurable: true,\n enumerable: true,\n get() {\n return hasClass(button, className);\n },\n set(pressed = false) {\n toggleClass(button, className, pressed);\n button.setAttribute('aria-pressed', pressed ? 'true' : 'false');\n }\n });\n };\n\n // Toggle classname when pressed property is set\n Object.values(this.elements.buttons).filter(Boolean).forEach(button => {\n if (is.array(button) || is.nodeList(button)) {\n Array.from(button).filter(Boolean).forEach(addProperty);\n } else {\n addProperty(button);\n }\n });\n }\n\n // Edge sometimes doesn't finish the paint so force a repaint\n if (browser.isEdge) {\n repaint(target);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const {\n classNames,\n selectors\n } = this.config;\n const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;\n const labels = getElements.call(this, selector);\n Array.from(labels).forEach(label => {\n toggleClass(label, this.config.classNames.hidden, false);\n toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n // Set media metadata\n setMediaMetadata() {\n try {\n if ('mediaSession' in navigator) {\n navigator.mediaSession.metadata = new window.MediaMetadata({\n title: this.config.mediaMetadata.title,\n artist: this.config.mediaMetadata.artist,\n album: this.config.mediaMetadata.album,\n artwork: this.config.mediaMetadata.artwork\n });\n }\n } catch (_) {\n // Do nothing\n }\n },\n // Add markers\n setMarkers() {\n var _this$config$markers2, _this$config$markers3;\n if (!this.duration || this.elements.markers) return;\n\n // Get valid points\n const points = (_this$config$markers2 = this.config.markers) === null || _this$config$markers2 === void 0 ? void 0 : (_this$config$markers3 = _this$config$markers2.points) === null || _this$config$markers3 === void 0 ? void 0 : _this$config$markers3.filter(({\n time\n }) => time > 0 && time < this.duration);\n if (!(points !== null && points !== void 0 && points.length)) return;\n const containerFragment = document.createDocumentFragment();\n const pointsFragment = document.createDocumentFragment();\n let tipElement = null;\n const tipVisible = `${this.config.classNames.tooltip}--visible`;\n const toggleTip = show => toggleClass(tipElement, tipVisible, show);\n\n // Inject markers to progress container\n points.forEach(point => {\n const markerElement = createElement('span', {\n class: this.config.classNames.marker\n }, '');\n const left = `${point.time / this.duration * 100}%`;\n if (tipElement) {\n // Show on hover\n markerElement.addEventListener('mouseenter', () => {\n if (point.label) return;\n tipElement.style.left = left;\n tipElement.innerHTML = point.label;\n toggleTip(true);\n });\n\n // Hide on leave\n markerElement.addEventListener('mouseleave', () => {\n toggleTip(false);\n });\n }\n markerElement.addEventListener('click', () => {\n this.currentTime = point.time;\n });\n markerElement.style.left = left;\n pointsFragment.appendChild(markerElement);\n });\n containerFragment.appendChild(pointsFragment);\n\n // Inject a tooltip if needed\n if (!this.config.tooltips.seek) {\n tipElement = createElement('span', {\n class: this.config.classNames.tooltip\n }, '');\n containerFragment.appendChild(tipElement);\n }\n this.elements.markers = {\n points: pointsFragment,\n tip: tipElement\n };\n this.elements.progress.appendChild(containerFragment);\n }\n };\n\n // ==========================================================================\n\n /**\n * Parse a string to a URL object\n * @param {String} input - the URL to be parsed\n * @param {Boolean} safe - failsafe parsing\n */\n function parseUrl(input, safe = true) {\n let url = input;\n if (safe) {\n const parser = document.createElement('a');\n parser.href = url;\n url = parser.href;\n }\n try {\n return new URL(url);\n } catch (_) {\n return null;\n }\n }\n\n // Convert object to URLSearchParams\n function buildUrlParams(input) {\n const params = new URLSearchParams();\n if (is.object(input)) {\n Object.entries(input).forEach(([key, value]) => {\n params.set(key, value);\n });\n }\n return params;\n }\n\n // ==========================================================================\n const captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) {\n // Clear menu and hide\n if (is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n return;\n }\n\n // Inject the container\n if (!is.element(this.elements.captions)) {\n this.elements.captions = createElement('div', getAttributesFromSelector(this.config.selectors.captions));\n this.elements.captions.setAttribute('dir', 'auto');\n insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Fix IE captions if CORS is used\n // Fetch captions and inject as blobs instead (data URIs not supported!)\n if (browser.isIE && window.URL) {\n const elements = this.media.querySelectorAll('track');\n Array.from(elements).forEach(track => {\n const src = track.getAttribute('src');\n const url = parseUrl(src);\n if (url !== null && url.hostname !== window.location.href.hostname && ['http:', 'https:'].includes(url.protocol)) {\n fetch(src, 'blob').then(blob => {\n track.setAttribute('src', window.URL.createObjectURL(blob));\n }).catch(() => {\n removeElement(track);\n });\n }\n });\n }\n\n // Get and set initial data\n // The \"preferred\" options are not realized unless / until the wanted language has a match\n // * languages: Array of user's browser languages.\n // * language: The language preferred by user settings or config\n // * active: The state preferred by user settings or config\n // * toggled: The real captions state\n\n const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];\n const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));\n let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();\n\n // Use first browser language when language is 'auto'\n if (language === 'auto') {\n [language] = languages;\n }\n let active = this.storage.get('captions');\n if (!is.boolean(active)) {\n ({\n active\n } = this.config.captions);\n }\n Object.assign(this.captions, {\n toggled: false,\n active,\n language,\n languages\n });\n\n // Watch changes to textTracks and update captions menu\n if (this.isHTML5) {\n const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';\n on.call(this, this.media.textTracks, trackEvents, captions.update.bind(this));\n }\n\n // Update available languages in list next tick (the event must not be triggered before the listeners)\n setTimeout(captions.update.bind(this), 0);\n },\n // Update available language options in settings based on tracks\n update() {\n const tracks = captions.getTracks.call(this, true);\n // Get the wanted language\n const {\n active,\n language,\n meta,\n currentTrackNode\n } = this.captions;\n const languageExists = Boolean(tracks.find(track => track.language === language));\n\n // Handle tracks (add event listener and \"pseudo\"-default)\n if (this.isHTML5 && this.isVideo) {\n tracks.filter(track => !meta.get(track)).forEach(track => {\n this.debug.log('Track added', track);\n\n // Attempt to store if the original dom element was \"default\"\n meta.set(track, {\n default: track.mode === 'showing'\n });\n\n // Turn off native caption rendering to avoid double captions\n // Note: mode='hidden' forces a track to download. To ensure every track\n // isn't downloaded at once, only 'showing' tracks should be reassigned\n // eslint-disable-next-line no-param-reassign\n if (track.mode === 'showing') {\n // eslint-disable-next-line no-param-reassign\n track.mode = 'hidden';\n }\n\n // Add event listener for cue changes\n on.call(this, track, 'cuechange', () => captions.updateCues.call(this));\n });\n }\n\n // Update language first time it matches, or if the previous matching track was removed\n if (languageExists && this.language !== language || !tracks.includes(currentTrackNode)) {\n captions.setLanguage.call(this, language);\n captions.toggle.call(this, active && languageExists);\n }\n\n // Enable or disable captions based on track length\n if (this.elements) {\n toggleClass(this.elements.container, this.config.classNames.captions.enabled, !is.empty(tracks));\n }\n\n // Update available languages in list\n if (is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n // Toggle captions display\n // Used internally for the toggleCaptions method, with the passive option forced to false\n toggle(input, passive = true) {\n // If there's no full support\n if (!this.supported.ui) {\n return;\n }\n const {\n toggled\n } = this.captions; // Current state\n const activeClass = this.config.classNames.captions.active;\n // Get the next state\n // If the method is called without parameter, toggle based on current value\n const active = is.nullOrUndefined(input) ? !toggled : input;\n\n // Update state and trigger event\n if (active !== toggled) {\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.active = active;\n this.storage.set({\n captions: active\n });\n }\n\n // Force language if the call isn't passive and there is no matching language to toggle to\n if (!this.language && active && !passive) {\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [this.captions.language, ...this.captions.languages], true);\n\n // Override user preferences to avoid switching languages if a matching track is added\n this.captions.language = track.language;\n\n // Set caption, but don't store in localStorage as user preference\n captions.set.call(this, tracks.indexOf(track));\n return;\n }\n\n // Toggle button if it's enabled\n if (this.elements.buttons.captions) {\n this.elements.buttons.captions.pressed = active;\n }\n\n // Add class hook\n toggleClass(this.elements.container, activeClass, active);\n this.captions.toggled = active;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // Trigger event (not used internally)\n triggerEvent.call(this, this.media, active ? 'captionsenabled' : 'captionsdisabled');\n }\n\n // Wait for the call stack to clear before setting mode='hidden'\n // on the active track - forcing the browser to download it\n setTimeout(() => {\n if (active && this.captions.toggled) {\n this.captions.currentTrackNode.mode = 'hidden';\n }\n });\n },\n // Set captions by track index\n // Used internally for the currentTrack setter with the passive option forced to false\n set(index, passive = true) {\n const tracks = captions.getTracks.call(this);\n\n // Disable captions if setting to -1\n if (index === -1) {\n captions.toggle.call(this, false, passive);\n return;\n }\n if (!is.number(index)) {\n this.debug.warn('Invalid caption argument', index);\n return;\n }\n if (!(index in tracks)) {\n this.debug.warn('Track not found', index);\n return;\n }\n if (this.captions.currentTrack !== index) {\n this.captions.currentTrack = index;\n const track = tracks[index];\n const {\n language\n } = track || {};\n\n // Store reference to node for invalidation on remove\n this.captions.currentTrackNode = track;\n\n // Update settings menu\n controls.updateSetting.call(this, 'captions');\n\n // When passive, don't override user preferences\n if (!passive) {\n this.captions.language = language;\n this.storage.set({\n language\n });\n }\n\n // Handle Vimeo captions\n if (this.isVimeo) {\n this.embed.enableTextTrack(language);\n }\n\n // Trigger event\n triggerEvent.call(this, this.media, 'languagechange');\n }\n\n // Show captions\n captions.toggle.call(this, true, passive);\n if (this.isHTML5 && this.isVideo) {\n // If we change the active track while a cue is already displayed we need to update it\n captions.updateCues.call(this);\n }\n },\n // Set captions by language\n // Used internally for the language setter with the passive option forced to false\n setLanguage(input, passive = true) {\n if (!is.string(input)) {\n this.debug.warn('Invalid language argument', input);\n return;\n }\n // Normalize\n const language = input.toLowerCase();\n this.captions.language = language;\n\n // Set currentTrack\n const tracks = captions.getTracks.call(this);\n const track = captions.findTrack.call(this, [language]);\n captions.set.call(this, tracks.indexOf(track), passive);\n },\n // Get current valid caption tracks\n // If update is false it will also ignore tracks without metadata\n // This is used to \"freeze\" the language options when captions.update is false\n getTracks(update = false) {\n // Handle media or textTracks missing or null\n const tracks = Array.from((this.media || {}).textTracks || []);\n // For HTML5, use cache instead of current tracks when it exists (if captions.update is false)\n // Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)\n return tracks.filter(track => !this.isHTML5 || update || this.captions.meta.has(track)).filter(track => ['captions', 'subtitles'].includes(track.kind));\n },\n // Match tracks based on languages and get the first\n findTrack(languages, force = false) {\n const tracks = captions.getTracks.call(this);\n const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default);\n const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));\n let track;\n languages.every(language => {\n track = sorted.find(t => t.language === language);\n return !track; // Break iteration if there is a match\n });\n\n // If no match is found but is required, get first\n return track || (force ? sorted[0] : undefined);\n },\n // Get the current track\n getCurrentTrack() {\n return captions.getTracks.call(this)[this.currentTrack];\n },\n // Get UI label for track\n getLabel(track) {\n let currentTrack = track;\n if (!is.track(currentTrack) && support.textTracks && this.captions.toggled) {\n currentTrack = captions.getCurrentTrack.call(this);\n }\n if (is.track(currentTrack)) {\n if (!is.empty(currentTrack.label)) {\n return currentTrack.label;\n }\n if (!is.empty(currentTrack.language)) {\n return track.language.toUpperCase();\n }\n return i18n.get('enabled', this.config);\n }\n return i18n.get('disabled', this.config);\n },\n // Update captions using current track's active cues\n // Also optional array argument in case there isn't any track (ex: vimeo)\n updateCues(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n if (!is.element(this.elements.captions)) {\n this.debug.warn('No captions element to render to');\n return;\n }\n\n // Only accept array or empty input\n if (!is.nullOrUndefined(input) && !Array.isArray(input)) {\n this.debug.warn('updateCues: Invalid input', input);\n return;\n }\n let cues = input;\n\n // Get cues from track\n if (!cues) {\n const track = captions.getCurrentTrack.call(this);\n cues = Array.from((track || {}).activeCues || []).map(cue => cue.getCueAsHTML()).map(getHTML);\n }\n\n // Set new caption text\n const content = cues.map(cueText => cueText.trim()).join('\\n');\n const changed = content !== this.elements.captions.innerHTML;\n if (changed) {\n // Empty the container and create a new child element\n emptyElement(this.elements.captions);\n const caption = createElement('span', getAttributesFromSelector(this.config.selectors.caption));\n caption.innerHTML = content;\n this.elements.captions.appendChild(caption);\n\n // Trigger event\n triggerEvent.call(this, this.media, 'cuechange');\n }\n }\n };\n\n // ==========================================================================\n // Plyr default config\n // ==========================================================================\n\n const defaults = {\n // Disable\n enabled: true,\n // Custom media title\n title: '',\n // Logging to console\n debug: false,\n // Auto play (if supported)\n autoplay: false,\n // Only allow one media playing at once (vimeo only)\n autopause: true,\n // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present)\n // TODO: Remove iosNative fullscreen option in favour of this (logic needs work)\n playsinline: true,\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n // Default volume\n volume: 1,\n muted: false,\n // Pass a custom duration\n duration: null,\n // Display the media duration on load in the current time position\n // If you have opted to display both duration and currentTime, this is ignored\n displayDuration: true,\n // Invert the current time to be a countdown\n invertTime: true,\n // Clicking the currentTime inverts it's value to show time left rather than elapsed\n toggleInvert: true,\n // Force an aspect ratio\n // The format must be `'w:h'` (e.g. `'16:9'`)\n ratio: null,\n // Click video container to play/pause\n clickToPlay: true,\n // Auto hide the controls\n hideControls: true,\n // Reset to start when playback ended\n resetOnEnd: false,\n // Disable the standard context menu\n disableContextMenu: true,\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/3.7.3/plyr.svg',\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n // Quality default\n quality: {\n default: 576,\n // The options to display in the UI, if available for the source media\n options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],\n forced: false,\n onChange: null\n },\n // Set loops\n loop: {\n active: false\n // start: null,\n // end: null,\n },\n\n // Speed default and options to display\n speed: {\n selected: 1,\n // The options to display in the UI, if available for the source media (e.g. Vimeo and YouTube only support 0.5x-4x)\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4]\n },\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false\n },\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true\n },\n // Captions settings\n captions: {\n active: false,\n language: 'auto',\n // Listen to new tracks added after Plyr is initialized.\n // This is needed for streaming captions, but may result in unselectable options\n update: false\n },\n // Fullscreen settings\n fullscreen: {\n enabled: true,\n // Allow fullscreen?\n fallback: true,\n // Fallback using full viewport/window\n iosNative: false // Use the native fullscreen in iOS (disables custom controls)\n // Selector for the fullscreen container so contextual / non-player content can remain visible in fullscreen mode\n // Non-ancestors of the player element will be ignored\n // container: null, // defaults to the player element\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr'\n },\n // Default controls\n controls: ['play-large',\n // 'restart',\n // 'rewind',\n 'play',\n // 'fast-forward',\n 'progress', 'current-time',\n // 'duration',\n 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay',\n // 'download',\n 'fullscreen'],\n settings: ['captions', 'quality', 'speed'],\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime}s',\n play: 'Play',\n pause: 'Pause',\n fastForward: 'Forward {seektime}s',\n seek: 'Seek',\n seekLabel: '{currentTime} of {duration}',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n mute: 'Mute',\n unmute: 'Unmute',\n enableCaptions: 'Enable captions',\n disableCaptions: 'Disable captions',\n download: 'Download',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n pip: 'PIP',\n menuBack: 'Go back to previous menu',\n speed: 'Speed',\n normal: 'Normal',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n disabled: 'Disabled',\n enabled: 'Enabled',\n advertisement: 'Ad',\n qualityBadge: {\n 2160: '4K',\n 1440: 'HD',\n 1080: 'HD',\n 720: 'HD',\n 576: 'SD',\n 480: 'SD'\n }\n },\n // URLs\n urls: {\n download: null,\n vimeo: {\n sdk: 'https://player.vimeo.com/api/player.js',\n iframe: 'https://player.vimeo.com/video/{0}?{1}',\n api: 'https://vimeo.com/api/oembed.json?url={0}'\n },\n youtube: {\n sdk: 'https://www.youtube.com/iframe_api',\n api: 'https://noembed.com/embed?url=https://www.youtube.com/watch?v={0}'\n },\n googleIMA: {\n sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js'\n }\n },\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n fastForward: null,\n mute: null,\n volume: null,\n captions: null,\n download: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null\n },\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied', 'ratechange', 'cuechange',\n // Custom events\n 'download', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',\n // YouTube\n 'statechange',\n // Quality\n 'qualitychange',\n // Ads\n 'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls'\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n fastForward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n download: '[data-plyr=\"download\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]'\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]'\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress__buffer',\n loop: '.plyr__progress__loop',\n // Used later\n volume: '.plyr__volume--display'\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n caption: '.plyr__caption'\n },\n // Class hooks added to the player in different states\n classNames: {\n type: 'plyr--{0}',\n provider: 'plyr--{0}',\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n videoFixedRatio: 'plyr__video-wrapper--fixed-ratio',\n embedContainer: 'plyr__video-embed__container',\n poster: 'plyr__poster',\n posterEnabled: 'plyr__poster-enabled',\n ads: 'plyr__ads',\n control: 'plyr__control',\n controlPressed: 'plyr__control--pressed',\n playing: 'plyr--playing',\n paused: 'plyr--paused',\n stopped: 'plyr--stopped',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n cues: 'plyr__cues',\n marker: 'plyr__progress__marker',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n noTransition: 'plyr--no-transition',\n display: {\n time: 'plyr__time'\n },\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n open: 'plyr--menu-open'\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active'\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback'\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active'\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active'\n },\n tabFocus: 'plyr__tab-focus',\n previewThumbnails: {\n // Tooltip thumbs\n thumbContainer: 'plyr__preview-thumb',\n thumbContainerShown: 'plyr__preview-thumb--is-shown',\n imageContainer: 'plyr__preview-thumb__image-container',\n timeContainer: 'plyr__preview-thumb__time-container',\n // Scrubbing\n scrubbingContainer: 'plyr__preview-scrubbing',\n scrubbingContainerShown: 'plyr__preview-scrubbing--is-shown'\n }\n },\n // Embed attributes\n attributes: {\n embed: {\n provider: 'data-plyr-provider',\n id: 'data-plyr-embed-id',\n hash: 'data-plyr-embed-hash'\n }\n },\n // Advertisements plugin\n // Register for an account here: http://vi.ai/publisher-video-monetization/?aid=plyrio\n ads: {\n enabled: false,\n publisherId: '',\n tagUrl: ''\n },\n // Preview Thumbnails plugin\n previewThumbnails: {\n enabled: false,\n src: ''\n },\n // Vimeo plugin\n vimeo: {\n byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: false,\n // Custom settings from Plyr\n customControls: true,\n referrerPolicy: null,\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy\n // Whether the owner of the video has a Pro or Business account\n // (which allows us to properly hide controls without CSS hacks, etc)\n premium: false\n },\n // YouTube plugin\n youtube: {\n rel: 0,\n // No related vids\n showinfo: 0,\n // Hide info\n iv_load_policy: 3,\n // Hide annotations\n modestbranding: 1,\n // Hide logos as much as possible (they still show one in the corner when paused)\n // Custom settings from Plyr\n customControls: true,\n noCookie: false // Whether to use an alternative version of YouTube without cookies\n },\n\n // Media Metadata\n mediaMetadata: {\n title: '',\n artist: '',\n album: '',\n artwork: []\n },\n // Markers\n markers: {\n enabled: false,\n points: []\n }\n };\n\n // ==========================================================================\n // Plyr states\n // ==========================================================================\n\n const pip = {\n active: 'picture-in-picture',\n inactive: 'inline'\n };\n\n // ==========================================================================\n // Plyr supported types and providers\n // ==========================================================================\n\n const providers = {\n html5: 'html5',\n youtube: 'youtube',\n vimeo: 'vimeo'\n };\n const types = {\n audio: 'audio',\n video: 'video'\n };\n\n /**\n * Get provider by URL\n * @param {String} url\n */\n function getProviderByUrl(url) {\n // YouTube\n if (/^(https?:\\/\\/)?(www\\.)?(youtube\\.com|youtube-nocookie\\.com|youtu\\.?be)\\/.+$/.test(url)) {\n return providers.youtube;\n }\n\n // Vimeo\n if (/^https?:\\/\\/player.vimeo.com\\/video\\/\\d{0,9}(?=\\b|\\/)/.test(url)) {\n return providers.vimeo;\n }\n return null;\n }\n\n // ==========================================================================\n // Console wrapper\n // ==========================================================================\n\n const noop = () => {};\n class Console {\n constructor(enabled = false) {\n this.enabled = window.console && enabled;\n if (this.enabled) {\n this.log('Debugging enabled');\n }\n }\n get log() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.log, console) : noop;\n }\n get warn() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;\n }\n get error() {\n // eslint-disable-next-line no-console\n return this.enabled ? Function.prototype.bind.call(console.error, console) : noop;\n }\n }\n\n class Fullscreen {\n constructor(player) {\n _defineProperty$1(this, \"onChange\", () => {\n if (!this.enabled) {\n return;\n }\n\n // Update toggle button\n const button = this.player.elements.buttons.fullscreen;\n if (is.element(button)) {\n button.pressed = this.active;\n }\n\n // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up\n const target = this.target === this.player.media ? this.target : this.player.elements.container;\n // Trigger an event\n triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);\n });\n _defineProperty$1(this, \"toggleFallback\", (toggle = false) => {\n // Store or restore scroll position\n if (toggle) {\n this.scrollPosition = {\n x: window.scrollX || 0,\n y: window.scrollY || 0\n };\n } else {\n window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);\n }\n\n // Toggle scroll\n document.body.style.overflow = toggle ? 'hidden' : '';\n\n // Toggle class hook\n toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);\n\n // Force full viewport on iPhone X+\n if (browser.isIos) {\n let viewport = document.head.querySelector('meta[name=\"viewport\"]');\n const property = 'viewport-fit=cover';\n\n // Inject the viewport meta if required\n if (!viewport) {\n viewport = document.createElement('meta');\n viewport.setAttribute('name', 'viewport');\n }\n\n // Check if the property already exists\n const hasProperty = is.string(viewport.content) && viewport.content.includes(property);\n if (toggle) {\n this.cleanupViewport = !hasProperty;\n if (!hasProperty) {\n viewport.content += `,${property}`;\n }\n } else if (this.cleanupViewport) {\n viewport.content = viewport.content.split(',').filter(part => part.trim() !== property).join(',');\n }\n }\n\n // Toggle button and fire events\n this.onChange();\n });\n _defineProperty$1(this, \"trapFocus\", event => {\n // Bail if iOS, not active, not the tab key\n if (browser.isIos || !this.active || event.key !== 'Tab') {\n return;\n }\n\n // Get the current focused element\n const focused = document.activeElement;\n const focusable = getElements.call(this.player, 'a[href], button:not(:disabled), input:not(:disabled), [tabindex]');\n const [first] = focusable;\n const last = focusable[focusable.length - 1];\n if (focused === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n first.focus();\n event.preventDefault();\n } else if (focused === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n last.focus();\n event.preventDefault();\n }\n });\n _defineProperty$1(this, \"update\", () => {\n if (this.enabled) {\n let mode;\n if (this.forceFallback) {\n mode = 'Fallback (forced)';\n } else if (Fullscreen.native) {\n mode = 'Native';\n } else {\n mode = 'Fallback';\n }\n this.player.debug.log(`${mode} fullscreen enabled`);\n } else {\n this.player.debug.log('Fullscreen not supported and fallback disabled');\n }\n\n // Add styling hook to show button\n toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);\n });\n _defineProperty$1(this, \"enter\", () => {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen doesn't need the request step\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n if (this.player.isVimeo) {\n this.player.embed.requestFullscreen();\n } else {\n this.target.webkitEnterFullscreen();\n }\n } else if (!Fullscreen.native || this.forceFallback) {\n this.toggleFallback(true);\n } else if (!this.prefix) {\n this.target.requestFullscreen({\n navigationUI: 'hide'\n });\n } else if (!is.empty(this.prefix)) {\n this.target[`${this.prefix}Request${this.property}`]();\n }\n });\n _defineProperty$1(this, \"exit\", () => {\n if (!this.enabled) {\n return;\n }\n\n // iOS native fullscreen\n if (browser.isIos && this.player.config.fullscreen.iosNative) {\n this.target.webkitExitFullscreen();\n silencePromise(this.player.play());\n } else if (!Fullscreen.native || this.forceFallback) {\n this.toggleFallback(false);\n } else if (!this.prefix) {\n (document.cancelFullScreen || document.exitFullscreen).call(document);\n } else if (!is.empty(this.prefix)) {\n const action = this.prefix === 'moz' ? 'Cancel' : 'Exit';\n document[`${this.prefix}${action}${this.property}`]();\n }\n });\n _defineProperty$1(this, \"toggle\", () => {\n if (!this.active) {\n this.enter();\n } else {\n this.exit();\n }\n });\n // Keep reference to parent\n this.player = player;\n\n // Get prefix\n this.prefix = Fullscreen.prefix;\n this.property = Fullscreen.property;\n\n // Scroll position\n this.scrollPosition = {\n x: 0,\n y: 0\n };\n\n // Force the use of 'full window/browser' rather than fullscreen\n this.forceFallback = player.config.fullscreen.fallback === 'force';\n\n // Get the fullscreen element\n // Checks container is an ancestor, defaults to null\n this.player.elements.fullscreen = player.config.fullscreen.container && closest$1(this.player.elements.container, player.config.fullscreen.container);\n\n // Register event listeners\n // Handle event (incase user presses escape etc)\n on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {\n // TODO: Filter for target??\n this.onChange();\n });\n\n // Fullscreen toggle on double click\n on.call(this.player, this.player.elements.container, 'dblclick', event => {\n // Ignore double click in controls\n if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {\n return;\n }\n this.player.listeners.proxy(event, this.toggle, 'fullscreen');\n });\n\n // Tap focus when in fullscreen\n on.call(this, this.player.elements.container, 'keydown', event => this.trapFocus(event));\n\n // Update the UI\n this.update();\n\n // this.toggle = this.toggle.bind(this);\n }\n\n // Determine if native supported\n static get native() {\n return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);\n }\n\n // If we're actually using native\n get usingNative() {\n return Fullscreen.native && !this.forceFallback;\n }\n\n // Get the prefix for handlers\n static get prefix() {\n // No prefix\n if (is.function(document.exitFullscreen)) {\n return '';\n }\n\n // Check for fullscreen support by vendor prefix\n let value = '';\n const prefixes = ['webkit', 'moz', 'ms'];\n prefixes.some(pre => {\n if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n }\n return false;\n });\n return value;\n }\n static get property() {\n return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen';\n }\n\n // Determine if fullscreen is enabled\n get enabled() {\n return (Fullscreen.native || this.player.config.fullscreen.fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo;\n }\n\n // Get active state\n get active() {\n if (!this.enabled) {\n return false;\n }\n\n // Fallback using classname\n if (!Fullscreen.native || this.forceFallback) {\n return hasClass(this.target, this.player.config.classNames.fullscreen.fallback);\n }\n const element = !this.prefix ? this.target.getRootNode().fullscreenElement : this.target.getRootNode()[`${this.prefix}${this.property}Element`];\n return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;\n }\n\n // Get target element\n get target() {\n return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.fullscreen || this.player.elements.container;\n }\n }\n\n // ==========================================================================\n // Load image avoiding xhr/fetch CORS issues\n // Server status can't be obtained this way unfortunately, so this uses \"naturalWidth\" to determine if the image has loaded\n // By default it checks if it is at least 1px, but you can add a second argument to change this\n // ==========================================================================\n\n function loadImage(src, minWidth = 1) {\n return new Promise((resolve, reject) => {\n const image = new Image();\n const handler = () => {\n delete image.onload;\n delete image.onerror;\n (image.naturalWidth >= minWidth ? resolve : reject)(image);\n };\n Object.assign(image, {\n onload: handler,\n onerror: handler,\n src\n });\n });\n }\n\n // ==========================================================================\n const ui = {\n addStyleHook() {\n toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle = false) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling?\n this.listeners.media();\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.debug.warn(`Basic support only for ${this.provider} ${this.type}`);\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!is.element(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n this.listeners.controls();\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup captions for HTML5\n if (this.isHTML5) {\n captions.setup.call(this);\n }\n\n // Reset volume\n this.volume = null;\n\n // Reset mute state\n this.muted = null;\n\n // Reset loop state\n this.loop = null;\n\n // Reset quality setting\n this.quality = null;\n\n // Reset speed\n this.speed = null;\n\n // Reset volume display\n controls.updateVolume.call(this);\n\n // Reset time display\n controls.timeUpdate.call(this);\n\n // Reset duration display\n controls.durationUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Check for picture-in-picture support\n toggleClass(this.elements.container, this.config.classNames.pip.supported, support.pip && this.isHTML5 && this.isVideo);\n\n // Check for airplay support\n toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5);\n\n // Add iOS class\n toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n toggleClass(this.elements.container, this.config.classNames.isTouch, this.touch);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n setTimeout(() => {\n triggerEvent.call(this, this.media, 'ready');\n }, 0);\n\n // Set the title\n ui.setTitle.call(this);\n\n // Assure the poster image is set, if the property was added before the element was created\n if (this.poster) {\n ui.setPoster.call(this, this.poster, false).catch(() => {});\n }\n\n // Manually set the duration if user has overridden it.\n // The event listeners for it doesn't get called if preload is disabled (#701)\n if (this.config.duration) {\n controls.durationUpdate.call(this);\n }\n\n // Media metadata\n if (this.config.mediaMetadata) {\n controls.setMediaMetadata.call(this);\n }\n },\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = i18n.get('play', this.config);\n\n // If there's a media title set, use that for the label\n if (is.string(this.config.title) && !is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n }\n\n // If there's a play button, set label\n Array.from(this.elements.buttons.play || []).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = getElement.call(this, 'iframe');\n if (!is.element(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !is.empty(this.config.title) ? this.config.title : 'video';\n const format = i18n.get('frameTitle', this.config);\n iframe.setAttribute('title', format.replace('{title}', title));\n }\n },\n // Toggle poster\n togglePoster(enable) {\n toggleClass(this.elements.container, this.config.classNames.posterEnabled, enable);\n },\n // Set the poster image (async)\n // Used internally for the poster setter, with the passive option forced to false\n setPoster(poster, passive = true) {\n // Don't override if call is passive\n if (passive && this.poster) {\n return Promise.reject(new Error('Poster already set'));\n }\n\n // Set property synchronously to respect the call order\n this.media.setAttribute('data-poster', poster);\n\n // Show the poster\n this.elements.poster.removeAttribute('hidden');\n\n // Wait until ui is ready\n return ready.call(this)\n // Load image\n .then(() => loadImage(poster)).catch(error => {\n // Hide poster on error unless it's been set by another call\n if (poster === this.poster) {\n ui.togglePoster.call(this, false);\n }\n // Rethrow\n throw error;\n }).then(() => {\n // Prevent race conditions\n if (poster !== this.poster) {\n throw new Error('setPoster cancelled by later call to setPoster');\n }\n }).then(() => {\n Object.assign(this.elements.poster.style, {\n backgroundImage: `url('${poster}')`,\n // Reset backgroundSize as well (since it can be set to \"cover\" for padded thumbnails for youtube)\n backgroundSize: ''\n });\n ui.togglePoster.call(this, true);\n return poster;\n });\n },\n // Check playing state\n checkPlaying(event) {\n // Class hooks\n toggleClass(this.elements.container, this.config.classNames.playing, this.playing);\n toggleClass(this.elements.container, this.config.classNames.paused, this.paused);\n toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);\n\n // Set state\n Array.from(this.elements.buttons.play || []).forEach(target => {\n Object.assign(target, {\n pressed: this.playing\n });\n target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config));\n });\n\n // Only update controls on non timeupdate events\n if (is.event(event) && event.type === 'timeupdate') {\n return;\n }\n\n // Toggle controls\n ui.toggleControls.call(this);\n },\n // Check if media is loading\n checkLoading(event) {\n this.loading = ['stalled', 'waiting'].includes(event.type);\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Update progress bar loading class state\n toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Update controls visibility\n ui.toggleControls.call(this);\n }, this.loading ? 250 : 0);\n },\n // Toggle controls based on state and `force` argument\n toggleControls(force) {\n const {\n controls: controlsElement\n } = this.elements;\n if (controlsElement && this.config.hideControls) {\n // Don't hide controls if a touch-device user recently seeked. (Must be limited to touch devices, or it occasionally prevents desktop controls from hiding.)\n const recentTouchSeek = this.touch && this.lastSeekTime + 2000 > Date.now();\n\n // Show controls if force, loading, paused, button interaction, or recent seek, otherwise hide\n this.toggleControls(Boolean(force || this.loading || this.paused || controlsElement.pressed || controlsElement.hover || recentTouchSeek));\n }\n },\n // Migrate any custom properties from the media to the parent\n migrateStyles() {\n // Loop through values (as they are the keys when the object is spread 🤔)\n Object.values({\n ...this.media.style\n })\n // We're only fussed about Plyr specific properties\n .filter(key => !is.empty(key) && is.string(key) && key.startsWith('--plyr')).forEach(key => {\n // Set on the container\n this.elements.container.style.setProperty(key, this.media.style.getPropertyValue(key));\n\n // Clean up from media element\n this.media.style.removeProperty(key);\n });\n\n // Remove attribute if empty\n if (is.empty(this.media.style)) {\n this.media.removeAttribute('style');\n }\n }\n };\n\n class Listeners {\n constructor(_player) {\n _defineProperty$1(this, \"firstTouch\", () => {\n const {\n player\n } = this;\n const {\n elements\n } = player;\n player.touch = true;\n\n // Add touch class\n toggleClass(elements.container, player.config.classNames.isTouch, true);\n });\n _defineProperty$1(this, \"setTabFocus\", event => {\n const {\n player\n } = this;\n const {\n elements\n } = player;\n const {\n key,\n type,\n timeStamp\n } = event;\n clearTimeout(this.focusTimer);\n\n // Ignore any key other than tab\n if (type === 'keydown' && key !== 'Tab') {\n return;\n }\n\n // Store reference to event timeStamp\n if (type === 'keydown') {\n this.lastKeyDown = timeStamp;\n }\n\n // Remove current classes\n const removeCurrent = () => {\n const className = player.config.classNames.tabFocus;\n const current = getElements.call(player, `.${className}`);\n toggleClass(current, className, false);\n };\n\n // Determine if a key was pressed to trigger this event\n const wasKeyDown = timeStamp - this.lastKeyDown <= 20;\n\n // Ignore focus events if a key was pressed prior\n if (type === 'focus' && !wasKeyDown) {\n return;\n }\n\n // Remove all current\n removeCurrent();\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n if (type !== 'focusout') {\n this.focusTimer = setTimeout(() => {\n const focused = document.activeElement;\n\n // Ignore if current focus element isn't inside the player\n if (!elements.container.contains(focused)) {\n return;\n }\n toggleClass(document.activeElement, player.config.classNames.tabFocus, true);\n }, 10);\n }\n });\n _defineProperty$1(this, \"global\", (toggle = true) => {\n const {\n player\n } = this;\n\n // Keyboard shortcuts\n if (player.config.keyboard.global) {\n toggleListener.call(player, window, 'keydown keyup', this.handleKey, toggle, false);\n }\n\n // Click anywhere closes menu\n toggleListener.call(player, document.body, 'click', this.toggleMenu, toggle);\n\n // Detect touch by events\n once.call(player, document.body, 'touchstart', this.firstTouch);\n\n // Tab focus detection\n toggleListener.call(player, document.body, 'keydown focus blur focusout', this.setTabFocus, toggle, false, true);\n });\n _defineProperty$1(this, \"container\", () => {\n const {\n player\n } = this;\n const {\n config,\n elements,\n timers\n } = player;\n\n // Keyboard shortcuts\n if (!config.keyboard.global && config.keyboard.focused) {\n on.call(player, elements.container, 'keydown keyup', this.handleKey, false);\n }\n\n // Toggle controls on mouse events and entering fullscreen\n on.call(player, elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', event => {\n const {\n controls: controlsElement\n } = elements;\n\n // Remove button states for fullscreen\n if (controlsElement && event.type === 'enterfullscreen') {\n controlsElement.pressed = false;\n controlsElement.hover = false;\n }\n\n // Show, then hide after a timeout unless another control event occurs\n const show = ['touchstart', 'touchmove', 'mousemove'].includes(event.type);\n let delay = 0;\n if (show) {\n ui.toggleControls.call(player, true);\n // Use longer timeout for touch devices\n delay = player.touch ? 3000 : 2000;\n }\n\n // Clear timer\n clearTimeout(timers.controls);\n\n // Set new timer to prevent flicker when seeking\n timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n });\n\n // Set a gutter for Vimeo\n const setGutter = () => {\n if (!player.isVimeo || player.config.vimeo.premium) {\n return;\n }\n const target = elements.wrapper;\n const {\n active\n } = player.fullscreen;\n const [videoWidth, videoHeight] = getAspectRatio.call(player);\n const useNativeAspectRatio = supportsCSS(`aspect-ratio: ${videoWidth} / ${videoHeight}`);\n\n // If not active, remove styles\n if (!active) {\n if (useNativeAspectRatio) {\n target.style.width = null;\n target.style.height = null;\n } else {\n target.style.maxWidth = null;\n target.style.margin = null;\n }\n return;\n }\n\n // Determine which dimension will overflow and constrain view\n const [viewportWidth, viewportHeight] = getViewportSize();\n const overflow = viewportWidth / viewportHeight > videoWidth / videoHeight;\n if (useNativeAspectRatio) {\n target.style.width = overflow ? 'auto' : '100%';\n target.style.height = overflow ? '100%' : 'auto';\n } else {\n target.style.maxWidth = overflow ? `${viewportHeight / videoHeight * videoWidth}px` : null;\n target.style.margin = overflow ? '0 auto' : null;\n }\n };\n\n // Handle resizing\n const resized = () => {\n clearTimeout(timers.resized);\n timers.resized = setTimeout(setGutter, 50);\n };\n on.call(player, elements.container, 'enterfullscreen exitfullscreen', event => {\n const {\n target\n } = player.fullscreen;\n\n // Ignore events not from target\n if (target !== elements.container) {\n return;\n }\n\n // If it's not an embed and no ratio specified\n if (!player.isEmbed && is.empty(player.config.ratio)) {\n return;\n }\n\n // Set Vimeo gutter\n setGutter();\n\n // Watch for resizes\n const method = event.type === 'enterfullscreen' ? on : off;\n method.call(player, window, 'resize', resized);\n });\n });\n _defineProperty$1(this, \"media\", () => {\n const {\n player\n } = this;\n const {\n elements\n } = player;\n\n // Time change on media\n on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event));\n\n // Display duration\n on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(player, event));\n\n // Handle the media finishing\n on.call(player, player.media, 'ended', () => {\n // Show poster on end\n if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) {\n // Restart\n player.restart();\n\n // Call pause otherwise IE11 will start playing the video again\n player.pause();\n }\n });\n\n // Check for buffer progress\n on.call(player, player.media, 'progress playing seeking seeked', event => controls.updateProgress.call(player, event));\n\n // Handle volume changes\n on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event));\n\n // Handle play/pause\n on.call(player, player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(player, event));\n\n // Loading state\n on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event));\n\n // Click video\n if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {\n // Re-fetch the wrapper\n const wrapper = getElement.call(player, `.${player.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!is.element(wrapper)) {\n return;\n }\n\n // On click play, pause or restart\n on.call(player, elements.container, 'click', event => {\n const targets = [elements.container, wrapper];\n\n // Ignore if click if not container or in video wrapper\n if (!targets.includes(event.target) && !wrapper.contains(event.target)) {\n return;\n }\n\n // Touch devices will just show controls (if hidden)\n if (player.touch && player.config.hideControls) {\n return;\n }\n if (player.ended) {\n this.proxy(event, player.restart, 'restart');\n this.proxy(event, () => {\n silencePromise(player.play());\n }, 'play');\n } else {\n this.proxy(event, () => {\n silencePromise(player.togglePlay());\n }, 'play');\n }\n });\n }\n\n // Disable right click\n if (player.supported.ui && player.config.disableContextMenu) {\n on.call(player, elements.wrapper, 'contextmenu', event => {\n event.preventDefault();\n }, false);\n }\n\n // Volume change\n on.call(player, player.media, 'volumechange', () => {\n // Save to storage\n player.storage.set({\n volume: player.volume,\n muted: player.muted\n });\n });\n\n // Speed change\n on.call(player, player.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(player, 'speed');\n\n // Save to storage\n player.storage.set({\n speed: player.speed\n });\n });\n\n // Quality change\n on.call(player, player.media, 'qualitychange', event => {\n // Update UI\n controls.updateSetting.call(player, 'quality', null, event.detail.quality);\n });\n\n // Update download link when ready and if quality changes\n on.call(player, player.media, 'ready qualitychange', () => {\n controls.setDownloadUrl.call(player);\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');\n on.call(player, player.media, proxyEvents, event => {\n let {\n detail = {}\n } = event;\n\n // Get error details from media\n if (event.type === 'error') {\n detail = player.media.error;\n }\n triggerEvent.call(player, elements.container, event.type, true, detail);\n });\n });\n _defineProperty$1(this, \"proxy\", (event, defaultHandler, customHandlerKey) => {\n const {\n player\n } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n let returned = true;\n\n // Execute custom handler\n if (hasCustomHandler) {\n returned = customHandler.call(player, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (returned !== false && is.function(defaultHandler)) {\n defaultHandler.call(player, event);\n }\n });\n _defineProperty$1(this, \"bind\", (element, type, defaultHandler, customHandlerKey, passive = true) => {\n const {\n player\n } = this;\n const customHandler = player.config.listeners[customHandlerKey];\n const hasCustomHandler = is.function(customHandler);\n on.call(player, element, type, event => this.proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler);\n });\n _defineProperty$1(this, \"controls\", () => {\n const {\n player\n } = this;\n const {\n elements\n } = player;\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Play/pause toggle\n if (elements.buttons.play) {\n Array.from(elements.buttons.play).forEach(button => {\n this.bind(button, 'click', () => {\n silencePromise(player.togglePlay());\n }, 'play');\n });\n }\n\n // Pause\n this.bind(elements.buttons.restart, 'click', player.restart, 'restart');\n\n // Rewind\n this.bind(elements.buttons.rewind, 'click', () => {\n // Record seek time so we can prevent hiding controls for a few seconds after rewind\n player.lastSeekTime = Date.now();\n player.rewind();\n }, 'rewind');\n\n // Rewind\n this.bind(elements.buttons.fastForward, 'click', () => {\n // Record seek time so we can prevent hiding controls for a few seconds after fast forward\n player.lastSeekTime = Date.now();\n player.forward();\n }, 'fastForward');\n\n // Mute toggle\n this.bind(elements.buttons.mute, 'click', () => {\n player.muted = !player.muted;\n }, 'mute');\n\n // Captions toggle\n this.bind(elements.buttons.captions, 'click', () => player.toggleCaptions());\n\n // Download\n this.bind(elements.buttons.download, 'click', () => {\n triggerEvent.call(player, player.media, 'download');\n }, 'download');\n\n // Fullscreen toggle\n this.bind(elements.buttons.fullscreen, 'click', () => {\n player.fullscreen.toggle();\n }, 'fullscreen');\n\n // Picture-in-Picture\n this.bind(elements.buttons.pip, 'click', () => {\n player.pip = 'toggle';\n }, 'pip');\n\n // Airplay\n this.bind(elements.buttons.airplay, 'click', player.airplay, 'airplay');\n\n // Settings menu - click toggle\n this.bind(elements.buttons.settings, 'click', event => {\n // Prevent the document click listener closing the menu\n event.stopPropagation();\n event.preventDefault();\n controls.toggleMenu.call(player, event);\n }, null, false); // Can't be passive as we're preventing default\n\n // Settings menu - keyboard toggle\n // We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1220143\n this.bind(elements.buttons.settings, 'keyup', event => {\n if (!['Space', 'Enter'].includes(event.key)) {\n return;\n }\n\n // Because return triggers a click anyway, all we need to do is set focus\n if (event.key === 'Enter') {\n controls.focusFirstMenuItem.call(player, null, true);\n return;\n }\n\n // Prevent scroll\n event.preventDefault();\n\n // Prevent playing video (Firefox)\n event.stopPropagation();\n\n // Toggle menu\n controls.toggleMenu.call(player, event);\n }, null, false // Can't be passive as we're preventing default\n );\n\n // Escape closes menu\n this.bind(elements.settings.menu, 'keydown', event => {\n if (event.key === 'Escape') {\n controls.toggleMenu.call(player, event);\n }\n });\n\n // Set range input alternative \"value\", which matches the tooltip time (#954)\n this.bind(elements.inputs.seek, 'mousedown mousemove', event => {\n const rect = elements.progress.getBoundingClientRect();\n const percent = 100 / rect.width * (event.pageX - rect.left);\n event.currentTarget.setAttribute('seek-value', percent);\n });\n\n // Pause while seeking\n this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {\n const seek = event.currentTarget;\n const attribute = 'play-on-seeked';\n if (is.keyboardEvent(event) && !['ArrowLeft', 'ArrowRight'].includes(event.key)) {\n return;\n }\n\n // Record seek time so we can prevent hiding controls for a few seconds after seek\n player.lastSeekTime = Date.now();\n\n // Was playing before?\n const play = seek.hasAttribute(attribute);\n // Done seeking\n const done = ['mouseup', 'touchend', 'keyup'].includes(event.type);\n\n // If we're done seeking and it was playing, resume playback\n if (play && done) {\n seek.removeAttribute(attribute);\n silencePromise(player.play());\n } else if (!done && player.playing) {\n seek.setAttribute(attribute, '');\n player.pause();\n }\n });\n\n // Fix range inputs on iOS\n // Super weird iOS bug where after you interact with an ,\n // it takes over further interactions on the page. This is a hack\n if (browser.isIos) {\n const inputs = getElements.call(player, 'input[type=\"range\"]');\n Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target)));\n }\n\n // Seek\n this.bind(elements.inputs.seek, inputEvent, event => {\n const seek = event.currentTarget;\n // If it exists, use seek-value instead of \"value\" for consistency with tooltip time (#954)\n let seekTo = seek.getAttribute('seek-value');\n if (is.empty(seekTo)) {\n seekTo = seek.value;\n }\n seek.removeAttribute('seek-value');\n player.currentTime = seekTo / seek.max * player.duration;\n }, 'seek');\n\n // Seek tooltip\n this.bind(elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(player, event));\n\n // Preview thumbnails plugin\n // TODO: Really need to work on some sort of plug-in wide event bus or pub-sub for this\n this.bind(elements.progress, 'mousemove touchmove', event => {\n const {\n previewThumbnails\n } = player;\n if (previewThumbnails && previewThumbnails.loaded) {\n previewThumbnails.startMove(event);\n }\n });\n\n // Hide thumbnail preview - on mouse click, mouse leave, and video play/seek. All four are required, e.g., for buffering\n this.bind(elements.progress, 'mouseleave touchend click', () => {\n const {\n previewThumbnails\n } = player;\n if (previewThumbnails && previewThumbnails.loaded) {\n previewThumbnails.endMove(false, true);\n }\n });\n\n // Show scrubbing preview\n this.bind(elements.progress, 'mousedown touchstart', event => {\n const {\n previewThumbnails\n } = player;\n if (previewThumbnails && previewThumbnails.loaded) {\n previewThumbnails.startScrubbing(event);\n }\n });\n this.bind(elements.progress, 'mouseup touchend', event => {\n const {\n previewThumbnails\n } = player;\n if (previewThumbnails && previewThumbnails.loaded) {\n previewThumbnails.endScrubbing(event);\n }\n });\n\n // Polyfill for lower fill in for webkit\n if (browser.isWebkit) {\n Array.from(getElements.call(player, 'input[type=\"range\"]')).forEach(element => {\n this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target));\n });\n }\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (player.config.toggleInvert && !is.element(elements.display.duration)) {\n this.bind(elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (player.currentTime === 0) {\n return;\n }\n player.config.invertTime = !player.config.invertTime;\n controls.timeUpdate.call(player);\n });\n }\n\n // Volume\n this.bind(elements.inputs.volume, inputEvent, event => {\n player.volume = event.target.value;\n }, 'volume');\n\n // Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mouseenter mouseleave', event => {\n elements.controls.hover = !player.touch && event.type === 'mouseenter';\n });\n\n // Also update controls.hover state for any non-player children of fullscreen element (as above)\n if (elements.fullscreen) {\n Array.from(elements.fullscreen.children).filter(c => !c.contains(elements.container)).forEach(child => {\n this.bind(child, 'mouseenter mouseleave', event => {\n if (elements.controls) {\n elements.controls.hover = !player.touch && event.type === 'mouseenter';\n }\n });\n });\n }\n\n // Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)\n this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Show controls when they receive focus (e.g., when using keyboard tab key)\n this.bind(elements.controls, 'focusin', () => {\n const {\n config,\n timers\n } = player;\n\n // Skip transition to prevent focus from scrolling the parent element\n toggleClass(elements.controls, config.classNames.noTransition, true);\n\n // Toggle\n ui.toggleControls.call(player, true);\n\n // Restore transition\n setTimeout(() => {\n toggleClass(elements.controls, config.classNames.noTransition, false);\n }, 0);\n\n // Delay a little more for mouse users\n const delay = this.touch ? 3000 : 4000;\n\n // Clear timer\n clearTimeout(timers.controls);\n\n // Hide again after delay\n timers.controls = setTimeout(() => ui.toggleControls.call(player, false), delay);\n });\n\n // Mouse wheel for volume\n this.bind(elements.inputs.volume, 'wheel', event => {\n // Detect \"natural\" scroll - supported on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n // Get delta from event. Invert if `inverted` is true\n const [x, y] = [event.deltaX, -event.deltaY].map(value => inverted ? -value : value);\n // Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)\n const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);\n\n // Change the volume by 2%\n player.increaseVolume(direction / 50);\n\n // Don't break page scrolling at max and min\n const {\n volume\n } = player.media;\n if (direction === 1 && volume < 1 || direction === -1 && volume > 0) {\n event.preventDefault();\n }\n }, 'volume', false);\n });\n this.player = _player;\n this.lastKey = null;\n this.focusTimer = null;\n this.lastKeyDown = null;\n this.handleKey = this.handleKey.bind(this);\n this.toggleMenu = this.toggleMenu.bind(this);\n this.setTabFocus = this.setTabFocus.bind(this);\n this.firstTouch = this.firstTouch.bind(this);\n }\n\n // Handle key presses\n handleKey(event) {\n const {\n player\n } = this;\n const {\n elements\n } = player;\n const {\n key,\n type,\n altKey,\n ctrlKey,\n metaKey,\n shiftKey\n } = event;\n const pressed = type === 'keydown';\n const repeat = pressed && key === this.lastKey;\n\n // Bail if a modifier key is set\n if (altKey || ctrlKey || metaKey || shiftKey) {\n return;\n }\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the key for whatever reason\n if (!key) {\n return;\n }\n\n // Seek by increment\n const seekByIncrement = increment => {\n // Divide the max duration into 10th's and times by the number value\n player.currentTime = player.duration / 10 * increment;\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Check focused element\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n const focused = document.activeElement;\n if (is.element(focused)) {\n const {\n editable\n } = player.config.selectors;\n const {\n seek\n } = elements.inputs;\n if (focused !== seek && matches(focused, editable)) {\n return;\n }\n if (event.key === 'Space' && matches(focused, 'button, [role^=\"menuitem\"]')) {\n return;\n }\n }\n\n // Which keys should we prevent default\n const preventDefault = ['Space', 'ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'c', 'f', 'k', 'l', 'm'];\n\n // If the key is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(key)) {\n event.preventDefault();\n event.stopPropagation();\n }\n switch (key) {\n case '0':\n case '1':\n case '2':\n case '3':\n case '4':\n case '5':\n case '6':\n case '7':\n case '8':\n case '9':\n if (!repeat) {\n seekByIncrement(parseInt(key, 10));\n }\n break;\n case 'Space':\n case 'k':\n if (!repeat) {\n silencePromise(player.togglePlay());\n }\n break;\n case 'ArrowUp':\n player.increaseVolume(0.1);\n break;\n case 'ArrowDown':\n player.decreaseVolume(0.1);\n break;\n case 'm':\n if (!repeat) {\n player.muted = !player.muted;\n }\n break;\n case 'ArrowRight':\n player.forward();\n break;\n case 'ArrowLeft':\n player.rewind();\n break;\n case 'f':\n player.fullscreen.toggle();\n break;\n case 'c':\n if (!repeat) {\n player.toggleCaptions();\n }\n break;\n case 'l':\n player.loop = !player.loop;\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (key === 'Escape' && !player.fullscreen.usingNative && player.fullscreen.active) {\n player.fullscreen.toggle();\n }\n\n // Store last key for next cycle\n this.lastKey = key;\n } else {\n this.lastKey = null;\n }\n }\n\n // Toggle menu\n toggleMenu(event) {\n controls.toggleMenu.call(this.player, event);\n }\n\n // Device is touch enabled\n }\n\n var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n var loadjs_umd = createCommonjsModule(function (module, exports) {\n (function (root, factory) {\n {\n module.exports = factory();\n }\n })(commonjsGlobal, function () {\n /**\n * Global dependencies.\n * @global {Object} document - DOM\n */\n\n var devnull = function () {},\n bundleIdCache = {},\n bundleResultCache = {},\n bundleCallbackQueue = {};\n\n /**\n * Subscribe to bundle load event.\n * @param {string[]} bundleIds - Bundle ids\n * @param {Function} callbackFn - The callback function\n */\n function subscribe(bundleIds, callbackFn) {\n // listify\n bundleIds = bundleIds.push ? bundleIds : [bundleIds];\n var depsNotFound = [],\n i = bundleIds.length,\n numWaiting = i,\n fn,\n bundleId,\n r,\n q;\n\n // define callback function\n fn = function (bundleId, pathsNotFound) {\n if (pathsNotFound.length) depsNotFound.push(bundleId);\n numWaiting--;\n if (!numWaiting) callbackFn(depsNotFound);\n };\n\n // register callback\n while (i--) {\n bundleId = bundleIds[i];\n\n // execute callback if in result cache\n r = bundleResultCache[bundleId];\n if (r) {\n fn(bundleId, r);\n continue;\n }\n\n // add to callback queue\n q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];\n q.push(fn);\n }\n }\n\n /**\n * Publish bundle load event.\n * @param {string} bundleId - Bundle id\n * @param {string[]} pathsNotFound - List of files not found\n */\n function publish(bundleId, pathsNotFound) {\n // exit if id isn't defined\n if (!bundleId) return;\n var q = bundleCallbackQueue[bundleId];\n\n // cache result\n bundleResultCache[bundleId] = pathsNotFound;\n\n // exit if queue is empty\n if (!q) return;\n\n // empty callback queue\n while (q.length) {\n q[0](bundleId, pathsNotFound);\n q.splice(0, 1);\n }\n }\n\n /**\n * Execute callbacks.\n * @param {Object or Function} args - The callback args\n * @param {string[]} depsNotFound - List of dependencies not found\n */\n function executeCallbacks(args, depsNotFound) {\n // accept function as argument\n if (args.call) args = {\n success: args\n };\n\n // success and error callbacks\n if (depsNotFound.length) (args.error || devnull)(depsNotFound);else (args.success || devnull)(args);\n }\n\n /**\n * Load individual file.\n * @param {string} path - The file path\n * @param {Function} callbackFn - The callback function\n */\n function loadFile(path, callbackFn, args, numTries) {\n var doc = document,\n async = args.async,\n maxTries = (args.numRetries || 0) + 1,\n beforeCallbackFn = args.before || devnull,\n pathname = path.replace(/[\\?|#].*$/, ''),\n pathStripped = path.replace(/^(css|img)!/, ''),\n isLegacyIECss,\n e;\n numTries = numTries || 0;\n if (/(^css!|\\.css$)/.test(pathname)) {\n // css\n e = doc.createElement('link');\n e.rel = 'stylesheet';\n e.href = pathStripped;\n\n // tag IE9+\n isLegacyIECss = 'hideFocus' in e;\n\n // use preload in IE Edge (to detect load errors)\n if (isLegacyIECss && e.relList) {\n isLegacyIECss = 0;\n e.rel = 'preload';\n e.as = 'style';\n }\n } else if (/(^img!|\\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {\n // image\n e = doc.createElement('img');\n e.src = pathStripped;\n } else {\n // javascript\n e = doc.createElement('script');\n e.src = path;\n e.async = async === undefined ? true : async;\n }\n e.onload = e.onerror = e.onbeforeload = function (ev) {\n var result = ev.type[0];\n\n // treat empty stylesheets as failures to get around lack of onerror\n // support in IE9-11\n if (isLegacyIECss) {\n try {\n if (!e.sheet.cssText.length) result = 'e';\n } catch (x) {\n // sheets objects created from load errors don't allow access to\n // `cssText` (unless error is Code:18 SecurityError)\n if (x.code != 18) result = 'e';\n }\n }\n\n // handle retries in case of load failure\n if (result == 'e') {\n // increment counter\n numTries += 1;\n\n // exit function and try again\n if (numTries < maxTries) {\n return loadFile(path, callbackFn, args, numTries);\n }\n } else if (e.rel == 'preload' && e.as == 'style') {\n // activate preloaded stylesheets\n return e.rel = 'stylesheet'; // jshint ignore:line\n }\n\n // execute callback\n callbackFn(path, result, ev.defaultPrevented);\n };\n\n // add to document (unless callback returns `false`)\n if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);\n }\n\n /**\n * Load multiple files.\n * @param {string[]} paths - The file paths\n * @param {Function} callbackFn - The callback function\n */\n function loadFiles(paths, callbackFn, args) {\n // listify paths\n paths = paths.push ? paths : [paths];\n var numWaiting = paths.length,\n x = numWaiting,\n pathsNotFound = [],\n fn,\n i;\n\n // define callback function\n fn = function (path, result, defaultPrevented) {\n // handle error\n if (result == 'e') pathsNotFound.push(path);\n\n // handle beforeload event. If defaultPrevented then that means the load\n // will be blocked (ex. Ghostery/ABP on Safari)\n if (result == 'b') {\n if (defaultPrevented) pathsNotFound.push(path);else return;\n }\n numWaiting--;\n if (!numWaiting) callbackFn(pathsNotFound);\n };\n\n // load scripts\n for (i = 0; i < x; i++) loadFile(paths[i], fn, args);\n }\n\n /**\n * Initiate script load and register bundle.\n * @param {(string|string[])} paths - The file paths\n * @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success\n * callback or (3) object literal with success/error arguments, numRetries,\n * etc.\n * @param {(Function|Object)} [arg2] - The (1) success callback or (2) object\n * literal with success/error arguments, numRetries, etc.\n */\n function loadjs(paths, arg1, arg2) {\n var bundleId, args;\n\n // bundleId (if string)\n if (arg1 && arg1.trim) bundleId = arg1;\n\n // args (default is {})\n args = (bundleId ? arg2 : arg1) || {};\n\n // throw error if bundle is already defined\n if (bundleId) {\n if (bundleId in bundleIdCache) {\n throw \"LoadJS\";\n } else {\n bundleIdCache[bundleId] = true;\n }\n }\n function loadFn(resolve, reject) {\n loadFiles(paths, function (pathsNotFound) {\n // execute callbacks\n executeCallbacks(args, pathsNotFound);\n\n // resolve Promise\n if (resolve) {\n executeCallbacks({\n success: resolve,\n error: reject\n }, pathsNotFound);\n }\n\n // publish bundle load event\n publish(bundleId, pathsNotFound);\n }, args);\n }\n if (args.returnPromise) return new Promise(loadFn);else loadFn();\n }\n\n /**\n * Execute callbacks when dependencies have been satisfied.\n * @param {(string|string[])} deps - List of bundle ids\n * @param {Object} args - success/error arguments\n */\n loadjs.ready = function ready(deps, args) {\n // subscribe to bundle load event\n subscribe(deps, function (depsNotFound) {\n // execute callbacks\n executeCallbacks(args, depsNotFound);\n });\n return loadjs;\n };\n\n /**\n * Manually satisfy bundle dependencies.\n * @param {string} bundleId - The bundle id\n */\n loadjs.done = function done(bundleId) {\n publish(bundleId, []);\n };\n\n /**\n * Reset loadjs dependencies statuses\n */\n loadjs.reset = function reset() {\n bundleIdCache = {};\n bundleResultCache = {};\n bundleCallbackQueue = {};\n };\n\n /**\n * Determine if bundle has already been defined\n * @param String} bundleId - The bundle id\n */\n loadjs.isDefined = function isDefined(bundleId) {\n return bundleId in bundleIdCache;\n };\n\n // export\n return loadjs;\n });\n });\n\n // ==========================================================================\n function loadScript(url) {\n return new Promise((resolve, reject) => {\n loadjs_umd(url, {\n success: resolve,\n error: reject\n });\n });\n }\n\n // ==========================================================================\n\n // Parse Vimeo ID from URL\n function parseId$1(url) {\n if (is.empty(url)) {\n return null;\n }\n if (is.number(Number(url))) {\n return url;\n }\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n }\n\n // Try to extract a hash for private videos from the URL\n function parseHash(url) {\n /* This regex matches a hexadecimal hash if given in any of these forms:\n * - [https://player.]vimeo.com/video/{id}/{hash}[?params]\n * - [https://player.]vimeo.com/video/{id}?h={hash}[¶ms]\n * - [https://player.]vimeo.com/video/{id}?[params]&h={hash}\n * - video/{id}/{hash}\n * If matched, the hash is available in capture group 4\n */\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+)(\\?.*&*h=|\\/)+([\\d,a-f]+)/;\n const found = url.match(regex);\n return found && found.length === 5 ? found[4] : null;\n }\n\n // Set playback state and trigger change (only on actual change)\n function assurePlaybackState$1(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n }\n const vimeo = {\n setup() {\n const player = this;\n\n // Add embed class for responsive\n toggleClass(player.elements.wrapper, player.config.classNames.embed, true);\n\n // Set speed options from config\n player.options.speed = player.config.speed.options;\n\n // Set intial ratio\n setAspectRatio.call(player);\n\n // Load the SDK if not already\n if (!is.object(window.Vimeo)) {\n loadScript(player.config.urls.vimeo.sdk).then(() => {\n vimeo.ready.call(player);\n }).catch(error => {\n player.debug.warn('Vimeo SDK (player.js) failed to load', error);\n });\n } else {\n vimeo.ready.call(player);\n }\n },\n // API Ready\n ready() {\n const player = this;\n const config = player.config.vimeo;\n const {\n premium,\n referrerPolicy,\n ...frameParams\n } = config;\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n let hash = '';\n // Get from
if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(player.config.attributes.embed.id);\n // hash can also be set as attribute on the
\n hash = player.media.getAttribute(player.config.attributes.embed.hash);\n } else {\n hash = parseHash(source);\n }\n const hashParam = hash ? {\n h: hash\n } : {};\n\n // If the owner has a pro or premium account then we can hide controls etc\n if (premium) {\n Object.assign(frameParams, {\n controls: false,\n sidedock: false\n });\n }\n\n // Get Vimeo params for the iframe\n const params = buildUrlParams({\n loop: player.config.loop.active,\n autoplay: player.autoplay,\n muted: player.muted,\n gesture: 'media',\n playsinline: !this.config.fullscreen.iosNative,\n // hash has to be added to iframe-URL\n ...hashParam,\n ...frameParams\n });\n const id = parseId$1(source);\n // Build an iframe\n const iframe = createElement('iframe');\n const src = format(player.config.urls.vimeo.iframe, id, params);\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allow', ['autoplay', 'fullscreen', 'picture-in-picture', 'encrypted-media', 'accelerometer', 'gyroscope'].join('; '));\n\n // Set the referrer policy if required\n if (!is.empty(referrerPolicy)) {\n iframe.setAttribute('referrerPolicy', referrerPolicy);\n }\n\n // Inject the package\n if (premium || !config.customControls) {\n iframe.setAttribute('data-poster', player.poster);\n player.media = replaceElement(iframe, player.media);\n } else {\n const wrapper = createElement('div', {\n class: player.config.classNames.embedContainer,\n 'data-poster': player.poster\n });\n wrapper.appendChild(iframe);\n player.media = replaceElement(wrapper, player.media);\n }\n\n // Get poster image\n if (!config.customControls) {\n fetch(format(player.config.urls.vimeo.api, src)).then(response => {\n if (is.empty(response) || !response.thumbnail_url) {\n return;\n }\n\n // Set and show poster\n ui.setPoster.call(player, response.thumbnail_url).catch(() => {});\n });\n }\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe, {\n autopause: player.config.autopause,\n muted: player.muted\n });\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Disable native text track rendering\n if (player.supported.ui) {\n player.embed.disableTextTrack();\n }\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n assurePlaybackState$1.call(player, true);\n return player.embed.play();\n };\n player.media.pause = () => {\n assurePlaybackState$1.call(player, false);\n return player.embed.pause();\n };\n player.media.stop = () => {\n player.pause();\n player.currentTime = 0;\n };\n\n // Seeking\n let {\n currentTime\n } = player.media;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return currentTime;\n },\n set(time) {\n // Vimeo will automatically play on seek if the video hasn't been played before\n\n // Get current paused state and volume etc\n const {\n embed,\n media,\n paused,\n volume\n } = player;\n const restorePause = paused && !embed.hasPlayed;\n\n // Set seeking state and trigger event\n media.seeking = true;\n triggerEvent.call(player, media, 'seeking');\n\n // If paused, mute until seek is complete\n Promise.resolve(restorePause && embed.setVolume(0))\n // Seek\n .then(() => embed.setCurrentTime(time))\n // Restore paused\n .then(() => restorePause && embed.pause())\n // Restore volume\n .then(() => restorePause && embed.setVolume(volume)).catch(() => {\n // Do nothing\n });\n }\n });\n\n // Playback speed\n let speed = player.config.speed.selected;\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return speed;\n },\n set(input) {\n player.embed.setPlaybackRate(input).then(() => {\n speed = input;\n triggerEvent.call(player, player.media, 'ratechange');\n }).catch(() => {\n // Cannot set Playback Rate, Video is probably not on Pro account\n player.options.speed = [1];\n });\n }\n });\n\n // Volume\n let {\n volume\n } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n player.embed.setVolume(input).then(() => {\n volume = input;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n }\n });\n\n // Muted\n let {\n muted\n } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : false;\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n triggerEvent.call(player, player.media, 'volumechange');\n });\n }\n });\n\n // Loop\n let {\n loop\n } = player.config;\n Object.defineProperty(player.media, 'loop', {\n get() {\n return loop;\n },\n set(input) {\n const toggle = is.boolean(input) ? input : player.config.loop.active;\n player.embed.setLoop(toggle).then(() => {\n loop = toggle;\n });\n }\n });\n\n // Source\n let currentSrc;\n player.embed.getVideoUrl().then(value => {\n currentSrc = value;\n controls.setDownloadUrl.call(player);\n }).catch(error => {\n this.debug.warn(error);\n });\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return currentSrc;\n }\n });\n\n // Ended\n Object.defineProperty(player.media, 'ended', {\n get() {\n return player.currentTime === player.duration;\n }\n });\n\n // Set aspect ratio based on video size\n Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {\n const [width, height] = dimensions;\n player.embed.ratio = roundAspectRatio(width, height);\n setAspectRatio.call(this);\n });\n\n // Set autopause\n player.embed.setAutopause(player.config.autopause).then(state => {\n player.config.autopause = state;\n });\n\n // Get title\n player.embed.getVideoTitle().then(title => {\n player.config.title = title;\n ui.setTitle.call(this);\n });\n\n // Get current time\n player.embed.getCurrentTime().then(value => {\n currentTime = value;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.media.textTracks = tracks;\n captions.setup.call(player);\n });\n player.embed.on('cuechange', ({\n cues = []\n }) => {\n const strippedCues = cues.map(cue => stripHTML(cue.text));\n captions.updateCues.call(player, strippedCues);\n });\n player.embed.on('loaded', () => {\n // Assure state and events are updated on autoplay\n player.embed.getPaused().then(paused => {\n assurePlaybackState$1.call(player, !paused);\n if (!paused) {\n triggerEvent.call(player, player.media, 'playing');\n }\n });\n if (is.element(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n player.embed.on('bufferstart', () => {\n triggerEvent.call(player, player.media, 'waiting');\n });\n player.embed.on('bufferend', () => {\n triggerEvent.call(player, player.media, 'playing');\n });\n player.embed.on('play', () => {\n assurePlaybackState$1.call(player, true);\n triggerEvent.call(player, player.media, 'playing');\n });\n player.embed.on('pause', () => {\n assurePlaybackState$1.call(player, false);\n });\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n triggerEvent.call(player, player.media, 'timeupdate');\n });\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n triggerEvent.call(player, player.media, 'progress');\n\n // Check all loaded\n if (parseInt(data.percent, 10) === 1) {\n triggerEvent.call(player, player.media, 'canplaythrough');\n }\n\n // Get duration as if we do it before load, it gives an incorrect value\n // https://github.com/sampotts/plyr/issues/891\n player.embed.getDuration().then(value => {\n if (value !== player.media.duration) {\n player.media.duration = value;\n triggerEvent.call(player, player.media, 'durationchange');\n }\n });\n });\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n triggerEvent.call(player, player.media, 'seeked');\n });\n player.embed.on('ended', () => {\n player.media.paused = true;\n triggerEvent.call(player, player.media, 'ended');\n });\n player.embed.on('error', detail => {\n player.media.error = detail;\n triggerEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n if (config.customControls) {\n setTimeout(() => ui.build.call(player), 0);\n }\n }\n };\n\n // ==========================================================================\n\n // Parse YouTube ID from URL\n function parseId(url) {\n if (is.empty(url)) {\n return null;\n }\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n }\n\n // Set playback state and trigger change (only on actual change)\n function assurePlaybackState(play) {\n if (play && !this.embed.hasPlayed) {\n this.embed.hasPlayed = true;\n }\n if (this.media.paused === play) {\n this.media.paused = !play;\n triggerEvent.call(this, this.media, play ? 'play' : 'pause');\n }\n }\n function getHost(config) {\n if (config.noCookie) {\n return 'https://www.youtube-nocookie.com';\n }\n if (window.location.protocol === 'http:') {\n return 'http://www.youtube.com';\n }\n\n // Use YouTube's default\n return undefined;\n }\n const youtube = {\n setup() {\n // Add embed class for responsive\n toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Setup API\n if (is.object(window.YT) && is.function(window.YT.Player)) {\n youtube.ready.call(this);\n } else {\n // Reference current global callback\n const callback = window.onYouTubeIframeAPIReady;\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n // Call global callback if set\n if (is.function(callback)) {\n callback();\n }\n youtube.ready.call(this);\n };\n\n // Load the SDK\n loadScript(this.config.urls.youtube.sdk).catch(error => {\n this.debug.warn('YouTube API failed to load', error);\n });\n }\n },\n // Get the media title\n getTitle(videoId) {\n const url = format(this.config.urls.youtube.api, videoId);\n fetch(url).then(data => {\n if (is.object(data)) {\n const {\n title,\n height,\n width\n } = data;\n\n // Set title\n this.config.title = title;\n ui.setTitle.call(this);\n\n // Set aspect ratio\n this.embed.ratio = roundAspectRatio(width, height);\n }\n setAspectRatio.call(this);\n }).catch(() => {\n // Set aspect ratio\n setAspectRatio.call(this);\n });\n },\n // API ready\n ready() {\n const player = this;\n const config = player.config.youtube;\n // Ignore already setup (race condition)\n const currentId = player.media && player.media.getAttribute('id');\n if (!is.empty(currentId) && currentId.startsWith('youtube-')) {\n return;\n }\n\n // Get the source URL or ID\n let source = player.media.getAttribute('src');\n\n // Get from
if needed\n if (is.empty(source)) {\n source = player.media.getAttribute(this.config.attributes.embed.id);\n }\n\n // Replace the