PageSourceSearch

https://sewardpark.org/_static/??-eJyNj90KwjAMRl/ItjrFnwvxFbzwxstu…grBlvhHRYLIDYikgt5Ojxz8frHZzbNttlquH0iicwo=

js sewardpark.org collected 2026-10-02 12:54:48 UTC 132,088 bytes, 3,127 lines download raw bytes

1/*!
2 * jquery-timepicker v1.11.14 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
3 * Copyright (c) 2018 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
4 * License: MIT
5 */
6
7!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=t(b.minTime)),b.maxTime&&(b.maxTime=t(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=t(b.durationTime)),"now"==b.scrollDefault)b.scrollDefault=function(){return b.roundingFunction(t(new Date),b)};else if(b.scrollDefault&&"function"!=typeof b.scrollDefault){var c=b.scrollDefault;b.scrollDefault=function(){return b.roundingFunction(t(c),b)}}else b.minTime&&(b.scrollDefault=function(){return b.roundingFunction(b.minTime,b)});if("string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.showOnFocus===!1&&b.showOn.indexOf("focus")!=-1&&b.showOn.splice(b.showOn.indexOf("focus"),1),b.disableTimeRanges.length>0){for(var d in b.disableTimeRanges)b.disableTimeRanges[d]=[t(b.disableTimeRanges[d][0]),t(b.disableTimeRanges[d][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var d=b.disableTimeRanges.length-1;d>0;d--)b.disableTimeRanges[d][0]<=b.disableTimeRanges[d-1][1]&&(b.disableTimeRanges[d-1]=[Math.min(b.disableTimeRanges[d][0],b.disableTimeRanges[d-1][0]),Math.max(b.disableTimeRanges[d][1],b.disableTimeRanges[d-1][1])],b.disableTimeRanges.splice(d,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a("<select />",{"class":"ui-timepicker-select"}),b.attr("name")&&d.attr("name","ui-timepicker-"+b.attr("name"));var g=d}else{d=a("<ul />",{"class":"ui-timepicker-list"});var g=a("<div />",{"class":"ui-timepicker-wrapper",tabindex:-1});g.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var i in c.noneOption)if(parseInt(i,10)==i){var k=e(c.noneOption[i],c.useSelect);d.append(k)}}else{var k=e(c.noneOption,c.useSelect);d.append(k)}if(c.className&&g.addClass(c.className),(null!==c.minTime||null!==c.durationTime)&&c.showDuration){"function"==typeof c.step?"function":c.step;g.addClass("ui-timepicker-with-duration"),g.addClass("ui-timepicker-step-"+c.step)}var l=c.minTime;"function"==typeof c.durationTime?l=t(c.durationTime()):null!==c.durationTime&&(l=c.durationTime);var n=null!==c.minTime?c.minTime:0,o=null!==c.maxTime?c.maxTime:n+v-1;o<n&&(o+=v),o===v-1&&"string"===a.type(c.timeFormat)&&c.show2400&&(o=v);var p=c.disableTimeRanges,w=0,x=p.length,z=c.step;"function"!=typeof z&&(z=function(){return c.step});for(var i=n,A=0;i<=o;A++,i+=60*z(A)){var B=i,C=s(B,c);if(c.useSelect){var D=a("<option />",{value:C});D.text(C)}else{var D=a("<li />");D.addClass(B%v<v/2?"ui-timepicker-am":"ui-timepicker-pm"),D.data("time",u(B,c)),D.text(C)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var E=r(i-l,c.step);if(c.useSelect)D.text(D.text()+" ("+E+")");else{var F=a("<span />",{"class":"ui-timepicker-duration"});F.text(" ("+E+")"),D.append(F)}}w<x&&(B>=p[w][1]&&(w+=1),p[w]&&B>=p[w][0]&&B<p[w][1]&&(c.useSelect?D.prop("disabled",!0):D.addClass("ui-timepicker-disabled"))),d.append(D)}if(g.data("timepicker-input",b),b.data("timepicker-list",g),c.useSelect)b.val()&&d.val(f(t(b.val()),c)),d.on("focus",function(){a(this).data("timepicker-input").trigger("showTimepicker")}),d.on("blur",function(){a(this).data("timepicker-input").trigger("hideTimepicker")}),d.on("change",function(){m(b,a(this).val(),"select")}),m(b,d.val(),"initial"),b.hide().after(d);else{var G=c.appendTo;"string"==typeof G?G=a(G):"function"==typeof G&&(G=G(b)),G.append(g),j(b,d),d.on("mousedown click","li",function(c){b.off("focus.timepicker"),b.on("focus.timepicker-ie-hack",function(){b.off("focus.timepicker-ie-hack"),b.on("focus.timepicker",y.show)}),h(b)||b[0].focus(),d.find("li").removeClass("ui-timepicker-selected"),a(this).addClass("ui-timepicker-selected"),q(b)&&(b.trigger("hideTimepicker"),d.on("mouseup.timepicker click.timepicker","li",function(a){d.off("mouseup.timepicker click.timepicker"),g.hide()}))})}}function e(b,c){var d,e,f;return"object"==typeof b?(d=b.label,e=b.className,f=b.value):"string"==typeof b?(d=b,f=""):a.error("Invalid noneOption value"),c?a("<option />",{value:f,"class":e,text:d}):a("<li />",{"class":e,text:d}).data("time",String(f))}function f(a,b){if(a=b.roundingFunction(a,b),null!==a)return s(a,b)}function g(b){if(b.target!=window){var c=a(b.target);c.closest(".ui-timepicker-input").length||c.closest(".ui-timepicker-wrapper").length||(y.hide(),a(document).unbind(".ui-timepicker"),a(window).unbind(".ui-timepicker"))}}function h(a){var b=a.data("timepicker-settings");return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&b.disableTouchKeyboard}function i(b,c,d){if(!d&&0!==d)return!1;var e=b.data("timepicker-settings"),f=!1,d=e.roundingFunction(d,e);return c.find("li").each(function(b,c){var e=a(c);if("number"==typeof e.data("time"))return e.data("time")==d?(f=e,!1):void 0}),f}function j(a,b){b.find("li").removeClass("ui-timepicker-selected");var c=a.data("timepicker-settings"),d=t(l(a),c);if(null!==d){var e=i(a,b,d);if(e){var f=e.offset().top-b.offset().top;(f+e.outerHeight()>b.outerHeight()||f<0)&&b.scrollTop(b.scrollTop()+e.position().top-e.outerHeight()),(c.forceRoundTime||e.data("time")===d)&&e.addClass("ui-timepicker-selected")}}}function k(b,c){if("timepicker"!=c){var d=a(this);if(""===this.value)return void m(d,null,c);if(!d.is(":focus")||b&&"change"==b.type){var e=d.data("timepicker-settings"),f=t(this.value,e);if(null===f)return void d.trigger("timeFormatError");var g=!1;if(null!==e.minTime&&null!==e.maxTime&&(f<e.minTime||f>e.maxTime)&&(g=!0),a.each(e.disableTimeRanges,function(){if(f>=this[0]&&f<this[1])return g=!0,!1}),e.forceRoundTime){var h=e.roundingFunction(f,e);h!=f&&(f=h,c=null)}var i=s(f,e);g?(m(d,i,"error")||b&&"change"==b.type)&&d.trigger("timeRangeError"):m(d,i,c)}}}function l(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function m(a,b,c){if(a.is("input")){a.val(b);var d=a.data("timepicker-settings");d.useSelect&&"select"!=c&&a.data("timepicker-list")&&a.data("timepicker-list").val(f(t(b),d))}return a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change","timepicker"):["error","initial"].indexOf(c)==-1&&a.trigger("changeTime"),!0):(["error","initial"].indexOf(c)==-1&&a.trigger("selectTime"),!1)}function n(a){switch(a.keyCode){case 13:case 9:return;default:a.preventDefault()}}function o(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e)){if(40!=c.keyCode)return!0;
7y.show.call(d.get(0)),e=d.data("timepicker-list"),h(d)||d.focus()}switch(c.keyCode){case 13:return q(d)&&(k.call(d.get(0),{type:"change"}),y.hide.apply(this)),c.preventDefault(),!1;case 38:var f=e.find(".ui-timepicker-selected");return f.length?f.is(":first-child")||(f.removeClass("ui-timepicker-selected"),f.prev().addClass("ui-timepicker-selected"),f.prev().position().top<f.outerHeight()&&e.scrollTop(e.scrollTop()-f.outerHeight())):(e.find("li").each(function(b,c){if(a(c).position().top>0)return f=a(c),!1}),f.addClass("ui-timepicker-selected")),!1;case 40:return f=e.find(".ui-timepicker-selected"),0===f.length?(e.find("li").each(function(b,c){if(a(c).position().top>0)return f=a(c),!1}),f.addClass("ui-timepicker-selected")):f.is(":last-child")||(f.removeClass("ui-timepicker-selected"),f.next().addClass("ui-timepicker-selected"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find("li").removeClass("ui-timepicker-selected"),y.hide();break;case 9:y.hide();break;default:return!0}}function p(c){var d=a(this),e=d.data("timepicker-list"),f=d.data("timepicker-settings");if(!e||!b(e)||f.disableTextInput)return!0;if("paste"===c.type||"cut"===c.type)return void setTimeout(function(){f.typeaheadHighlight?j(d,e):e.hide()},0);switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:f.typeaheadHighlight?j(d,e):e.hide()}}function q(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");return!e.hasClass("ui-timepicker-disabled")&&(e.length&&(d=e.data("time")),null!==d&&("string"!=typeof d&&(d=s(d,b)),m(a,d,"select")),!0)}function r(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return e<60?f=[e,w.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=w.decimal+5),f.push(c),f.push(1==c?w.hr:w.hrs),30!=b&&d&&(f.push(d),f.push(w.mins))),f.join(" ")}function s(b,c){if("number"!=typeof b)return null;var d=parseInt(b%60),e=parseInt(b/60%60),f=parseInt(b/3600%24),g=new Date(1970,0,2,f,e,d,0);if(isNaN(g.getTime()))return null;if("function"===a.type(c.timeFormat))return c.timeFormat(g);for(var h,i,j="",k=0;k<c.timeFormat.length;k++)switch(i=c.timeFormat.charAt(k)){case"a":j+=g.getHours()>11?w.pm:w.am;break;case"A":j+=g.getHours()>11?w.PM:w.AM;break;case"g":h=g.getHours()%12,j+=0===h?"12":h;break;case"G":h=g.getHours(),b===v&&(h=c.show2400?24:0),j+=h;break;case"h":h=g.getHours()%12,0!==h&&h<10&&(h="0"+h),j+=0===h?"12":h;break;case"H":h=g.getHours(),b===v&&(h=c.show2400?24:0),j+=h>9?h:"0"+h;break;case"i":var e=g.getMinutes();j+=e>9?e:"0"+e;break;case"s":d=g.getSeconds(),j+=d>9?d:"0"+d;break;case"\\":k++,j+=c.timeFormat.charAt(k);break;default:j+=i}return j}function t(a,b){if(""===a||null===a)return null;if("object"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();if("string"!=typeof a)return a;a=a.toLowerCase().replace(/[\s\.]/g,""),"a"!=a.slice(-1)&&"p"!=a.slice(-1)||(a+="m");var c="("+w.am.replace(".","")+"|"+w.pm.replace(".","")+"|"+w.AM.replace(".","")+"|"+w.PM.replace(".","")+")?",d=new RegExp("^"+c+"([0-9]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?"+c+"$"),e=a.match(d);if(!e)return null;var f=parseInt(1*e[2],10),g=e[1]||e[5],h=f,i=1*e[3]||0,j=1*e[4]||0;if(f<=12&&g){var k=g==w.pm||g==w.PM;h=12==f?k?12:0:f+(k?12:0)}else if(b){var l=3600*f+60*i+j;if(l>=v+(b.show2400?1:0)){if(b.wrapHours===!1)return null;h=f%24}}var m=3600*h+60*i+j;if(f<12&&!g&&b&&b._twelveHourTime&&b.scrollDefault){var n=m-b.scrollDefault();n<0&&n>=v/-2&&(m=(m+v/2)%v)}return m}function u(a,b){return a==v&&b.show2400?a:a%v}var v=86400,w={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},x={appendTo:"body",className:null,closeOnWindowScroll:!1,disableTextInput:!1,disableTimeRanges:[],disableTouchKeyboard:!1,durationTime:null,forceRoundTime:!1,maxTime:null,minTime:null,noneOption:!1,orientation:"l",roundingFunction:function(a,b){if(null===a)return null;if("number"!=typeof b.step)return a;var c=a%(60*b.step),d=b.minTime||0;return c-=d%(60*b.step),c>=30*b.step?a+=60*b.step-c:a-=c,u(a,b)},scrollDefault:null,selectOnBlur:!1,show2400:!1,showDuration:!1,showOn:["click","focus"],showOnFocus:!0,step:30,stopScrollPropagation:!1,timeFormat:"g:ia",typeaheadHighlight:!0,useSelect:!1,wrapHours:!0},y={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in x)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},x,b,f);
7if(h.lang&&(w=a.extend(w,h.lang)),h=c(h),e.data("timepicker-settings",h),e.addClass("ui-timepicker-input"),h.useSelect)d(e);else{if(e.prop("autocomplete","off"),h.showOn)for(var i in h.showOn)e.on(h.showOn[i]+".timepicker",y.show);e.on("change.timepicker",k),e.on("keydown.timepicker",o),e.on("keyup.timepicker",p),h.disableTextInput&&e.on("keydown.timepicker",n),e.on("cut.timepicker",p),e.on("paste.timepicker",p),k.call(e.get(0),null,"initial")}})},show:function(c){var e=a(this),f=e.data("timepicker-settings");if(c&&c.preventDefault(),f.useSelect)return void e.data("timepicker-list").focus();h(e)&&e.blur();var k=e.data("timepicker-list");if(!e.prop("readonly")&&(k&&0!==k.length&&"function"!=typeof f.durationTime||(d(e),k=e.data("timepicker-list")),!b(k))){e.data("ui-timepicker-value",e.val()),j(e,k),y.hide(),k.show();var m={};f.orientation.match(/r/)?m.left=e.offset().left+e.outerWidth()-k.outerWidth()+parseInt(k.css("marginLeft").replace("px",""),10):m.left=e.offset().left+parseInt(k.css("marginLeft").replace("px",""),10);var n;n=f.orientation.match(/t/)?"t":f.orientation.match(/b/)?"b":e.offset().top+e.outerHeight(!0)+k.outerHeight()>a(window).height()+a(window).scrollTop()?"t":"b","t"==n?(k.addClass("ui-timepicker-positioned-top"),m.top=e.offset().top-k.outerHeight()+parseInt(k.css("marginTop").replace("px",""),10)):(k.removeClass("ui-timepicker-positioned-top"),m.top=e.offset().top+e.outerHeight()+parseInt(k.css("marginTop").replace("px",""),10)),k.offset(m);var o=k.find(".ui-timepicker-selected");if(!o.length){var p=t(l(e));null!==p?o=i(e,k,p):f.scrollDefault&&(o=i(e,k,f.scrollDefault()))}if(o.length&&!o.hasClass("ui-timepicker-disabled")||(o=k.find("li:not(.ui-timepicker-disabled):first")),o&&o.length){var q=k.scrollTop()+o.position().top-o.outerHeight();k.scrollTop(q)}else k.scrollTop(0);return f.stopScrollPropagation&&a(document).on("wheel.ui-timepicker",".ui-timepicker-wrapper",function(b){b.preventDefault();var c=a(this).scrollTop();a(this).scrollTop(c+b.originalEvent.deltaY)}),a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",g),a(window).on("resize.ui-timepicker",g),f.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",g),e.trigger("showTimepicker"),this}},hide:function(c){var d=a(this),e=d.data("timepicker-settings");return e&&e.useSelect&&d.blur(),a(".ui-timepicker-wrapper").each(function(){var c=a(this);if(b(c)){var d=c.data("timepicker-input"),e=d.data("timepicker-settings");e&&e.selectOnBlur&&q(d),c.hide(),d.trigger("hideTimepicker")}}),this},option:function(b,e){return"string"==typeof b&&"undefined"==typeof e?a(this).data("timepicker-settings")[b]:this.each(function(){var f=a(this),g=f.data("timepicker-settings"),h=f.data("timepicker-list");"object"==typeof b?g=a.extend(g,b):"string"==typeof b&&(g[b]=e),g=c(g),f.data("timepicker-settings",g),k.call(f.get(0),{type:"change"},"initial"),h&&(h.remove(),f.data("timepicker-list",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return t(l(this))},getTime:function(a){var b=this,c=l(b);if(!c)return null;var d=t(c);if(null===d)return null;a||(a=new Date);var e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},isVisible:function(){var a=this,c=a.data("timepicker-list");return!(!c||!b(c))},setTime:function(a){var b=this,c=b.data("timepicker-settings");if(c.forceRoundTime)var d=f(t(a),c);else var d=s(t(a),c);return a&&null===d&&c.noneOption&&(d=a),m(b,d,"initial"),k.call(b.get(0),{type:"change"},"initial"),b.data("timepicker-list")&&j(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input")){var b=a.data("timepicker-settings");return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),b.useSelect&&a.show(),a.removeData("timepicker-list"),this}}};a.fn.timepicker=function(b){return this.length?y[b]?this.hasClass("ui-timepicker-input")?y[b].apply(this,Array.prototype.slice.call(arguments,1)):this:"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.timepicker"):y.init.apply(this,arguments):this}});
8;
9/**********************************************
10 * @File Name: jquery.mb.YTPlayer.src.js
11 * @Author: Matteo Bicocchi
12 * @Date: 2020-03-16
13 * @Email: [email protected]
14 *
15 * @Last Modified by: Matteo Bicocchi
16 * @Last Modified time: 2020-03-18
17 * @Copyright: 2020. Matteo Bicocchi
18 *
19 *  Open Lab s.r.l., Florence - Italy
20 *  @blog:  http://pupunzi.open-lab.com
vendor: 74,946 bytes, lines 21-2785
21 *  @site:  http://pupunzi.com
22 ****************************************************/
23
24
25var ytp = ytp || {};
26
27let YTPRndSuffix = new Date().getTime();
28let YTPTimerLabels = {
29	init        : "YTPlayerInit_" + YTPRndSuffix,
30	startPlaying: "YTPlayerStartPlay_" + YTPRndSuffix
31};
32
33function onYouTubeIframeAPIReady() {
34	if (ytp.YTAPIReady)
35		return;
36
37	ytp.YTAPIReady = true;
38	jQuery(document).trigger('YTAPIReady')
39}
40
41let getYTPVideoID = function (url) {
42	let videoID, playlistID;
43	if (url.indexOf('youtu.be') > 0 || url.indexOf('youtube.com/embed') > 0) {
44		videoID = url.substr(url.lastIndexOf('/') + 1, url.length);
45		playlistID = videoID.indexOf('?list=') > 0 ? videoID.substr(videoID.lastIndexOf('='), videoID.length) : null;
46		videoID = playlistID ? videoID.substr(0, videoID.lastIndexOf('?')) : videoID
47	} else if (url.indexOf('http') > -1) {
48		//videoID = url.match( /([\/&]v\/([^&#]*))|([\\?&]v=([^&#]*))/ )[ 1 ];
49		videoID = url.match(/[\\?&]v=([^&#]*)/)[1];
50		playlistID = url.indexOf('list=') > 0 ? url.match(/[\\?&]list=([^&#]*)/)[1] : null
51	} else {
52		videoID = url.length > 15 ? null : url;
53		playlistID = videoID ? null : url
54	}
55	return {
56		videoID   : videoID,
57		playlistID: playlistID
58	}
59};
60
61(function (jQuery, ytp) {
62
63	jQuery.mbYTPlayer = {
64		name   : 'jquery.mb.YTPlayer',
65		version: '3.3.9',
66		build  : '7581',
67		author : 'Matteo Bicocchi (pupunzi)',
68		apiKey : '',
69
70		/*
71		 * Default options for the player
72		 */
73		defaults        : {
74			/**
75			 videoURL (string)
76			 the complete Youtube video URL or the short url or the videoID
77			 */
78			videoURL: null,
79
80			/**
81			 containment (string)
82			 default containment for the player
83			 */
84			containment: 'body',
85
86			/**
87			 ratio (string or number)
88			 "auto", "16/9", "4/3" or number: 4/3, 16/9
89			 */
90			ratio: 'auto',
91
92			/**
93			 fadeOnStartTime (int)
94			 fade in timing at video start
95			 */
96			fadeOnStartTime: 1000,
97
98			/**
99			 startAt (int)
100			 start second
101			 */
102			startAt: 0,
103
104			/**
105			 stopAt (int)
106			 stop second
107			 */
108			stopAt: 0,
109
110			/**
111			 autoPlay (bool)
112			 on page load video should start or pause
113			 */
114			autoPlay: true,
115
116			/**
117			 delayAtStart (bool)
118			 If the YT API don't fire the event the player will try to start anyway after...
119			 */
120			delayAtStart: 1000,
121
122			/**
123			 coverImage (string)
124			 The path to the image to be used as cover if the autoPlay option is set to false
125			 */
126			coverImage: false,
127
128			/**
129			 loop (bool or int)
130			 video should loop or not; if number it will loop for the specified times
131			 */
132			loop: true,
133
134			/**
135			 addRaster (bool)
136			 shows a raster image over the video (added via CSS)
137			 You can change the raster image via CSS:
138			 .YTPOverlay.raster { background: url(images/raster.png)}
139			 */
140			addRaster: false,
141
142			/**
143			 mask (bool or object) the key is the second and the value is the path to the image
144			 Ex: mask:{ 0:'assets/mask-1.png', 5:'assets/mask-2.png', 30: false, 50:'assets/mask-3.png'}
145			 */
146			mask: false,
147
148			/**
149			 opacity (int)
150			 0 to 1
151			 */
152			opacity: 1,
153
154			/**
155			 quality (string)
156			 @deprecated
157
158			 setPlaybackQuality has been deprecated on the YT API and doesn't work anymore
159			 “small”, “medium”, “large”, “hd720”, “hd1080”, “highres”, "default"
160			 */
161			quality: 'default',
162
163			/**
164			 vol (int)
165			 0 to 100
166			 */
167			vol: 50,
168
169			/**
170			 mute (bool)
171			 mute the video at start
172			 */
173			mute: false,
174
175			/**
176			 showControls (bool)
177			 shows the control bar at the bottom of the containment
178			 */
179			showControls: true,
180
181			/**
182			 anchor (string)
183			 center,top,bottom,left,right combined in pair
184			 */
185			anchor: 'center,center',
186
187			/**
188			 showAnnotations (bool)
189			 display the annotations on video
190			 */
191			showAnnotations: false,
192
193			/**
194			 cc_load_policy (bool)
195			 display the subtitles
196			 */
197			cc_load_policy: false,
198
199			/**
200			 showYTLogo (bool)
201			 display the Youtube logotype inside the button bar
202			 */
203			showYTLogo: true,
204
205			/**
206			 useOnMobile (bool)
207			 activate the player also on mobile
208			 */
209			useOnMobile: true,
210
211			/**
212			 playOnlyIfVisible (bool)
213			 play the video only if the containment is on screen
214			 */
215			playOnlyIfVisible: false,
216
217			/**
218			 onScreenPercentage (bool)
219			 percentage of the player height the video should stop or start when visible
220			 */
221			onScreenPercentage: 30,
222
223			/**
224			 * goFullScreenOnPlay (bool)
225			 * if the player containment is set to "self" this allow the video to go fullscreen when played
226			 */
227			goFullScreenOnPlay: false,
228
229			/**
230			 stopMovieOnBlur (bool)
231			 stop the video if the window loose the focus
232			 */
233			stopMovieOnBlur: true,
234
235			/**
236			 realfullscreen (bool)
237			 the video when in full screen covers all the display
238			 */
239			realFullscreen: true,
240
241			/**
242			 optimizeDisplay (bool)
243			 The video always fit the containment without displaying the black strips
244			 */
245			optimizeDisplay: true,
246
247			/**
248			 abundance (bool)
249			 the abudance of the video size
250			 */
251			abundance: 0.3,
252
253			/**
254			 gaTrack (bool)
255			 track the video plays on GA
256			 */
257			gaTrack: true,
258
259			/**
260			 remember_last_time (bool)
261			 when the page is reloaded the video will start from the last position
262			 */
263			remember_last_time: false,
264
265			/**
266			 addFilters (bool or string)
267			 add one or more CSS filters as object to the video
268			 Ex: {sepia: 50, hue_rotate : 220}
269			 */
270			addFilters: false,
271
272			/**
273			 useNoCookie (bool)
274			 use https://www.youtube-nocookie.com host to serve the video
275			 */
276			useNoCookie: true,
277
278			/**
279			 onReady (function)
280			 a callback function fired once the player is ready
281			 */
282			onReady: function (player) {
283			},
284
285			/**
286			 onReady (function)
287			 a callback function fired if there's an error
288			 */
289			onError: function (player, err) {
290			},
291
292			/**
293			 onEnd (function)
294			 a callback function fired when the video ends
295			 */
296			onEnd: function () {
297			}
298		},
299		/**
300		 *  @fontface icons
301		 *  */
302		controls        : {
303			play    : 'P',
304			pause   : 'p',
305			mute    : 'M',
306			unmute  : 'A',
307			onlyYT  : 'O',
308			showSite: 'R',
309			ytLogo  : 'Y'
310		},
311		controlBar      : null,
312		locationProtocol: 'https:',
313
314		/**
315		 * Applicable filters
316		 */
317		defaultFilters: {
318			grayscale : {value: 0, unit: '%'},
319			hue_rotate: {value: 0, unit: 'deg'},
320			invert    : {value: 0, unit: '%'},
321			opacity   : {value: 0, unit: '%'},
322			saturate  : {value: 0, unit: '%'},
323			sepia     : {value: 0, unit: '%'},
324			brightness: {value: 0, unit: '%'},
325			contrast  : {value: 0, unit: '%'},
326			blur      : {value: 0, unit: 'px'}
327		},
328
329		/**
330		 * build the player
331		 * @param options
332		 * @returns [players]
333		 */
334		buildPlayer: function (options) {
335
336			if (!ytp.YTAPIReady && typeof window.YT === 'undefined') {
337				jQuery('#YTAPI').remove();
338				let tag = jQuery('<script>').attr({
339					'src': 'https://www.youtube.com/iframe_api?v=' + jQuery.mbYTPlayer.version,
340					'id' : 'YTAPI'
341				});
342				jQuery('head').prepend(tag)
343			} else {
344				setTimeout(function () {
345					jQuery(document).trigger('YTAPIReady');
346					ytp.YTAPIReady = true
347				}, 100)
348			}
349
350			function isIframe() {
351				let isIfr = false;
352				try {
353					if (self.location.href !== top.location.href) isIfr = true
354				} catch (e) {
355					isIfr = true
356				}
357				return isIfr
358			}
359
360			return this.each(function () {
361				let YTPlayer = this;
362				let $YTPlayer = jQuery(YTPlayer);
363				$YTPlayer.hide();
364				YTPlayer.loop = 0;
365				YTPlayer.state = 0;
366				YTPlayer.filters = jQuery.extend(true, {}, jQuery.mbYTPlayer.defaultFilters);
367				YTPlayer.filtersEnabled = true;
368				YTPlayer.id = YTPlayer.id || 'YTP_' + new Date().getTime();
369				$YTPlayer.addClass('mb_YTPlayer');
370
371				/**
372				 Set properties
373				 */
374				let property = $YTPlayer.data('property') && typeof $YTPlayer.data('property') == 'string' ?
375						eval('(' + $YTPlayer.data('property') + ')') :
376						$YTPlayer.data('property');
377
378				if (typeof property !== 'object')
379					property = {};
380
381				YTPlayer.opt = jQuery.extend(true, {}, jQuery.mbYTPlayer.defaults, YTPlayer.opt, options, property);
382
383				YTPRndSuffix = getYTPVideoID(YTPlayer.opt.videoURL).videoID;
384				YTPTimerLabels = {
385					init        : "YTPlayerInit_" + YTPRndSuffix,
386					startPlaying: "YTPlayerStartPlay_" + YTPRndSuffix
387				};
388
389				console.time(YTPTimerLabels.init);
390				console.time(YTPTimerLabels.startPlaying);
391
392				YTPlayer.opt.elementId = YTPlayer.id;
393
394				if (YTPlayer.opt.vol === 0) {
395					YTPlayer.opt.vol = 1;
396					YTPlayer.opt.mute = true
397				}
398
399				if (YTPlayer.opt.loop && typeof YTPlayer.opt.loop === 'boolean') {
400					YTPlayer.opt.loop = 9999
401				}
402
403				/**
404				 Disable fullScreen if is in an iframe or full-screen API is not available
405				 */
406				let fullScreenAvailable = document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled;
407				YTPlayer.opt.realFullscreen = isIframe() || !fullScreenAvailable ? false : YTPlayer.opt.realFullscreen;
408
409				/**
410				 Manage annotations
411				 */
412				YTPlayer.opt.showAnnotations = YTPlayer.opt.showAnnotations ? '1' : '3';
413
414				/**
415				 Manage show subtitle and caption
416				 */
417				YTPlayer.opt.cc_load_policy = YTPlayer.opt.cc_load_policy ? '1' : '0';
418
419				/**
420				 Manage cover image
421				 */
422				YTPlayer.opt.coverImage = YTPlayer.opt.coverImage || YTPlayer.opt.backgroundImage;
423
424				/**
425				 Manage Quality
426				 the setPlaybackQuality has been deprecated by YT
427				 */
428				YTPlayer.opt.quality = 'hd1080';
429
430				YTPlayer.opt.containment = YTPlayer.opt.containment === 'self' ? $YTPlayer : jQuery(YTPlayer.opt.containment);
431				YTPlayer.isRetina = (window.retina || window.devicePixelRatio > 1);
432
433				YTPlayer.opt.ratio = YTPlayer.opt.ratio === 'auto' ? 16 / 9 : YTPlayer.opt.ratio;
434				YTPlayer.opt.ratio = eval(YTPlayer.opt.ratio);
435
436				let origContainmentBackground = YTPlayer.opt.containment.css('background-image');
437				origContainmentBackground = (origContainmentBackground === 'none') ? null : origContainmentBackground;
438				YTPlayer.orig_containment_background = origContainmentBackground;
439
440				if (!$YTPlayer.attr('id'))
441					$YTPlayer.attr('id', 'ytp_' + new Date().getTime());
442
443				YTPlayer.playerID = 'iframe_' + YTPlayer.id;
444
445				YTPlayer.isAlone = false;
446				YTPlayer.hasFocus = true;
447				YTPlayer.videoID = YTPlayer.opt.videoURL ?
448						getYTPVideoID(YTPlayer.opt.videoURL).videoID : $YTPlayer.attr('href') ?
449								getYTPVideoID($YTPlayer.attr('href')).videoID :
450								false;
451
452				/**
453				 Check if it is a video list
454				 */
455				YTPlayer.playlistID = YTPlayer.opt.videoURL ?
456						getYTPVideoID(YTPlayer.opt.videoURL).playlistID : $YTPlayer.attr('href') ?
457								getYTPVideoID($YTPlayer.attr('href')).playlistID :
458								false;
459
460				let start_from_last = 0;
461				if (jQuery.mbCookie.get('YTPlayer_start_from' + YTPlayer.videoID))
462					start_from_last = parseFloat(jQuery.mbCookie.get('YTPlayer_start_from' + YTPlayer.videoID));
463				if (YTPlayer.opt.remember_last_time && start_from_last) {
464					YTPlayer.start_from_last = start_from_last;
465					jQuery.mbCookie.remove('YTPlayer_start_from' + YTPlayer.videoID)
466				}
467
468				YTPlayer.isPlayer = $YTPlayer.is(YTPlayer.opt.containment);
469				YTPlayer.isBackground = YTPlayer.opt.containment.is('body');
470
471				if (YTPlayer.isBackground && ytp.backgroundIsInited)
472					return;
473
474				/**
475				 Hide the placeholder if it's not the target of the player
476				 */
477				if (YTPlayer.isPlayer)
478					$YTPlayer.show();
479
480				/**
481				 create the overlay
482				 */
483				YTPlayer.overlay = jQuery('<div/>').css({
484					position: 'absolute',
485					top     : 0,
486					left    : 0,
487					width   : '100%',
488					height  : '100%'
489				}).addClass('YTPOverlay');
490
491				$YTPlayer.changeCoverImage();
492
493				/**
494				 create the wrapper
495				 */
496				YTPlayer.wrapper = jQuery('<div/>').attr('id', 'wrapper_' + YTPlayer.id).css({
497					position : 'absolute',
498					zIndex   : 0,
499					minWidth : '100%',
500					minHeight: '100%',
501					left     : 0,
502					top      : 0,
503					overflow : 'hidden',
504					opacity  : 0
505				}).addClass('mbYTP_wrapper');
506
507				/**
508				 If is an inline player toggle play if the overlay is clicked
509				 */
510				if (YTPlayer.isPlayer) {
511					let inlinePlayButtonCss = jQuery.mbBrowser.mobile ? "inlinePlayButtonMobile" : "inlinePlayButton";
512					YTPlayer.inlinePlayButton = jQuery('<div/>').addClass(inlinePlayButtonCss).html(jQuery.mbYTPlayer.controls.play);
513					$YTPlayer.append(YTPlayer.inlinePlayButton);
514					YTPlayer.inlinePlayButton.on('click', function (e) {
515
516						$YTPlayer.YTPPlay();
517						/**
518						 * Hide the PLAY button on play
519						 */
520						YTPlayer.inlinePlayButton.hide();
521
522						/**
523						 * set the fullscreen on play
524						 */
525						if (YTPlayer.opt.goFullScreenOnPlay) {
526							$YTPlayer.YTPFullscreen();
527						}
528
529						e.stopPropagation()
530					});
531
532					if (YTPlayer.opt.autoPlay)
533						YTPlayer.inlinePlayButton.hide();
534
535					YTPlayer.overlay.on('click', function () {
536						$YTPlayer.YTPTogglePlay();
537
538						if (YTPlayer.opt.goFullScreenOnPlay) {
539							$YTPlayer.YTPFullscreen();
540						}
541
542					}).css({cursor: 'pointer'})
543
544				}
545
546				/**
547				 create the playerBox where the YT iframe will be placed
548				 */
549				let playerBox = jQuery('<div/>').attr('id', YTPlayer.playerID).addClass('playerBox');
550				playerBox.css({
551					position: 'absolute',
552					zIndex  : 0,
553					width   : '100%',
554					height  : '100%',
555					top     : 0,
556					left    : 0,
557					overflow: 'hidden',
558					opacity : 1
559				});
560
561				YTPlayer.wrapper.append(playerBox);
562				playerBox.after(YTPlayer.overlay);
563
564				if (YTPlayer.isPlayer) {
565					YTPlayer.inlineWrapper = jQuery('<div/>').addClass('inline-YTPlayer');
566
567					YTPlayer.inlineWrapper.css({
568						position: 'relative',
569						maxWidth: YTPlayer.opt.containment.css('width')
570					});
571
572					YTPlayer.opt.containment.css({
573						position     : 'relative',
574						paddingBottom: '56.25%',
575						overflow     : 'hidden',
576						height       : 0
577					});
578					YTPlayer.opt.containment.wrap(YTPlayer.inlineWrapper)
579				}
580
581				/**
582				 Loop all the elements inside the container and check if their position is not "static"
583				 */
584				YTPlayer.opt.containment.children().not('script, style').each(function () {
585					if (jQuery(this).css('position') === 'static')
586						jQuery(this).css('position', 'relative')
587				});
588
589				if (YTPlayer.isBackground) {
590					jQuery('body').css({
591						boxSizing: 'border-box'
592					});
593
594					YTPlayer.wrapper.css({
595						position: 'fixed',
596						top     : 0,
597						left    : 0,
598						zIndex  : 0
599					})
600
601				} else if (YTPlayer.opt.containment.css('position') === 'static') {
602
603					YTPlayer.opt.containment.css({
604						position: 'relative'
605					});
606					$YTPlayer.show()
607				}
608				YTPlayer.opt.containment.prepend(YTPlayer.wrapper);
609
610				if (!YTPlayer.isBackground) {
611					YTPlayer.overlay.on('mouseenter', function () {
612						if (YTPlayer.controlBar && YTPlayer.controlBar.length)
613							YTPlayer.controlBar.addClass('visible')
614					}).on('mouseleave', function () {
615						if (YTPlayer.controlBar && YTPlayer.controlBar.length)
616							YTPlayer.controlBar.removeClass('visible')
617					})
618				}
619
620				if (jQuery.mbBrowser.mobile && !YTPlayer.opt.useOnMobile) {
621					if (YTPlayer.opt.coverImage) {
622						YTPlayer.wrapper.css({
623							backgroundImage   : 'url(' + YTPlayer.opt.coverImage + ')',
624							backgroundPosition: 'center center',
625							backgroundSize    : 'cover',
626							backgroundRepeat  : 'no-repeat',
627							opacity           : 1
628						});
629
630						YTPlayer.wrapper.css({opacity: 1})
631					}
632					return $YTPlayer
633				}
634
635				/**
636				 If is on device start playing on first touch
637				 */
638				if (jQuery.mbBrowser.mobile && YTPlayer.opt.autoPlay && YTPlayer.opt.useOnMobile)
639					jQuery('body').one('touchstart', function () {
640						YTPlayer.player.playVideo()
641					});
642
643				jQuery(document).one('YTAPIReady', function () {
644					$YTPlayer.trigger('YTAPIReady_' + YTPlayer.id);
645					ytp.YTAPIReady = true
646				});
647
648				YTPlayer.isOnScreen = jQuery.mbYTPlayer.isOnScreen(YTPlayer, YTPlayer.opt.onScreenPercentage);
649
650				$YTPlayer.one('YTAPIReady_' + YTPlayer.id, function () {
651
652					let YTPlayer = this;
653					let $YTPlayer = jQuery(YTPlayer);
654
655					if ((YTPlayer.isBackground && ytp.backgroundIsInited) || YTPlayer.isInit)
656						return;
657
658					if (YTPlayer.isBackground)
659						ytp.backgroundIsInited = true;
660
661					YTPlayer.opt.autoPlay = typeof YTPlayer.opt.autoPlay == 'undefined' ? (!!YTPlayer.isBackground) : YTPlayer.opt.autoPlay;
662					YTPlayer.opt.vol = YTPlayer.opt.vol ? YTPlayer.opt.vol : 100;
663
664					jQuery.mbYTPlayer.getDataFromAPI(YTPlayer);
665
666					jQuery(YTPlayer).on('YTPChanged', function (e) {
667
668						if (YTPlayer.isInit)
669							return;
670
671						YTPlayer.isInit = true;
672
673						/** Initialize the YT player ------------------------------------
674						 * Youtube player variables
675						 * @type {{modestbranding: number, autoplay: number, controls: number, showinfo: number, rel: number, enablejsapi: number, version: number, playerapiid: string, origin: string, allowfullscreen: boolean, iv_load_policy: (string|*|jQuery.mbYTPlayer.opt.showAnnotations), playsinline: number}}
676						 */
677						let playerVars = {
678							'modestbranding' : 1,
679							'autoplay'       : 0,
680							'controls'       : 0,
681							'showinfo'       : 0,
682							'rel'            : 0,
683							'enablejsapi'    : 1,
684							'version'        : 3,
685							'playerapiid'    : YTPlayer.playerID,
686							'origin'         : '*',
687							'allowfullscreen': true,
688							'wmode'          : 'transparent',
689							'iv_load_policy' : YTPlayer.opt.showAnnotations,
690							'cc_load_policy' : YTPlayer.opt.cc_load_policy,
691							'playsinline'    : jQuery.mbBrowser.mobile && !YTPlayer.isPlayer ? 1 : 0,
692
693							/**
694							 Check if the mbBrowser can play HTML5 videos
695							 */
696							'html5': document.createElement('video').canPlayType ? 1 : 0
697						};
698
699						new YT.Player(YTPlayer.playerID, {
700							//videoId: YTPlayer.videoID.toString(),
701							host      : YTPlayer.opt.useNoCookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
702							playerVars: playerVars,
703							events    : {
704								'onReady'      : function (event) {
705									YTPlayer.player = event.target;
706									YTPlayer.player.loadVideoById({
707										videoId         : YTPlayer.videoID.toString(),
708										suggestedQuality: YTPlayer.opt.quality
709									});
710
711									$YTPlayer.trigger('YTPlayerIsReady_' + YTPlayer.id)
712								},
713								/**
714								 * on State Change
715								 * @param event
716								 *
717								 * -1 (unstarted)
718								 * 0 (ended)
719								 * 1 (playing)
720								 * 2 (paused)
721								 * 3 (buffering)
722								 * 5 (video cued)
723								 */
724								'onStateChange': function (event) {
725
726									if (typeof event.target.getPlayerState != 'function')
727										return;
728
729									let state = event.target.getPlayerState();
730
731									if (YTPlayer.preventTrigger || YTPlayer.isStarting) {
732										YTPlayer.preventTrigger = false;
733										return
734									}
735
736									YTPlayer.state = state;
737									// console.debug(YTPlayer.state);
738
739									if (event.data === YT.PlayerState.PLAYING) {
740										event.target.setPlaybackQuality(YTPlayer.opt.quality)
741									}
742
743									let eventType;
744									switch (state) {
745
746											/** unstarted */
747										case -1:
748											eventType = 'YTPUnstarted';
749											break;
750
751											/** unstarted */
752										case 0:
753											eventType = 'YTPRealEnd';
754											break;
755
756											/** play */
757										case 1:
758											eventType = 'YTPPlay';
759											if (YTPlayer.controlBar.length)
760												YTPlayer.controlBar.find('.mb_YTPPlayPause').html(jQuery.mbYTPlayer.controls.pause);
761
762											if (YTPlayer.isPlayer)
763												YTPlayer.inlinePlayButton.hide();
764
765											jQuery(document).off('mousedown.YTPstart');
766											break;
767
768											/** pause */
769										case 2:
770											eventType = 'YTPPause';
771											if (YTPlayer.controlBar.length)
772												YTPlayer.controlBar.find('.mb_YTPPlayPause').html(jQuery.mbYTPlayer.controls.play);
773
774											if (YTPlayer.isPlayer)
775												YTPlayer.inlinePlayButton.show();
776											break;
777
778											/** buffer */
779										case 3:
780											// YTPlayer.player.setPlaybackQuality('default');
781											YTPlayer.player.setPlaybackQuality(YTPlayer.opt.quality);
782											eventType = 'YTPBuffering';
783											if (YTPlayer.controlBar.length)
784												YTPlayer.controlBar.find('.mb_YTPPlayPause').html(jQuery.mbYTPlayer.controls.play);
785											break;
786
787											/** cued */
788										case 5:
789											eventType = 'YTPCued';
790											break;
791
792										default:
793											break
794									}
795
796									/**
797									 Trigger state events
798									 */
799									let YTPEvent = jQuery.Event(eventType);
800									YTPEvent.time = YTPlayer.currentTime;
801									jQuery(YTPlayer).trigger(YTPEvent)
802								},
803
804								/**
805								 * onPlaybackQualityChange
806								 * @param e
807								 */
808								'onPlaybackQualityChange': function (e) {
809									let quality = e.target.getPlaybackQuality();
810									let YTPQualityChange = jQuery.Event('YTPQualityChange');
811									YTPQualityChange.quality = quality;
812									jQuery(YTPlayer).trigger(YTPQualityChange)
813								},
814
815								/**
816								 * onError
817								 * @param err
818								 *
819								 2 – The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.
820								 5 – The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.
821								 100 – The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.
822								 101 – The owner of the requested video does not allow it to be played in embedded players.
823								 150 – This error is the same as 101. It's just a 101 error in disguise!
824								 */
825								'onError': function (err) {
826
827									if (typeof YTPlayer.opt.onError == 'function')
828										YTPlayer.opt.onError($YTPlayer, err);
829
830									console.debug("error:", err);
831
832									switch (err.data) {
833										case 2:
834											console.error('video ID:: ' + YTPlayer.videoID + ': The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.');
835											break;
836										case 5:
837											console.error('video ID:: ' + YTPlayer.videoID + ': The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.');
838											break;
839										case 100:
840											console.error('video ID:: ' + YTPlayer.videoID + ': The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.');
841											break;
842										case 101:
843										case 150:
844											console.error('video ID:: ' + YTPlayer.videoID + ': The video doesn\'t exist or The owner does not allow it to be played in embedded players.');
845											break
846									}
847
848									if (YTPlayer.isList)
849										jQuery(YTPlayer).YTPPlayNext()
850								}
851							}
852						});
853
854						$YTPlayer.on('YTPlayerIsReady_' + YTPlayer.id, function () {
855
856							if (YTPlayer.isReady)
857								return this;
858
859							YTPlayer.playerEl = YTPlayer.player.getIframe();
860							jQuery(YTPlayer.playerEl).unselectable();
861							$YTPlayer.optimizeDisplay();
862
863							/**
864							 * Optimize display on resize
865							 */
866							jQuery(window).off('resize.YTP_' + YTPlayer.id).on('resize.YTP_' + YTPlayer.id, function () {
867								$YTPlayer.optimizeDisplay()
868							});
869
870							/**
871							 * Optimize display on orientation change
872							 */
873							jQuery(window).off('orientationchange.YTP_' + YTPlayer.id).on('orientationchange.YTP_' + YTPlayer.id, function () {
874								$YTPlayer.optimizeDisplay()
875							});
876
877							/**
878							 * Set the time of the last visit progress
879							 */
880							if (YTPlayer.opt.remember_last_time) {
881								jQuery(window).on('unload.YTP_' + YTPlayer.id, function () {
882									let current_time = YTPlayer.player.getCurrentTime();
883									jQuery.mbCookie.set('YTPlayer_start_from' + YTPlayer.videoID, current_time, 0)
884								})
885							}
886
887							$YTPlayer.YTPCheckForState()
888
889						})
890					})
891				});
892
893				$YTPlayer.off('YTPTime.mask');
894				jQuery.mbYTPlayer.applyMask(YTPlayer);
895
896				console.timeEnd(YTPTimerLabels.init);
897
898				setTimeout(function () {
899					if (!ytp.YTAPIReady && typeof window.YT == "object") {
900						jQuery(document).trigger('YTAPIReady');
901						ytp.YTAPIReady = true;
902						console.error("YTPlayer: More then a call to the YT API has been detected")
903					}
904				}, YTPlayer.opt.delayAtStart)
905			})
906		},
907
908		/**
909		 *
910		 * @param YTPlayer
911		 * @param perc
912		 * @returns {boolean}
913		 */
914		isOnScreen: function (YTPlayer, perc) {
915			perc = perc || 10;
916			let playerBox = YTPlayer.wrapper;
917			let winTop = jQuery(window).scrollTop();
918			let winBottom = winTop + jQuery(window).height();
919
920			let margin = (playerBox.height() * perc) / 100;
921			let elTop = playerBox.offset().top + margin;
922			let elBottom = playerBox.offset().top + (playerBox.height() - margin);
923
924			return ((elBottom <= winBottom) && (elTop >= winTop))
925		},
926
927		/**
928		 * getDataFromAPI
929		 * @param YTPlayer
930		 */
931		getDataFromAPI: function (YTPlayer) {
932
933			YTPlayer.videoData = jQuery.mbStorage.get('YTPlayer_data_' + YTPlayer.videoID);
934			if (YTPlayer.videoData) {
935				setTimeout(function () {
936					YTPlayer.dataReceived = true;
937
938					let YTPChanged = jQuery.Event('YTPChanged');
939					YTPChanged.time = YTPlayer.currentTime;
940					YTPChanged.videoId = YTPlayer.videoID;
941					YTPChanged.opt = YTPlayer.opt;
942
943					//console.debug("videoData:",YTPlayer.videoData)
944
945					jQuery(YTPlayer).trigger(YTPChanged);
946
947					let YTPData = jQuery.Event('YTPData');
948					YTPData.prop = {};
949
950					for (let x in YTPlayer.videoData)
951						if (YTPlayer.videoData.hasOwnProperty(x))
952							YTPData.prop[x] = YTPlayer.videoData[x];
953
954					jQuery(YTPlayer).trigger(YTPData)
955
956				}, YTPlayer.opt.fadeOnStartTime);
957
958				YTPlayer.hasData = true
959
960			} else if (jQuery.mbYTPlayer.apiKey) {
961
962				/**
963				 * Get video info from API3 (needs api key)
964				 * snippet,player,contentDetails,statistics,status
965				 */
966
967				jQuery.getJSON('https://www.googleapis.com/youtube/v3/videos?id=' + YTPlayer.videoID + '&key=' + jQuery.mbYTPlayer.apiKey + '&part=snippet', function (data) {
968					YTPlayer.dataReceived = true;
969
970					let YTPChanged = jQuery.Event('YTPChanged');
971					YTPChanged.time = YTPlayer.currentTime;
972					YTPChanged.videoId = YTPlayer.videoID;
973					jQuery(YTPlayer).trigger(YTPChanged);
974
975					function parseYTPlayer_data(data) {
976						YTPlayer.videoData = {};
977						YTPlayer.videoData.id = YTPlayer.videoID;
978						YTPlayer.videoData.channelTitle = data.channelTitle;
979						YTPlayer.videoData.title = data.title;
980						YTPlayer.videoData.description = data.description.length < 400 ? data.description : data.description.substring(0, 400) + ' ...';
981						YTPlayer.videoData.thumb_max = data.thumbnails.maxres ? data.thumbnails.maxres.url : null;
982						YTPlayer.videoData.thumb_high = data.thumbnails.high ? data.thumbnails.high.url : null;
983						YTPlayer.videoData.thumb_medium = data.thumbnails.medium ? data.thumbnails.medium.url : null;
984						jQuery.mbStorage.set('YTPlayer_data_' + YTPlayer.videoID, YTPlayer.videoData)
985					}
986
987					if (!data.items[0]) {
988						YTPlayer.videoData = {};
989						YTPlayer.hasData = false
990					} else {
991						parseYTPlayer_data(data.items[0].snippet);
992						YTPlayer.hasData = true
993					}
994
995					let YTPData = jQuery.Event('YTPData');
996					YTPData.prop = {};
997					for (let x in YTPlayer.videoData)
998						YTPData.prop[x] = YTPlayer.videoData[x];
999
1000					jQuery(YTPlayer).trigger(YTPData)
1001				})
1002						.fail(function (jqxhr) {
1003							console.error("YT data error:: ", jqxhr);
1004							YTPlayer.hasData = false;
1005
1006							let YTPChanged = jQuery.Event('YTPChanged');
1007							YTPChanged.time = YTPlayer.currentTime;
1008							YTPChanged.videoId = YTPlayer.videoID;
1009							jQuery(YTPlayer).trigger(YTPChanged)
1010						})
1011			} else {
1012
1013				setTimeout(function () {
1014					let YTPChanged = jQuery.Event('YTPChanged');
1015					YTPChanged.time = YTPlayer.currentTime;
1016					YTPChanged.videoId = YTPlayer.videoID;
1017					jQuery(YTPlayer).trigger(YTPChanged)
1018				}, 10);
1019				YTPlayer.videoData = null
1020			}
1021
1022			YTPlayer.opt.ratio = YTPlayer.opt.ratio == 'auto' ? 16 / 9 : YTPlayer.opt.ratio;
1023
1024			if (YTPlayer.isPlayer && !YTPlayer.opt.autoPlay) { //&& ( !jQuery.mbBrowser.mobile && !jQuery.isTablet )
1025				YTPlayer.loading = jQuery('<div/>').addClass('loading').html('Loading').hide();
1026				jQuery(YTPlayer).append(YTPlayer.loading);
1027				YTPlayer.loading.fadeIn()
1028			}
1029		},
1030
1031		/**
1032		 * removeStoredData
1033		 */
1034		removeStoredData: function () {
1035			jQuery.mbStorage.remove()
1036		},
1037
1038		/**
1039		 * getVideoData
1040		 * @returns {*|YTPlayer.videoData}
1041		 */
1042		getVideoData: function () {
1043			let YTPlayer = this.get(0);
1044			return YTPlayer.videoData
1045		},
1046
1047		/**
1048		 * getVideoID
1049		 * @returns {*|YTPlayer.videoID|boolean}
1050		 */
1051		getVideoID: function () {
1052			let YTPlayer = this.get(0);
1053			return YTPlayer.videoID || false
1054		},
1055
1056		/**
1057		 * getPlaylistID
1058		 * @returns {*|YTPlayer.videoID|boolean}
1059		 */
1060		getPlaylistID  : function () {
1061			let YTPlayer = this.get(0);
1062			return YTPlayer.playlistID || false
1063		},
1064		/**
1065		 * setVideoQuality
1066		 * @deprecated
1067		 *
1068		 * @param quality
1069		 * @returns {jQuery.mbYTPlayer}
1070		 */
1071		setVideoQuality: function (quality) {
1072
1073			let YTPlayer = this.get(0);
1074			let time = YTPlayer.player.getCurrentTime();
1075			jQuery(YTPlayer).YTPPause();
1076			YTPlayer.opt.quality = quality;
1077			YTPlayer.player.setPlaybackQuality(quality);
1078			YTPlayer.player.seekTo(time); // or set to CurrentTime using player.getCurrentTime()
1079			jQuery(YTPlayer).YTPPlay();
1080			return this;
1081		},
1082
1083		/**
1084		 * getVideoQuality
1085		 * @returns {jQuery.mbYTPlayer}
1086		 */
1087		getVideoQuality: function () {
1088			let YTPlayer = this.get(0);
1089			let quality = YTPlayer.player.getPlaybackQuality();
1090			return quality
1091		},
1092
1093		/**
1094		 * playlist
1095		 * @param videos -> Array or String (videoList ID)
1096		 * @param shuffle
1097		 * @param callback
1098		 * @returns {jQuery.mbYTPlayer}
1099		 *
1100		 * To retrieve a Youtube playlist the Youtube API key is required:
1101		 * https://console.developers.google.com/
1102		 * jQuery.mbYTPlayer.apiKey
1103		 */
1104		playlist: function (videos, shuffle, callback) {
1105
1106			let $YTPlayer = this;
1107			let YTPlayer = $YTPlayer.get(0);
1108
1109			YTPlayer.isList = true;
1110
1111			if (shuffle)
1112				videos = jQuery.shuffle(videos);
1113
1114			if (!YTPlayer.videoID) {
1115				YTPlayer.videos = videos;
1116				YTPlayer.videoCounter = 1;
1117				YTPlayer.videoLength = videos.length;
1118				jQuery(YTPlayer).data('property', videos[0]);
1119				jQuery(YTPlayer).YTPlayer()
1120			}
1121
1122			if (typeof callback == 'function')
1123				jQuery(YTPlayer).on('YTPChanged', function () {
1124					callback(YTPlayer)
1125				});
1126
1127			jQuery(YTPlayer).on('YTPEnd', function () {
1128				jQuery(YTPlayer).YTPPlayNext()
1129			});
1130			return this
1131		},
1132
1133		/**
1134		 * playNext
1135		 * @returns {jQuery.mbYTPlayer}
1136		 */
1137		playNext: function () {
1138			let YTPlayer = this.get(0);
1139			YTPlayer.videoCounter++;
1140			if (YTPlayer.videoCounter > YTPlayer.videoLength)
1141				YTPlayer.videoCounter = 1;
1142			jQuery(YTPlayer).YTPPlayIndex(YTPlayer.videoCounter);
1143			return this
1144		},
1145
1146		/**
1147		 * playPrev
1148		 * @returns {jQuery.mbYTPlayer}
1149		 */
1150		playPrev: function () {
1151			let YTPlayer = this.get(0);
1152			YTPlayer.videoCounter--;
1153			if (YTPlayer.videoCounter <= 0)
1154				YTPlayer.videoCounter = YTPlayer.videoLength;
1155			jQuery(YTPlayer).YTPPlayIndex(YTPlayer.videoCounter);
1156			return this
1157		},
1158
1159		/**
1160		 * playIndex
1161		 * @param idx
1162		 * @returns {jQuery.mbYTPlayer}
1163		 */
1164		playIndex: function (idx) {
1165			let YTPlayer = this.get(0);
1166			if (YTPlayer.checkForStartAt) {
1167				clearInterval(YTPlayer.checkForStartAt);
1168				clearInterval(YTPlayer.getState)
1169			}
1170			YTPlayer.videoCounter = idx;
1171
1172			if (YTPlayer.videoCounter >= YTPlayer.videoLength)
1173				YTPlayer.videoCounter = YTPlayer.videoLength;
1174
1175			let video = YTPlayer.videos[YTPlayer.videoCounter - 1];
1176
1177			jQuery(YTPlayer).YTPChangeVideo(video);
1178			return this
1179		},
1180
1181		/**
1182		 * changeVideo
1183		 * @param opt
1184		 * @returns {jQuery.mbYTPlayer}
1185		 */
1186		changeVideo: function (opt) {
1187			let $YTPlayer = this;
1188			let YTPlayer = $YTPlayer.get(0);
1189
1190			YTPlayer.opt.startAt = 0;
1191			YTPlayer.opt.stopAt = 0;
1192			YTPlayer.opt.mask = false;
1193			YTPlayer.opt.mute = true;
1194			YTPlayer.opt.autoPlay = true;
1195			YTPlayer.opt.addFilters = false;
1196			YTPlayer.opt.coverImage = false;
1197
1198			YTPlayer.hasData = false;
1199			YTPlayer.hasChanged = true;
1200
1201			YTPlayer.player.loopTime = undefined;
1202
1203			if (opt)
1204				jQuery.extend(YTPlayer.opt, opt);
1205
1206			YTPlayer.videoID = getYTPVideoID(YTPlayer.opt.videoURL).videoID;
1207
1208			if (YTPlayer.opt.loop && typeof YTPlayer.opt.loop == 'boolean')
1209				YTPlayer.opt.loop = 9999;
1210
1211			YTPlayer.wrapper.css({
1212				background: 'none'
1213			});
1214
1215			jQuery(YTPlayer.playerEl).CSSAnimate({
1216				opacity: 0
1217			}, YTPlayer.opt.fadeOnStartTime, function () {
1218
1219				jQuery.mbYTPlayer.getDataFromAPI(YTPlayer);
1220
1221				$YTPlayer.YTPGetPlayer().loadVideoById({
1222					videoId         : YTPlayer.videoID,
1223					suggestedQuality: YTPlayer.opt.quality
1224				});
1225
1226				$YTPlayer.YTPPause();
1227				$YTPlayer.optimizeDisplay();
1228
1229				if (YTPlayer.checkForStartAt) {
1230					clearInterval(YTPlayer.checkForStartAt);
1231					clearInterval(YTPlayer.getState)
1232				}
1233				$YTPlayer.YTPCheckForState()
1234			});
1235
1236			let YTPChangeVideo = jQuery.Event('YTPChangeVideo');
1237			YTPChangeVideo.time = YTPlayer.currentTime;
1238			jQuery(YTPlayer).trigger(YTPChangeVideo);
1239
1240			jQuery.mbYTPlayer.applyMask(YTPlayer);
1241
1242			return this
1243		},
1244
1245		/**
1246		 * getPlayer
1247		 * @returns {player}
1248		 */
1249		getPlayer: function () {
1250			let YTPlayer = this.get(0);
1251			return !YTPlayer.isReady ? null : YTPlayer.player
1252		},
1253
1254		/**
1255		 * playerDestroy
1256		 * @returns {jQuery.mbYTPlayer}
1257		 */
1258		playerDestroy: function () {
1259			let YTPlayer = this.get(0);
1260
1261			if (!YTPlayer.isReady)
1262				return this;
1263
1264			ytp.YTAPIReady = true;
1265			ytp.backgroundIsInited = false;
1266			YTPlayer.isInit = false;
1267			YTPlayer.videoID = null;
1268			YTPlayer.isReady = false;
1269			YTPlayer.wrapper.remove();
1270			jQuery('#controlBar_' + YTPlayer.id).remove();
1271			clearInterval(YTPlayer.checkForStartAt);
1272			clearInterval(YTPlayer.getState);
1273			return this
1274		},
1275
1276		/**
1277		 * fullscreen
1278		 * @param real
1279		 * @returns {jQuery.mbYTPlayer}
1280		 */
1281		fullscreen: function (real) {
1282			let YTPlayer = this.get(0);
1283
1284			if (typeof real == 'undefined')
1285				real = eval(YTPlayer.opt.realFullscreen);
1286
1287			let controls = jQuery('#controlBar_' + YTPlayer.id);
1288			let fullScreenBtn = controls.find('.mb_OnlyYT');
1289			let videoWrapper = YTPlayer.isPlayer ? YTPlayer.opt.containment : YTPlayer.wrapper;
1290
1291			if (real) {
1292				let fullscreenchange = jQuery.mbBrowser.mozilla ? 'mozfullscreenchange' : jQuery.mbBrowser.webkit ? 'webkitfullscreenchange' : 'fullscreenchange';
1293				jQuery(document).off(fullscreenchange).on(fullscreenchange, function () {
1294					let isFullScreen = RunPrefixMethod(document, 'IsFullScreen') || RunPrefixMethod(document, 'FullScreen');
1295					if (!isFullScreen) {
1296						YTPlayer.isAlone = false;
1297						fullScreenBtn.html(jQuery.mbYTPlayer.controls.onlyYT);
1298						jQuery(YTPlayer).YTPSetVideoQuality(YTPlayer.opt.quality);
1299						videoWrapper.removeClass('YTPFullscreen');
1300						videoWrapper.CSSAnimate({
1301							opacity: YTPlayer.opt.opacity
1302						}, YTPlayer.opt.fadeOnStartTime);
1303
1304						videoWrapper.css({
1305							zIndex: 0
1306						});
1307
1308						if (YTPlayer.isBackground) {
1309							jQuery('body').after(controls)
1310						} else {
1311							YTPlayer.wrapper.before(controls)
1312						}
1313						jQuery(window).resize();
1314						jQuery(YTPlayer).trigger('YTPFullScreenEnd')
1315
1316					} else {
1317						jQuery(YTPlayer).trigger('YTPFullScreenStart')
1318					}
1319				})
1320			}
1321			if (!YTPlayer.isAlone) {
1322				function hideMouse() {
1323					YTPlayer.overlay.css({
1324						cursor: 'none'
1325					})
1326				}
1327
1328				jQuery(document).on('mousemove.YTPlayer', function (e) {
1329					YTPlayer.overlay.css({
1330						cursor: 'auto'
1331					});
1332					clearTimeout(YTPlayer.hideCursor);
1333					if (!jQuery(e.target).parents().is('.mb_YTPBar'))
1334						YTPlayer.hideCursor = setTimeout(hideMouse, 3000)
1335				});
1336
1337				hideMouse();
1338
1339				if (real) {
1340					videoWrapper.css({
1341						opacity: 0
1342					});
1343					videoWrapper.addClass('YTPFullscreen');
1344					launchFullscreen(videoWrapper.get(0));
1345
1346					setTimeout(function () {
1347						videoWrapper.CSSAnimate({
1348							opacity: 1
1349						}, YTPlayer.opt.fadeOnStartTime * 2);
1350
1351						videoWrapper.append(controls);
1352						jQuery(YTPlayer).optimizeDisplay();
1353						YTPlayer.player.seekTo(YTPlayer.player.getCurrentTime() + .1, true)
1354
1355					}, YTPlayer.opt.fadeOnStartTime)
1356				} else
1357					videoWrapper.css({
1358						zIndex: 10000
1359					}).CSSAnimate({
1360						opacity: 1
1361					}, YTPlayer.opt.fadeOnStartTime * 2);
1362				fullScreenBtn.html(jQuery.mbYTPlayer.controls.showSite);
1363				YTPlayer.isAlone = true
1364			} else {
1365				jQuery(document).off('mousemove.YTPlayer');
1366				clearTimeout(YTPlayer.hideCursor);
1367				YTPlayer.overlay.css({
1368					cursor: 'auto'
1369				});
1370				if (real) {
1371					cancelFullscreen()
1372				} else {
1373					videoWrapper.CSSAnimate({
1374						opacity: YTPlayer.opt.opacity
1375					}, YTPlayer.opt.fadeOnStartTime);
1376					videoWrapper.css({
1377						zIndex: 0
1378					})
1379				}
1380				fullScreenBtn.html(jQuery.mbYTPlayer.controls.onlyYT);
1381				YTPlayer.isAlone = false
1382			}
1383
1384			function RunPrefixMethod(obj, method) {
1385				let pfx = ['webkit', 'moz', 'ms', 'o', ''];
1386				let p = 0,
1387						m, t;
1388				while (p < pfx.length && !obj[m]) {
1389					m = method;
1390					if (pfx[p] === '') {
1391						m = m.substr(0, 1).toLowerCase() + m.substr(1)
1392					}
1393					m = pfx[p] + m;
1394					t = typeof obj[m];
1395					if (t != 'undefined') {
1396						pfx = [pfx[p]];
1397						return (t == 'function' ? obj[m]() : obj[m])
1398					}
1399					p++
1400				}
1401			}
1402
1403			function launchFullscreen(element) {
1404				RunPrefixMethod(element, 'RequestFullScreen')
1405			}
1406
1407			function cancelFullscreen() {
1408				if (RunPrefixMethod(document, 'FullScreen') || RunPrefixMethod(document, 'IsFullScreen')) {
1409					RunPrefixMethod(document, 'CancelFullScreen')
1410				}
1411			}
1412
1413			return this
1414		},
1415
1416		/**
1417		 * toggleLoops
1418		 * @returns {jQuery.mbYTPlayer}
1419		 */
1420		toggleLoops: function () {
1421			let YTPlayer = this.get(0);
1422			let data = YTPlayer.opt;
1423			if (data.loop == 1) {
1424				data.loop = 0
1425			} else {
1426				if (data.startAt) {
1427					YTPlayer.player.seekTo(data.startAt)
1428				} else {
1429					YTPlayer.player.playVideo()
1430				}
1431				data.loop = 1
1432			}
1433			return this
1434		},
1435
1436		/**
1437		 * play
1438		 * @returns {jQuery.mbYTPlayer}
1439		 */
1440		play: function () {
1441			let YTPlayer = this.get(0);
1442			let $YTPlayer = jQuery(YTPlayer);
1443
1444			if (!YTPlayer.isReady)
1445				return this;
1446
1447			setTimeout(function () {
1448				$YTPlayer.YTPSetAbundance(YTPlayer.opt.abundance)
1449			}, 300);
1450
1451			YTPlayer.player.playVideo();
1452
1453			jQuery(YTPlayer.playerEl).css({
1454				opacity: 1
1455			});
1456
1457			YTPlayer.wrapper.css({
1458				backgroundImage: 'none'
1459			});
1460
1461			YTPlayer.wrapper.CSSAnimate({
1462				opacity: YTPlayer.isAlone ? 1 : YTPlayer.opt.opacity
1463			}, YTPlayer.opt.fadeOnStartTime);
1464
1465			let controls = jQuery('#controlBar_' + YTPlayer.id);
1466			let playBtn = controls.find('.mb_YTPPlayPause');
1467			playBtn.html(jQuery.mbYTPlayer.controls.pause);
1468			YTPlayer.state = 1;
1469
1470			return this
1471		},
1472
1473		/**
1474		 * togglePlay
1475		 * @param callback
1476		 * @returns {jQuery.mbYTPlayer}
1477		 */
1478		togglePlay: function (callback) {
1479			let YTPlayer = this.get(0);
1480
1481			if (!YTPlayer.isReady)
1482				return this;
1483
1484			if (YTPlayer.state === 1)
1485				this.YTPPause();
1486			else
1487				this.YTPPlay();
1488
1489			if (typeof callback == 'function')
1490				callback(YTPlayer.state);
1491
1492			return this
1493		},
1494
1495		/**
1496		 * stop
1497		 * @returns {jQuery.mbYTPlayer}
1498		 */
1499		stop: function () {
1500			let YTPlayer = this.get(0);
1501
1502			if (!YTPlayer.isReady)
1503				return this;
1504
1505			let controls = jQuery('#controlBar_' + YTPlayer.id);
1506			let playBtn = controls.find('.mb_YTPPlayPause');
1507			playBtn.html(jQuery.mbYTPlayer.controls.play);
1508			YTPlayer.player.stopVideo();
1509			return this
1510		},
1511
1512		/**
1513		 * pause
1514		 * @returns {jQuery.mbYTPlayer}
1515		 */
1516		pause: function () {
1517			let YTPlayer = this.get(0);
1518
1519			if (!YTPlayer.isReady)
1520				return this;
1521
1522			if (YTPlayer.opt.abundance < .2)
1523				this.YTPSetAbundance(.2);
1524
1525			YTPlayer.player.pauseVideo();
1526			YTPlayer.state = 2;
1527			return this
1528		},
1529
1530		/**
1531		 * seekTo
1532		 * @param sec
1533		 * @returns {jQuery.mbYTPlayer}
1534		 */
1535		seekTo: function (sec) {
1536			let YTPlayer = this.get(0);
1537
1538			if (!YTPlayer.isReady)
1539				return this;
1540
1541			YTPlayer.player.seekTo(sec, true);
1542			return this
1543		},
1544
1545		/**
1546		 *
1547		 * @returns {*}
1548		 */
1549		getPlaybackRate: function () {
1550			let YTPlayer = this.get(0);
1551
1552			if (!YTPlayer.isReady)
1553				return this;
1554
1555			return YTPlayer.player.getPlaybackRate()
1556		},
1557
1558		/**
1559		 * setPlaybackRate
1560		 * @param val:Number
1561		 * 0.25, 0.5, 1, 1.5, 2
1562		 * @returns {jQuery.mbYTPlayer}
1563		 */
1564		setPlaybackRate: function (val) {
1565			let YTPlayer = this.get(0);
1566
1567			if (!YTPlayer.isReady)
1568				return this;
1569
1570			YTPlayer.player.setPlaybackRate(val);
1571			return this
1572		},
1573
1574		/**
1575		 * setVolume
1576		 * @param val
1577		 * @returns {jQuery.mbYTPlayer}
1578		 */
1579		setVolume: function (val) {
1580			let YTPlayer = this.get(0);
1581
1582			if (!YTPlayer.isReady)
1583				return this;
1584
1585			YTPlayer.opt.vol = val;
1586			this.YTPUnmute();
1587			YTPlayer.player.setVolume(YTPlayer.opt.vol);
1588
1589			if (YTPlayer.volumeBar && YTPlayer.volumeBar.length)
1590				YTPlayer.volumeBar.updateSliderVal(val);
1591
1592			return this
1593		},
1594		/**
1595		 * getVolume
1596		 * @returns {*}
1597		 */
1598		getVolume: function () {
1599			let YTPlayer = this.get(0);
1600
1601			if (!YTPlayer.isReady)
1602				return this;
1603
1604			return YTPlayer.player.getVolume()
1605		},
1606
1607		/**
1608		 * toggleVolume
1609		 * @returns {jQuery.mbYTPlayer}
1610		 */
1611		toggleVolume: function () {
1612
1613			let YTPlayer = this.get(0);
1614
1615			if (!YTPlayer.isReady)
1616				return this;
1617
1618			if (YTPlayer.isMute) {
1619				if (!jQuery.mbBrowser.mobile)
1620					this.YTPSetVolume(YTPlayer.opt.vol);
1621				this.YTPUnmute()
1622			} else {
1623				this.YTPMute()
1624			}
1625			return this
1626		},
1627
1628		/**
1629		 * mute
1630		 * @returns {jQuery.mbYTPlayer}
1631		 */
1632		mute: function () {
1633			let YTPlayer = this.get(0);
1634
1635			if (!YTPlayer.isReady)
1636				return this;
1637
1638			if (YTPlayer.isMute)
1639				return this;
1640			YTPlayer.player.mute();
1641			YTPlayer.isMute = true;
1642			YTPlayer.player.setVolume(0);
1643			if (YTPlayer.volumeBar && YTPlayer.volumeBar.length && YTPlayer.volumeBar.width() > 10) {
1644				YTPlayer.volumeBar.updateSliderVal(0)
1645			}
1646			let controls = jQuery('#controlBar_' + YTPlayer.id);
1647			let muteBtn = controls.find('.mb_YTPMuteUnmute');
1648			muteBtn.html(jQuery.mbYTPlayer.controls.unmute);
1649			jQuery(YTPlayer).addClass('isMuted');
1650			if (YTPlayer.volumeBar && YTPlayer.volumeBar.length) YTPlayer.volumeBar.addClass('muted');
1651			let YTPEvent = jQuery.Event('YTPMuted');
1652			YTPEvent.time = YTPlayer.currentTime;
1653
1654			if (!YTPlayer.preventTrigger)
1655				jQuery(YTPlayer).trigger(YTPEvent);
1656
1657			return this
1658		},
1659
1660		/**
1661		 * unmute
1662		 * @returns {jQuery.mbYTPlayer}
1663		 */
1664		unmute: function () {
1665			let YTPlayer = this.get(0);
1666
1667			if (!YTPlayer.isReady)
1668				return this;
1669
1670			if (!YTPlayer.isMute)
1671				return this;
1672
1673			YTPlayer.player.unMute();
1674			YTPlayer.isMute = false;
1675			jQuery(YTPlayer).YTPSetVolume(YTPlayer.opt.vol);
1676			if (YTPlayer.volumeBar && YTPlayer.volumeBar.length)
1677				YTPlayer.volumeBar.updateSliderVal(YTPlayer.opt.vol > 10 ? YTPlayer.opt.vol : 10);
1678			let controls = jQuery('#controlBar_' + YTPlayer.id);
1679			let muteBtn = controls.find('.mb_YTPMuteUnmute');
1680			muteBtn.html(jQuery.mbYTPlayer.controls.mute);
1681			jQuery(YTPlayer).removeClass('isMuted');
1682			if (YTPlayer.volumeBar && YTPlayer.volumeBar.length)
1683				YTPlayer.volumeBar.removeClass('muted');
1684			let YTPEvent = jQuery.Event('YTPUnmuted');
1685			YTPEvent.time = YTPlayer.currentTime;
1686
1687			if (!YTPlayer.preventTrigger)
1688				jQuery(YTPlayer).trigger(YTPEvent);
1689
1690			return this
1691		},
1692
1693		/* FILTERS ---------------------------------------------------------------------------------------------------------*/
1694
1695		/**
1696		 * applyFilter
1697		 * @param filter
1698		 * @param value
1699		 * @returns {jQuery.mbYTPlayer}
1700		 */
1701		applyFilter: function (filter, value) {
1702			let $YTPlayer = this;
1703			let YTPlayer = $YTPlayer.get(0);
1704
1705			if (!YTPlayer.isReady)
1706				return this;
1707
1708			YTPlayer.filters[filter].value = value;
1709			if (YTPlayer.filtersEnabled)
1710				$YTPlayer.YTPEnableFilters()
1711		},
1712
1713		/**
1714		 * applyFilters
1715		 * @param filters
1716		 * @returns {jQuery.mbYTPlayer}
1717		 */
1718		applyFilters: function (filters) {
1719			let $YTPlayer = this;
1720			let YTPlayer = $YTPlayer.get(0);
1721
1722			if (!YTPlayer.isReady) {
1723				jQuery(YTPlayer).on('YTPReady', function () {
1724					$YTPlayer.YTPApplyFilters(filters)
1725				});
1726				return this
1727			}
1728
1729			for (let key in filters) {
1730				$YTPlayer.YTPApplyFilter(key, filters[key])
1731			}
1732
1733			$YTPlayer.trigger('YTPFiltersApplied')
1734		},
1735
1736		/**
1737		 * toggleFilter
1738		 * @param filter
1739		 * @param value
1740		 * @returns {jQuery.mbYTPlayer}
1741		 */
1742		toggleFilter: function (filter, value) {
1743			let $YTPlayer = this;
1744			let YTPlayer = $YTPlayer.get(0);
1745
1746			if (!YTPlayer.isReady)
1747				return this;
1748
1749			if (!YTPlayer.filters[filter].value)
1750				YTPlayer.filters[filter].value = value;
1751			else
1752				YTPlayer.filters[filter].value = 0;
1753
1754			if (YTPlayer.filtersEnabled)
1755				jQuery(YTPlayer).YTPEnableFilters();
1756
1757			return this
1758		},
1759
1760		/**
1761		 * toggleFilters
1762		 * @param callback
1763		 * @returns {jQuery.mbYTPlayer}
1764		 */
1765		toggleFilters: function (callback) {
1766			let $YTPlayer = this;
1767			let YTPlayer = $YTPlayer.get(0);
1768
1769			if (!YTPlayer.isReady)
1770				return this;
1771
1772			if (YTPlayer.filtersEnabled) {
1773				jQuery(YTPlayer).trigger('YTPDisableFilters');
1774				jQuery(YTPlayer).YTPDisableFilters()
1775			} else {
1776				jQuery(YTPlayer).YTPEnableFilters();
1777				jQuery(YTPlayer).trigger('YTPEnableFilters')
1778			}
1779			if (typeof callback == 'function')
1780				callback(YTPlayer.filtersEnabled);
1781
1782			return this
1783		},
1784
1785		/**
1786		 * disableFilters
1787		 * @returns {jQuery.mbYTPlayer}
1788		 */
1789		disableFilters: function () {
1790			let $YTPlayer = this;
1791			let YTPlayer = $YTPlayer.get(0);
1792
1793			if (!YTPlayer.isReady)
1794				return this;
1795
1796			let iframe = jQuery(YTPlayer.playerEl);
1797			iframe.css('-webkit-filter', '');
1798			iframe.css('filter', '');
1799			YTPlayer.filtersEnabled = false;
1800
1801			return this
1802		},
1803
1804		/**
1805		 * enableFilters
1806		 * @returns {jQuery.mbYTPlayer}
1807		 */
1808		enableFilters: function () {
1809			let $YTPlayer = this;
1810			let YTPlayer = $YTPlayer.get(0);
1811
1812			if (!YTPlayer.isReady)
1813				return this;
1814
1815			let iframe = jQuery(YTPlayer.playerEl);
1816			let filterStyle = '';
1817			for (let key in YTPlayer.filters) {
1818				if (YTPlayer.filters[key].value)
1819					filterStyle += key.replace('_', '-') + '(' + YTPlayer.filters[key].value + YTPlayer.filters[key].unit + ') '
1820			}
1821			iframe.css('-webkit-filter', filterStyle);
1822			iframe.css('filter', filterStyle);
1823			YTPlayer.filtersEnabled = true;
1824
1825			return this
1826		},
1827
1828		/**
1829		 * removeFilter
1830		 * @param filter
1831		 * @param callback
1832		 * @returns {jQuery.mbYTPlayer}
1833		 */
1834		removeFilter: function (filter, callback) {
1835			let $YTPlayer = this;
1836			let YTPlayer = $YTPlayer.get(0);
1837
1838			if (!YTPlayer.isReady)
1839				return this;
1840
1841			if (typeof filter == 'function') {
1842				callback = filter;
1843				filter = null
1844			}
1845
1846			if (!filter) {
1847				for (let key in YTPlayer.filters) {
1848					if (YTPlayer.filters.hasOwnProperty(key)) {
1849						$YTPlayer.YTPApplyFilter(key, 0);
1850						if (typeof callback == 'function')
1851							callback(key);
1852					}
1853				}
1854
1855				YTPlayer.filters = jQuery.extend(true, {}, jQuery.mbYTPlayer.defaultFilters)
1856
1857			} else {
1858				$YTPlayer.YTPApplyFilter(filter, 0);
1859				if (typeof callback == 'function') callback(filter)
1860			}
1861
1862			let YTPEvent = jQuery.Event('YTPFiltersApplied');
1863			$YTPlayer.trigger(YTPEvent);
1864
1865			return this
1866		},
1867
1868		/**
1869		 * getFilters
1870		 * @returns {filters}
1871		 */
1872		getFilters: function () {
1873			let YTPlayer = this.get(0);
1874
1875			if (!YTPlayer.isReady)
1876				return this;
1877
1878			return YTPlayer.filters
1879		},
1880
1881		/* MASK ---------------------------------------------------------------------------------------------------------*/
1882
1883		/**
1884		 * addMask
1885		 * @param mask
1886		 * @returns {jQuery.mbYTPlayer}
1887		 */
1888		addMask: function (mask) {
1889			let YTPlayer = this.get(0);
1890
1891			if (!mask)
1892				mask = YTPlayer.actualMask;
1893
1894			let tempImg = jQuery('<img/>').attr('src', mask).on('load', function () {
1895				YTPlayer.overlay.CSSAnimate({
1896					opacity: 0
1897				}, YTPlayer.opt.fadeOnStartTime, function () {
1898					YTPlayer.hasMask = true;
1899					tempImg.remove();
1900					YTPlayer.overlay.css({
1901						backgroundImage   : 'url(' + mask + ')',
1902						backgroundRepeat  : 'no-repeat',
1903						backgroundPosition: 'center center',
1904						backgroundSize    : 'cover'
1905					});
1906					YTPlayer.overlay.CSSAnimate({
1907						opacity: 1
1908					}, YTPlayer.opt.fadeOnStartTime)
1909				})
1910			});
1911
1912			return this
1913		},
1914
1915		/**
1916		 * removeMask
1917		 * @returns {jQuery.mbYTPlayer}
1918		 */
1919		removeMask: function () {
1920			let YTPlayer = this.get(0);
1921
1922			YTPlayer.overlay.CSSAnimate({
1923				opacity: 0
1924			}, YTPlayer.opt.fadeOnStartTime, function () {
1925				YTPlayer.hasMask = false;
1926				YTPlayer.overlay.css({
1927					backgroundImage   : '',
1928					backgroundRepeat  : '',
1929					backgroundPosition: '',
1930					backgroundSize    : ''
1931				});
1932				YTPlayer.overlay.CSSAnimate({
1933					opacity: 1
1934				}, YTPlayer.opt.fadeOnStartTime)
1935			});
1936
1937			return this
1938		},
1939
1940		/**
1941		 * Apply mask
1942		 * @param YTPlayer
1943		 */
1944		applyMask: function (YTPlayer) {
1945			let $YTPlayer = jQuery(YTPlayer);
1946
1947			$YTPlayer.off('YTPTime.mask');
1948
1949			if (YTPlayer.opt.mask) {
1950				if (typeof YTPlayer.opt.mask == 'string') {
1951
1952					$YTPlayer.YTPAddMask(YTPlayer.opt.mask);
1953					YTPlayer.actualMask = YTPlayer.opt.mask
1954
1955				} else if (typeof YTPlayer.opt.mask == 'object') {
1956
1957					for (let time in YTPlayer.opt.mask) {
1958
1959						if (YTPlayer.opt.mask[time])
1960							img = jQuery('<img/>').attr('src', YTPlayer.opt.mask[time])
1961					}
1962
1963					if (YTPlayer.opt.mask[0])
1964						$YTPlayer.YTPAddMask(YTPlayer.opt.mask[0]);
1965
1966					$YTPlayer.on('YTPTime.mask', function (e) {
1967
1968						for (let time in YTPlayer.opt.mask) {
1969							if (e.time === time)
1970								if (!YTPlayer.opt.mask[time]) {
1971									$YTPlayer.YTPRemoveMask()
1972								} else {
1973									$YTPlayer.YTPAddMask(YTPlayer.opt.mask[time]);
1974									YTPlayer.actualMask = YTPlayer.opt.mask[time]
1975								}
1976						}
1977					})
1978				}
1979			}
1980		},
1981
1982		/**
1983		 * toggleMask
1984		 * @returns {jQuery.mbYTPlayer}
1985		 */
1986		toggleMask: function () {
1987			let YTPlayer = this.get(0);
1988
1989			let $YTPlayer = jQuery(YTPlayer);
1990			if (YTPlayer.hasMask)
1991				$YTPlayer.YTPRemoveMask();
1992			else
1993				$YTPlayer.YTPAddMask();
1994			return this
1995		},
1996
1997		/* CONTROLS --------------------------------------------------------------------------------------------------------*/
1998
1999		/**
2000		 * manageProgress
2001		 * @returns {{totalTime: number, currentTime: number}}
2002		 */
2003		manageProgress: function () {
2004			let YTPlayer = this.get(0);
2005			let controls = jQuery('#controlBar_' + YTPlayer.id);
2006			let progressBar = controls.find('.mb_YTPProgress');
2007			let loadedBar = controls.find('.mb_YTPLoaded');
2008			let timeBar = controls.find('.mb_YTPseekbar');
2009			let totW = progressBar.outerWidth();
2010			let currentTime = Math.floor(YTPlayer.player.getCurrentTime());
2011			let totalTime = Math.floor(YTPlayer.player.getDuration());
2012			let timeW = (currentTime * totW) / totalTime;
2013			let startLeft = 0;
2014			let loadedW = YTPlayer.player.getVideoLoadedFraction() * 100;
2015			loadedBar.css({
2016				left : startLeft,
2017				width: loadedW + '%'
2018			});
2019			timeBar.css({
2020				left : 0,
2021				width: timeW
2022			});
2023			return {
2024				totalTime  : totalTime,
2025				currentTime: currentTime
2026			}
2027		},
2028
2029		/**
2030		 * buildControls
2031		 * @param YTPlayer
2032		 */
2033		buildControls: function (YTPlayer) {
2034
2035			jQuery('#controlBar_' + YTPlayer.id).remove();
2036			if (!YTPlayer.opt.showControls) {
2037				YTPlayer.controlBar = false;
2038				return
2039			}
2040
2041			YTPlayer.opt.showYTLogo = YTPlayer.opt.showYTLogo || YTPlayer.opt.printUrl;
2042			if (jQuery('#controlBar_' + YTPlayer.id).length)
2043				return;
2044			YTPlayer.controlBar = jQuery('<div/>').attr('id', 'controlBar_' + YTPlayer.id).addClass('mb_YTPBar').css({
2045				whiteSpace: 'noWrap',
2046				position  : YTPlayer.isBackground ? 'fixed' : 'absolute',
2047				zIndex    : YTPlayer.isBackground ? 10000 : 1000
2048			}).hide().on('click', function (e) {
2049				e.stopPropagation()
2050			});
2051			let buttonBar = jQuery('<div/>').addClass('buttonBar');
2052			/**
2053			 *  play/pause button
2054			 * */
2055			let playpause = jQuery('<span>' + jQuery.mbYTPlayer.controls.play + '</span>').addClass('mb_YTPPlayPause ytpicon').on('click', function (e) {
2056				e.stopPropagation();
2057				jQuery(YTPlayer).YTPTogglePlay()
2058			});
2059			/**
2060			 *  mute/unmute button
2061			 * */
2062			let MuteUnmute = jQuery('<span>' + jQuery.mbYTPlayer.controls.mute + '</span>').addClass('mb_YTPMuteUnmute ytpicon').on('click', function (e) {
2063				e.stopPropagation();
2064				jQuery(YTPlayer).YTPToggleVolume()
2065			});
2066			/**
2067			 *  volume bar
2068			 * */
2069			let volumeBar = jQuery('<div/>').addClass('mb_YTPVolumeBar').css({
2070				display: 'inline-block'
2071			});
2072			YTPlayer.volumeBar = volumeBar;
2073
2074			/**
2075			 * time elapsed
2076			 * */
2077			let idx = jQuery('<span/>').addClass('mb_YTPTime');
2078			let vURL = YTPlayer.opt.videoURL ? YTPlayer.opt.videoURL : '';
2079			if (vURL.indexOf('http') < 0) vURL = 'https://www.youtube.com/watch?v=' + YTPlayer.opt.videoURL;
2080			let movieUrl = jQuery('<span/>').html(jQuery.mbYTPlayer.controls.ytLogo).addClass('mb_YTPUrl ytpicon').attr('title', 'view on YouTube').on('click', function () {
2081				window.open(vURL, 'viewOnYT')
2082			});
2083			let onlyVideo = jQuery('<span/>').html(jQuery.mbYTPlayer.controls.onlyYT).addClass('mb_OnlyYT ytpicon').on('click', function (e) {
2084				e.stopPropagation();
2085				jQuery(YTPlayer).YTPFullscreen(YTPlayer.opt.realFullscreen)
2086			});
2087			let progressBar = jQuery('<div/>').addClass('mb_YTPProgress').css('position', 'absolute').on('click', function (e) {
2088				e.stopPropagation();
2089				timeBar.css({
2090					width: (e.clientX - timeBar.offset().left)
2091				});
2092				YTPlayer.timeW = e.clientX - timeBar.offset().left;
2093				YTPlayer.controlBar.find('.mb_YTPLoaded').css({
2094					width: 0
2095				});
2096				let totalTime = Math.floor(YTPlayer.player.getDuration());
2097				YTPlayer.goto = (timeBar.outerWidth() * totalTime) / progressBar.outerWidth();
2098				YTPlayer.player.seekTo(parseFloat(YTPlayer.goto), true);
2099				YTPlayer.controlBar.find('.mb_YTPLoaded').css({
2100					width: 0
2101				})
2102			});
2103			let loadedBar = jQuery('<div/>').addClass('mb_YTPLoaded').css('position', 'absolute');
2104			let timeBar = jQuery('<div/>').addClass('mb_YTPseekbar').css('position', 'absolute');
2105			progressBar.append(loadedBar).append(timeBar);
2106			buttonBar.append(playpause).append(MuteUnmute).append(volumeBar).append(idx);
2107
2108			if (YTPlayer.opt.showYTLogo) {
2109				buttonBar.append(movieUrl)
2110			}
2111
2112			/**
2113			 * Full screen button
2114			 */
2115			if (YTPlayer.isBackground || (eval(YTPlayer.opt.realFullscreen) && !YTPlayer.isBackground))
2116				buttonBar.append(onlyVideo);
2117
2118			YTPlayer.controlBar.append(buttonBar).append(progressBar);
2119
2120			if (!YTPlayer.isBackground) {
2121				YTPlayer.controlBar.addClass('inlinePlayer');
2122				YTPlayer.wrapper.before(YTPlayer.controlBar)
2123			} else {
2124				jQuery('body').after(YTPlayer.controlBar)
2125			}
2126
2127			/**
2128			 * Volume slider
2129			 */
2130			volumeBar.simpleSlider({
2131				initialval : YTPlayer.opt.vol,
2132				scale      : 100,
2133				orientation: 'h',
2134				callback   : function (el) {
2135
2136					if (el.value == 0) {
2137						jQuery(YTPlayer).YTPMute()
2138					} else {
2139						jQuery(YTPlayer).YTPUnmute()
2140					}
2141					YTPlayer.player.setVolume(el.value);
2142					if (!YTPlayer.isMute)
2143						YTPlayer.opt.vol = el.value
2144				}
2145
2146			})
2147		},
2148
2149		/**
2150		 * changeCoverImage
2151		 *
2152		 * @param imageURL
2153		 * @returns {jQuery.mbYTPlayer}
2154		 */
2155		changeCoverImage: function (imageURL) {
2156			let YTPlayer = this.get(0);
2157			if (YTPlayer.opt.coverImage || YTPlayer.orig_containment_background) {
2158				let bgndURL = imageURL || (YTPlayer.opt.coverImage ? 'url(' + YTPlayer.opt.coverImage + ') center center' : YTPlayer.orig_containment_background);
2159				if (bgndURL)
2160					YTPlayer.opt.containment.css({
2161						background          : bgndURL,
2162						backgroundSize      : 'cover',
2163						backgroundRepeat    : 'no-repeat',
2164						backgroundAttachment: 'fixed'
2165					})
2166			}
2167			return this;
2168		},
2169
2170		/* MANAGE PLAYER STATE ------------------------------------------------------------------------------------------*/
2171
2172		/**
2173		 * checkForState
2174		 */
2175		checkForState: function () {
2176			let YTPlayer = this.get(0);
2177			let $YTPlayer = jQuery(YTPlayer);
2178
2179			clearInterval(YTPlayer.getState);
2180			let interval = 100;
2181			//Checking if player has been removed from the scene
2182			if (!jQuery.contains(document, YTPlayer)) {
2183				$YTPlayer.YTPPlayerDestroy();
2184				clearInterval(YTPlayer.getState);
2185				clearInterval(YTPlayer.checkForStartAt);
2186				return
2187			}
2188
2189			jQuery.mbYTPlayer.checkForStart(YTPlayer);
2190
2191			YTPlayer.getState = setInterval(function () {
2192				let $YTPlayer = jQuery(YTPlayer);
2193
2194				if (!YTPlayer.isReady)
2195					return;
2196
2197				let prog = jQuery(YTPlayer).YTPManageProgress();
2198
2199				let stopAt = YTPlayer.opt.stopAt > YTPlayer.opt.startAt ? YTPlayer.opt.stopAt : 0;
2200				stopAt = stopAt < YTPlayer.player.getDuration() ? stopAt : 0;
2201
2202				if (YTPlayer.currentTime != prog.currentTime) {
2203					let YTPEvent = jQuery.Event('YTPTime');
2204					YTPEvent.time = YTPlayer.currentTime;
2205					jQuery(YTPlayer).trigger(YTPEvent)
2206				}
2207
2208				YTPlayer.currentTime = prog.currentTime;
2209				YTPlayer.totalTime = YTPlayer.player.getDuration();
2210				if (YTPlayer.player.getVolume() == 0) $YTPlayer.addClass('isMuted');
2211				else $YTPlayer.removeClass('isMuted');
2212
2213				if (YTPlayer.opt.showControls)
2214					if (prog.totalTime) {
2215						YTPlayer.controlBar.find('.mb_YTPTime').html(jQuery.mbYTPlayer.formatTime(prog.currentTime) + ' / ' + jQuery.mbYTPlayer.formatTime(prog.totalTime))
2216					} else {
2217						YTPlayer.controlBar.find('.mb_YTPTime').html('-- : -- / -- : --')
2218					}
2219
2220				/**
2221				 * Manage video pause on window blur
2222				 */
2223				if (eval(YTPlayer.opt.stopMovieOnBlur)) {
2224					if (!document.hasFocus()) {
2225						if (YTPlayer.state == 1) {
2226							YTPlayer.hasFocus = false;
2227							YTPlayer.preventTrigger = true;
2228							$YTPlayer.YTPPause()
2229						}
2230					} else if (document.hasFocus() && !YTPlayer.hasFocus && !(YTPlayer.state == -1 || YTPlayer.state == 0)) {
2231						YTPlayer.hasFocus = true;
2232						YTPlayer.preventTrigger = true;
2233						$YTPlayer.YTPPlay()
2234					}
2235				}
2236
2237				/**
2238				 * Manage video pause if not on screen
2239				 */
2240				if (YTPlayer.opt.playOnlyIfVisible) {
2241					let isOnScreen = jQuery.mbYTPlayer.isOnScreen(YTPlayer, YTPlayer.opt.onScreenPercentage);
2242					if (!isOnScreen && YTPlayer.state == 1) {
2243						YTPlayer.isOnScreen = false;
2244						$YTPlayer.YTPPause()
2245					} else if (isOnScreen && !YTPlayer.isOnScreen) {
2246						YTPlayer.isOnScreen = true;
2247						YTPlayer.player.playVideo()
2248					}
2249				}
2250
2251				if (YTPlayer.controlBar.length && YTPlayer.controlBar.outerWidth() <= 400 && !YTPlayer.isCompact) {
2252					YTPlayer.controlBar.addClass('compact');
2253					YTPlayer.isCompact = true;
2254					if (!YTPlayer.isMute && YTPlayer.volumeBar) YTPlayer.volumeBar.updateSliderVal(YTPlayer.opt.vol)
2255				} else if (YTPlayer.controlBar.length && YTPlayer.controlBar.outerWidth() > 400 && YTPlayer.isCompact) {
2256					YTPlayer.controlBar.removeClass('compact');
2257					YTPlayer.isCompact = false;
2258
2259					if (!YTPlayer.isMute && YTPlayer.volumeBar)
2260						YTPlayer.volumeBar.updateSliderVal(YTPlayer.opt.vol)
2261				}
2262				// the video is ended
2263				if (YTPlayer.player.getPlayerState() > 0 && ((parseFloat(YTPlayer.player.getDuration() - (YTPlayer.opt.fadeOnStartTime / 1000)) < YTPlayer.player.getCurrentTime()) || (stopAt > 0 && parseFloat(YTPlayer.player.getCurrentTime()) >= stopAt))) {
2264
2265					if (YTPlayer.isEnded)
2266						return;
2267
2268					YTPlayer.isEnded = true;
2269
2270					setTimeout(function () {
2271						YTPlayer.isEnded = false
2272					}, 1000);
2273
2274					if (YTPlayer.isList) {
2275						if (!YTPlayer.opt.loop || (YTPlayer.opt.loop > 0 && YTPlayer.player.loopTime === YTPlayer.opt.loop - 1)) {
2276							YTPlayer.player.loopTime = undefined;
2277							clearInterval(YTPlayer.getState);
2278							let YTPEnd = jQuery.Event('YTPEnd');
2279							YTPEnd.time = YTPlayer.currentTime;
2280							jQuery(YTPlayer).trigger(YTPEnd);
2281							return
2282						}
2283					} else if (!YTPlayer.opt.loop || (YTPlayer.opt.loop > 0 && YTPlayer.player.loopTime === YTPlayer.opt.loop - 1)) {
2284						YTPlayer.player.loopTime = undefined;
2285
2286						YTPlayer.state = 2;
2287
2288						$YTPlayer.changeCoverImage(YTPlayer);
2289
2290						jQuery(YTPlayer).YTPPause();
2291						YTPlayer.wrapper.CSSAnimate({
2292							opacity: 0
2293						}, YTPlayer.opt.fadeOnStartTime, function () {
2294
2295							if (YTPlayer.controlBar.length)
2296								YTPlayer.controlBar.find('.mb_YTPPlayPause').html(jQuery.mbYTPlayer.controls.play);
2297
2298							$YTPlayer.changeCoverImage();
2299
2300							let YTPEnd = jQuery.Event('YTPEnd');
2301							YTPEnd.time = YTPlayer.currentTime;
2302							jQuery(YTPlayer).trigger(YTPEnd);
2303							YTPlayer.player.seekTo(YTPlayer.opt.startAt, true);
2304						});
2305						return
2306					}
2307
2308					YTPlayer.player.loopTime = YTPlayer.player.loopTime ? ++YTPlayer.player.loopTime : 1;
2309					YTPlayer.opt.startAt = YTPlayer.opt.startAt || 1;
2310					YTPlayer.preventTrigger = true;
2311					YTPlayer.state = 2;
2312					YTPlayer.player.seekTo(YTPlayer.opt.startAt, true)
2313				}
2314			}, interval)
2315		},
2316
2317		/**
2318		 * checkForStart
2319		 * @param YTPlayer
2320		 */
2321		checkForStart: function (YTPlayer) {
2322			let $YTPlayer = jQuery(YTPlayer);
2323
2324			/* If the player has been removed from scene destroy it */
2325			if (!jQuery.contains(document, YTPlayer)) {
2326				$YTPlayer.YTPPlayerDestroy();
2327				return
2328			}
2329
2330			/* CREATE CONTROL BAR */
2331			jQuery.mbYTPlayer.buildControls(YTPlayer);
2332
2333			if (YTPlayer.overlay)
2334				if (YTPlayer.opt.addRaster) {
2335					let classN = YTPlayer.opt.addRaster == 'dot' ? 'raster-dot' : 'raster';
2336					YTPlayer.overlay.addClass(YTPlayer.isRetina ? classN + ' retina' : classN)
2337				} else {
2338					YTPlayer.overlay.removeClass(function (index, classNames) {
2339						// change the list into an array
2340						let current_classes = classNames.split(' '),
2341								// array of classes which are to be removed
2342								classes_to_remove = [];
2343						jQuery.each(current_classes, function (index, class_name) {
2344							// if the classname begins with bg add it to the classes_to_remove array
2345							if (/raster.*/.test(class_name)) {
2346								classes_to_remove.push(class_name)
2347							}
2348						});
2349						classes_to_remove.push('retina');
2350						// turn the array back into a string
2351						return classes_to_remove.join(' ')
2352					})
2353				}
2354
2355			YTPlayer.preventTrigger = true;
2356			YTPlayer.state = 2;
2357			YTPlayer.preventTrigger = true;
2358
2359			YTPlayer.player.mute();
2360			YTPlayer.player.playVideo();
2361			YTPlayer.isStarting = true;
2362
2363			let startAt = YTPlayer.start_from_last ? YTPlayer.start_from_last : YTPlayer.opt.startAt ? YTPlayer.opt.startAt : 1;
2364
2365			YTPlayer.preventTrigger = true;
2366			YTPlayer.checkForStartAt = setInterval(function () {
2367
2368				YTPlayer.player.mute();
2369				YTPlayer.player.seekTo(startAt, true);
2370
2371				let canPlayVideo = YTPlayer.player.getVideoLoadedFraction() >= startAt / YTPlayer.player.getDuration();
2372
2373				if (jQuery.mbBrowser.mobile)
2374					canPlayVideo = true;
2375
2376				if (YTPlayer.player.getDuration() > 0 && YTPlayer.player.getCurrentTime() >= startAt && canPlayVideo) {
2377					YTPlayer.start_from_last = null;
2378
2379					YTPlayer.preventTrigger = true;
2380					$YTPlayer.YTPPause();
2381
2382					clearInterval(YTPlayer.checkForStartAt);
2383
2384					if (typeof YTPlayer.opt.onReady == 'function')
2385						YTPlayer.opt.onReady(YTPlayer);
2386
2387					YTPlayer.isReady = true;
2388
2389					$YTPlayer.YTPRemoveFilter();
2390
2391					if (YTPlayer.opt.addFilters) {
2392						$YTPlayer.YTPApplyFilters(YTPlayer.opt.addFilters)
2393					} else {
2394						$YTPlayer.YTPApplyFilters()
2395					}
2396					$YTPlayer.YTPEnableFilters();
2397					let YTPready = jQuery.Event('YTPReady');
2398					YTPready.time = YTPlayer.currentTime;
2399					$YTPlayer.trigger(YTPready);
2400
2401					YTPlayer.state = 2;
2402
2403					if (!YTPlayer.opt.mute) {
2404
2405						if (YTPlayer.opt.autoPlay) {
2406							console.debug('We muted the audio to make the video \'auto-play\' according with the latest vendor policy. ' +
2407									'The audio will unmute at the first user interaction with the page');
2408							YTPlayer.player.mute();
2409							YTPlayer.forcedMuted = true;
2410							/**
2411							 * If autoPlay is set to true and mute is set to false
2412							 * Browsers will not auto-play
2413							 * Start playing audio after the first click
2414							 */
2415							jQuery(document).on('mousedown.YTPstartAudio', function () {
2416								if (YTPlayer.forcedMuted) {
2417									console.debug("AAAAAAA");
2418									YTPlayer.player.unMute();
2419									YTPlayer.forcedMuted = false;
2420									jQuery(document).off('mousedown.YTPstartAudio')
2421								}
2422							});
2423
2424							jQuery(window).on("scroll", function () {
2425								console.debug("AAAAA")
2426							})
2427
2428						} else {
2429							YTPlayer.player.unMute()
2430						}
2431
2432					} else {
2433						$YTPlayer.YTPMute()
2434					}
2435
2436					if (typeof _gaq != 'undefined' && eval(YTPlayer.opt.gaTrack))
2437						_gaq.push(['_trackEvent', 'YTPlayer', 'Play', (YTPlayer.hasData ? YTPlayer.videoData.title : YTPlayer.videoID.toString())]);
2438					else if (typeof ga != 'undefined' && eval(YTPlayer.opt.gaTrack))
2439						ga('send', 'event', 'YTPlayer', 'play', (YTPlayer.hasData ? YTPlayer.videoData.title : YTPlayer.videoID.toString()));
2440
2441					if (YTPlayer.opt.autoPlay) {
2442
2443						let YTPStart = jQuery.Event('YTPStart');
2444						YTPStart.time = YTPlayer.currentTime;
2445						jQuery(YTPlayer).trigger(YTPStart);
2446
2447						YTPlayer.isStarting = false;
2448
2449						/* Fix for Safari freeze */
2450						if (jQuery.mbBrowser.os.name === 'mac' && jQuery.mbBrowser.safari) {
2451							jQuery('body').one('mousedown.YTPstart', function () {
2452								$YTPlayer.YTPPlay()
2453							})
2454						}
2455						$YTPlayer.YTPPlay();
2456						console.timeEnd(YTPTimerLabels.startPlaying)
2457					} else {
2458						YTPlayer.preventTrigger = true;
2459						$YTPlayer.YTPPause();
2460
2461						if (YTPlayer.start_from_last)
2462							YTPlayer.player.seekTo(startAt, true);
2463
2464						setTimeout(function () {
2465							YTPlayer.preventTrigger = true;
2466							$YTPlayer.YTPPause();
2467
2468							if (!YTPlayer.isPlayer) {
2469								if (!YTPlayer.opt.coverImage) {
2470									jQuery(YTPlayer.playerEl).CSSAnimate({
2471										opacity: 1
2472									}, YTPlayer.opt.fadeOnStartTime);
2473									YTPlayer.wrapper.CSSAnimate({
2474										opacity: YTPlayer.isAlone ? 1 : YTPlayer.opt.opacity
2475									}, YTPlayer.opt.fadeOnStartTime)
2476								} else {
2477									YTPlayer.wrapper.css({opacity: 0});
2478									setTimeout(function () {
2479										$YTPlayer.changeCoverImage()
2480									}, YTPlayer.opt.fadeOnStartTime)
2481								}
2482							}
2483							YTPlayer.isStarting = false
2484						}, 500);
2485
2486						if (YTPlayer.controlBar.length)
2487							YTPlayer.controlBar.find('.mb_YTPPlayPause').html(jQuery.mbYTPlayer.controls.play)
2488					}
2489
2490					if (YTPlayer.isPlayer && !YTPlayer.opt.autoPlay && (YTPlayer.loading && YTPlayer.loading.length)) {
2491						YTPlayer.loading.html('Ready');
2492						setTimeout(function () {
2493							YTPlayer.loading.fadeOut()
2494						}, 100)
2495					}
2496
2497					if (YTPlayer.controlBar && YTPlayer.controlBar.length)
2498						YTPlayer.controlBar.slideDown(1000)
2499				}
2500
2501				if (jQuery.mbBrowser.os.name === 'mac' && jQuery.mbBrowser.safari) {
2502					YTPlayer.player.playVideo();
2503					if (startAt >= 0)
2504						YTPlayer.player.seekTo(startAt, true)
2505				}
2506
2507			}, 100);
2508
2509			return $YTPlayer
2510		},
2511
2512		/* TIME METHODS -------------------------------------------------------------------------------------------*/
2513
2514		/**
2515		 * getTime
2516		 * @returns {string} time
2517		 */
2518		getTime: function () {
2519			let YTPlayer = this.get(0);
2520			return jQuery.mbYTPlayer.formatTime(YTPlayer.currentTime)
2521		},
2522
2523		/**
2524		 * getTotalTime
2525		 * @returns {string} total time
2526		 */
2527		getTotalTime: function () {
2528			let YTPlayer = this.get(0);
2529			return jQuery.mbYTPlayer.formatTime(YTPlayer.totalTime)
2530		},
2531
2532		/**
2533		 * formatTime
2534		 * @param s
2535		 * @returns {string}
2536		 */
2537		formatTime: function (s) {
2538			let min = Math.floor(s / 60);
2539			let sec = Math.floor(s - (60 * min));
2540			return (min <= 9 ? '0' + min : min) + ' : ' + (sec <= 9 ? '0' + sec : sec)
2541		},
2542
2543		/* PLAYER POSITION AND SIZE OPTIMIZATION-------------------------------------------------------------------------------------------*/
2544
2545		/**
2546		 * setAnchor
2547		 * @param anchor
2548		 */
2549		setAnchor: function (anchor) {
2550			let $YTplayer = this;
2551			$YTplayer.optimizeDisplay(anchor)
2552		},
2553
2554		/**
2555		 * getAnchor
2556		 */
2557		getAnchor: function () {
2558			let YTPlayer = this.get(0);
2559			return YTPlayer.opt.anchor
2560		},
2561
2562		/**
2563		 * setAbundance
2564		 * @param val
2565		 * @param updateOptions
2566		 * @returns {jQuery.mbYTPlayer}
2567		 */
2568		setAbundance: function (val, updateOptions) {
2569			let YTPlayer = this.get(0);
2570			let $YTPlayer = this;
2571			if (updateOptions)
2572				YTPlayer.opt.abundance = val;
2573			$YTPlayer.optimizeDisplay(YTPlayer.opt.anchor, val);
2574			return $YTPlayer
2575		},
2576
2577		/**
2578		 * getAbundance
2579		 * @returns {*}
2580		 */
2581		getAbundance: function () {
2582			let YTPlayer = this.get(0);
2583			return YTPlayer.opt.abundance
2584		},
2585
2586		/**
2587		 * setOption
2588		 * @param opt
2589		 * @param val
2590		 * @returns {jQuery.mbYTPlayer}
2591		 */
2592		setOption: function (opt, val) {
2593			let YTPlayer = this.get(0);
2594			let $YTPlayer = this;
2595			YTPlayer.opt[opt] = val;
2596			return $YTPlayer
2597		}
2598	};
2599
2600	/**
2601	 * optimizeDisplay
2602	 * @param anchor
2603	 * @param abundanceX
2604	 */
2605	jQuery.fn.optimizeDisplay = function (anchor, abundanceX) {
2606
2607		let YTPlayer = this.get(0);
2608		let vid = {};
2609		let el = YTPlayer.wrapper;
2610		let iframe = jQuery(YTPlayer.playerEl);
2611
2612		YTPlayer.opt.anchor = anchor || YTPlayer.opt.anchor;
2613
2614		// console.debug(YTPlayer.opt.anchor);
2615
2616		YTPlayer.opt.anchor = typeof YTPlayer.opt.anchor != 'undefined ' ? YTPlayer.opt.anchor : 'center,center';
2617		let YTPAlign = YTPlayer.opt.anchor.split(',');
2618		let ab = abundanceX ? abundanceX : YTPlayer.opt.abundance;
2619
2620		if (YTPlayer.opt.optimizeDisplay) {
2621			let abundance = el.height() * ab;
2622			let win = {};
2623			win.width = el.outerWidth();
2624			win.height = el.outerHeight() + abundance;
2625
2626			YTPlayer.opt.ratio = YTPlayer.opt.ratio === 'auto' ? 16 / 9 : YTPlayer.opt.ratio;
2627			YTPlayer.opt.ratio = eval(YTPlayer.opt.ratio);
2628
2629			vid.width = win.width + abundance;
2630			vid.height = Math.ceil(vid.width / YTPlayer.opt.ratio);
2631			vid.marginTop = Math.ceil(-((vid.height - win.height + abundance) / 2));
2632			vid.marginLeft = -(abundance / 2);
2633			let lowest = vid.height < win.height;
2634
2635			if (lowest) {
2636				vid.height = win.height + abundance;
2637				vid.width = Math.ceil(vid.height * YTPlayer.opt.ratio);
2638				vid.marginTop = -(abundance / 2);
2639				vid.marginLeft = Math.ceil(-((vid.width - win.width) / 2))
2640			}
2641
2642			for (let a in YTPAlign) {
2643				if (YTPAlign.hasOwnProperty(a)) {
2644					let al = YTPAlign[a].replace(/ /g, '');
2645
2646					switch (al) {
2647						case 'top':
2648							vid.marginTop = -abundance;
2649							break;
2650						case 'bottom':
2651							vid.marginTop = Math.ceil(-(vid.height - win.height) - (abundance / 2));
2652							break;
2653						case 'left':
2654							vid.marginLeft = -(abundance);
2655							break;
2656						case 'right':
2657							vid.marginLeft = Math.ceil(-(vid.width - win.width) + (abundance / 2));
2658							break
2659					}
2660
2661				}
2662			}
2663
2664		} else {
2665			vid.width = '100%';
2666			vid.height = '100%';
2667			vid.marginTop = 0;
2668			vid.marginLeft = 0
2669		}
2670
2671		iframe.css({
2672			width     : vid.width,
2673			height    : vid.height,
2674			marginTop : vid.marginTop,
2675			marginLeft: vid.marginLeft,
2676			maxWidth  : 'initial'
2677		})
2678
2679
2680	};
2681
2682
2683	/* UTILITIES -----------------------------------------------------------------------------------------------------------------------*/
2684
2685	/**
2686	 * shuffle
2687	 * @param arr
2688	 * @returns {Array|string|Blob|*}
2689	 *
2690	 */
2691	jQuery.shuffle = function (arr) {
2692		let newArray = arr.slice();
2693		let len = newArray.length;
2694		let i = len;
2695		while (i--) {
2696			let p = parseInt(Math.random() * len);
2697			let t = newArray[i];
2698			newArray[i] = newArray[p];
2699			newArray[p] = t
2700		}
2701		return newArray;
2702	};
2703
2704	/**
2705	 * Unselectable
2706	 * @returns {*}
2707	 */
2708	jQuery.fn.unselectable = function () {
2709		return this.each(function () {
2710			jQuery(this).css({
2711				'-moz-user-select'   : 'none',
2712				'-webkit-user-select': 'none',
2713				'user-select'        : 'none'
2714			}).attr('unselectable', 'on')
2715		})
2716	};
2717
2718	/* EXTERNAL METHODS -----------------------------------------------------------------------------------------------------------------------*/
2719
2720	jQuery.fn.YTPlayer = jQuery.mbYTPlayer.buildPlayer;
2721	jQuery.fn.mb_YTPlayer = jQuery.mbYTPlayer.buildPlayer;
2722
2723	jQuery.fn.YTPCheckForState = jQuery.mbYTPlayer.checkForState;
2724
2725	jQuery.fn.YTPGetPlayer = jQuery.mbYTPlayer.getPlayer;
2726	jQuery.fn.YTPGetVideoID = jQuery.mbYTPlayer.getVideoID;
2727	jQuery.fn.YTPGetPlaylistID = jQuery.mbYTPlayer.getPlaylistID;
2728	jQuery.fn.YTPChangeVideo = jQuery.fn.YTPChangeMovie = jQuery.mbYTPlayer.changeVideo;
2729	jQuery.fn.YTPPlayerDestroy = jQuery.mbYTPlayer.playerDestroy;
2730
2731	jQuery.fn.YTPPlay = jQuery.mbYTPlayer.play;
2732	jQuery.fn.YTPTogglePlay = jQuery.mbYTPlayer.togglePlay;
2733	jQuery.fn.YTPStop = jQuery.mbYTPlayer.stop;
2734	jQuery.fn.YTPPause = jQuery.mbYTPlayer.pause;
2735	jQuery.fn.YTPSeekTo = jQuery.mbYTPlayer.seekTo;
2736
2737	jQuery.fn.YTPGetPlaybackRate = jQuery.mbYTPlayer.getPlaybackRate;
2738	jQuery.fn.YTPSetPlaybackRate = jQuery.mbYTPlayer.setPlaybackRate;
2739
2740	jQuery.fn.changeCoverImage = jQuery.mbYTPlayer.changeCoverImage;
2741
2742	jQuery.fn.YTPlaylist = jQuery.mbYTPlayer.playlist;
2743	jQuery.fn.YTPPlayNext = jQuery.mbYTPlayer.playNext;
2744	jQuery.fn.YTPPlayPrev = jQuery.mbYTPlayer.playPrev;
2745	jQuery.fn.YTPPlayIndex = jQuery.mbYTPlayer.playIndex;
2746
2747	jQuery.fn.YTPMute = jQuery.mbYTPlayer.mute;
2748	jQuery.fn.YTPUnmute = jQuery.mbYTPlayer.unmute;
2749	jQuery.fn.YTPToggleVolume = jQuery.mbYTPlayer.toggleVolume;
2750	jQuery.fn.YTPSetVolume = jQuery.mbYTPlayer.setVolume;
2751	jQuery.fn.YTPGetVolume = jQuery.mbYTPlayer.getVolume;
2752
2753	jQuery.fn.YTPGetVideoData = jQuery.mbYTPlayer.getVideoData;
2754	jQuery.fn.YTPFullscreen = jQuery.mbYTPlayer.fullscreen;
2755	jQuery.fn.YTPToggleLoops = jQuery.mbYTPlayer.toggleLoops;
2756	jQuery.fn.YTPManageProgress = jQuery.mbYTPlayer.manageProgress;
2757
2758	jQuery.fn.YTPSetVideoQuality = jQuery.mbYTPlayer.setVideoQuality;
2759	jQuery.fn.YTPGetVideoQuality = jQuery.mbYTPlayer.getVideoQuality;
2760
2761	jQuery.fn.YTPApplyFilter = jQuery.mbYTPlayer.applyFilter;
2762	jQuery.fn.YTPApplyFilters = jQuery.mbYTPlayer.applyFilters;
2763	jQuery.fn.YTPToggleFilter = jQuery.mbYTPlayer.toggleFilter;
2764	jQuery.fn.YTPToggleFilters = jQuery.mbYTPlayer.toggleFilters;
2765	jQuery.fn.YTPRemoveFilter = jQuery.mbYTPlayer.removeFilter;
2766	jQuery.fn.YTPDisableFilters = jQuery.mbYTPlayer.disableFilters;
2767	jQuery.fn.YTPEnableFilters = jQuery.mbYTPlayer.enableFilters;
2768	jQuery.fn.YTPGetFilters = jQuery.mbYTPlayer.getFilters;
2769
2770	jQuery.fn.YTPGetTime = jQuery.mbYTPlayer.getTime;
2771	jQuery.fn.YTPGetTotalTime = jQuery.mbYTPlayer.getTotalTime;
2772
2773	jQuery.fn.YTPAddMask = jQuery.mbYTPlayer.addMask;
2774	jQuery.fn.YTPRemoveMask = jQuery.mbYTPlayer.removeMask;
2775	jQuery.fn.YTPToggleMask = jQuery.mbYTPlayer.toggleMask;
2776
2777	jQuery.fn.YTPGetAbundance = jQuery.mbYTPlayer.getAbundance;
2778	jQuery.fn.YTPSetAbundance = jQuery.mbYTPlayer.setAbundance;
2779
2780	jQuery.fn.YTPSetAnchor = jQuery.mbYTPlayer.setAnchor;
2781	jQuery.fn.YTPGetAnchor = jQuery.mbYTPlayer.getAnchor;
2782
2783	jQuery.fn.YTPSetOption = jQuery.mbYTPlayer.setOption
2784
2785})(jQuery, ytp);
vendor: 8,868 bytes, lines 2786-2818
2786/*___________________________________________________________________________________________________________________________________________________
2787 _ jquery.mb.components                                                                                                                             _
2788 _                                                                                                                                                  _
2789 _ file: jquery.mb.mbBrowser.min.js                                                                                                                   _
2790 _ last modified: 24/05/17 19.56                                                                                                                    _
2791 _                                                                                                                                                  _
2792 _ Open Lab s.r.l., Florence - Italy                                                                                                                _
2793 _                                                                                                                                                  _
2794 _ email: [email protected]                                                                                                                       _
2795 _ site: http://pupunzi.com                                                                                                                         _
2796 _       http://open-lab.com                                                                                                                        _
2797 _ blog: http://pupunzi.open-lab.com                                                                                                                _
2798 _ Q&A:  http://jquery.pupunzi.com                                                                                                                  _
2799 _                                                                                                                                                  _
2800 _ Licences: MIT, GPL                                                                                                                               _
2801 _    http://www.opensource.org/licenses/mit-license.php                                                                                            _
2802 _    http://www.gnu.org/licenses/gpl.html                                                                                                          _
2803 _                                                                                                                                                  _
2804 _ Copyright (c) 2001-2017. Matteo Bicocchi (Pupunzi);                                                                                              _
2805 ___________________________________________________________________________________________________________________________________________________*/
2806var nAgt=navigator.userAgent;jQuery.mbBrowser=jQuery.mbBrowser||{};jQuery.mbBrowser.mozilla=!1;jQuery.mbBrowser.webkit=!1;jQuery.mbBrowser.opera=!1;jQuery.mbBrowser.safari=!1;jQuery.mbBrowser.chrome=!1;jQuery.mbBrowser.androidStock=!1;jQuery.mbBrowser.msie=!1;jQuery.mbBrowser.edge=!1;jQuery.mbBrowser.ua=nAgt;function isTouchSupported(){var a=nAgt.msMaxTouchPoints,e="ontouchstart"in document.createElement("div");return a||e?!0:!1}
2807var getOS=function(){var a={version:"Unknown version",name:"Unknown OS"};-1!=navigator.appVersion.indexOf("Win")&&(a.name="Windows");-1!=navigator.appVersion.indexOf("Mac")&&0>navigator.appVersion.indexOf("Mobile")&&(a.name="Mac");-1!=navigator.appVersion.indexOf("Linux")&&(a.name="Linux");/Mac OS X/.test(nAgt)&&!/Mobile/.test(nAgt)&&(a.version=/Mac OS X ([\._\d]+)/.exec(nAgt)[1],a.version=a.version.replace(/_/g,".").substring(0,5));/Windows/.test(nAgt)&&(a.version="Unknown.Unknown");/Windows NT 5.1/.test(nAgt)&&
2808(a.version="5.1");/Windows NT 6.0/.test(nAgt)&&(a.version="6.0");/Windows NT 6.1/.test(nAgt)&&(a.version="6.1");/Windows NT 6.2/.test(nAgt)&&(a.version="6.2");/Windows NT 10.0/.test(nAgt)&&(a.version="10.0");/Linux/.test(nAgt)&&/Linux/.test(nAgt)&&(a.version="Unknown.Unknown");a.name=a.name.toLowerCase();a.major_version="Unknown";a.minor_version="Unknown";"Unknown.Unknown"!=a.version&&(a.major_version=parseFloat(a.version.split(".")[0]),a.minor_version=parseFloat(a.version.split(".")[1]));return a};
2809jQuery.mbBrowser.os=getOS();jQuery.mbBrowser.hasTouch=isTouchSupported();jQuery.mbBrowser.name=navigator.appName;jQuery.mbBrowser.fullVersion=""+parseFloat(navigator.appVersion);jQuery.mbBrowser.majorVersion=parseInt(navigator.appVersion,10);var nameOffset,verOffset,ix;
2810if(-1!=(verOffset=nAgt.indexOf("Opera")))jQuery.mbBrowser.opera=!0,jQuery.mbBrowser.name="Opera",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+6),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8));else if(-1!=(verOffset=nAgt.indexOf("OPR")))jQuery.mbBrowser.opera=!0,jQuery.mbBrowser.name="Opera",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+4);else if(-1!=(verOffset=nAgt.indexOf("MSIE")))jQuery.mbBrowser.msie=!0,jQuery.mbBrowser.name="Microsoft Internet Explorer",
2811	jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+5);else if(-1!=nAgt.indexOf("Trident")){jQuery.mbBrowser.msie=!0;jQuery.mbBrowser.name="Microsoft Internet Explorer";var start=nAgt.indexOf("rv:")+3,end=start+4;jQuery.mbBrowser.fullVersion=nAgt.substring(start,end)}else-1!=(verOffset=nAgt.indexOf("Edge"))?(jQuery.mbBrowser.edge=!0,jQuery.mbBrowser.name="Microsoft Edge",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+5)):-1!=(verOffset=nAgt.indexOf("Chrome"))?(jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.chrome=
2812	!0,jQuery.mbBrowser.name="Chrome",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7)):-1<nAgt.indexOf("mozilla/5.0")&&-1<nAgt.indexOf("android ")&&-1<nAgt.indexOf("applewebkit")&&!(-1<nAgt.indexOf("chrome"))?(verOffset=nAgt.indexOf("Chrome"),jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.androidStock=!0,jQuery.mbBrowser.name="androidStock",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7)):-1!=(verOffset=nAgt.indexOf("Safari"))?(jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.safari=!0,jQuery.mbBrowser.name=
2813	"Safari",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8))):-1!=(verOffset=nAgt.indexOf("AppleWebkit"))?(jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.safari=!0,jQuery.mbBrowser.name="Safari",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8))):-1!=(verOffset=nAgt.indexOf("Firefox"))?(jQuery.mbBrowser.mozilla=
2814	!0,jQuery.mbBrowser.name="Firefox",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8)):(nameOffset=nAgt.lastIndexOf(" ")+1)<(verOffset=nAgt.lastIndexOf("/"))&&(jQuery.mbBrowser.name=nAgt.substring(nameOffset,verOffset),jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+1),jQuery.mbBrowser.name.toLowerCase()==jQuery.mbBrowser.name.toUpperCase()&&(jQuery.mbBrowser.name=navigator.appName));
2815-1!=(ix=jQuery.mbBrowser.fullVersion.indexOf(";"))&&(jQuery.mbBrowser.fullVersion=jQuery.mbBrowser.fullVersion.substring(0,ix));-1!=(ix=jQuery.mbBrowser.fullVersion.indexOf(" "))&&(jQuery.mbBrowser.fullVersion=jQuery.mbBrowser.fullVersion.substring(0,ix));jQuery.mbBrowser.majorVersion=parseInt(""+jQuery.mbBrowser.fullVersion,10);isNaN(jQuery.mbBrowser.majorVersion)&&(jQuery.mbBrowser.fullVersion=""+parseFloat(navigator.appVersion),jQuery.mbBrowser.majorVersion=parseInt(navigator.appVersion,10));
2816jQuery.mbBrowser.version=jQuery.mbBrowser.majorVersion;jQuery.mbBrowser.android=/Android/i.test(nAgt);jQuery.mbBrowser.blackberry=/BlackBerry|BB|PlayBook/i.test(nAgt);jQuery.mbBrowser.ios=/iPhone|iPad|iPod|webOS/i.test(nAgt);jQuery.mbBrowser.operaMobile=/Opera Mini/i.test(nAgt);jQuery.mbBrowser.windowsMobile=/IEMobile|Windows Phone/i.test(nAgt);jQuery.mbBrowser.kindle=/Kindle|Silk/i.test(nAgt);
2817jQuery.mbBrowser.mobile=jQuery.mbBrowser.android||jQuery.mbBrowser.blackberry||jQuery.mbBrowser.ios||jQuery.mbBrowser.windowsMobile||jQuery.mbBrowser.operaMobile||jQuery.mbBrowser.kindle;jQuery.isMobile=jQuery.mbBrowser.mobile;jQuery.isTablet=jQuery.mbBrowser.mobile&&765<jQuery(window).width();jQuery.isAndroidDefault=jQuery.mbBrowser.android&&!/chrome/i.test(nAgt);jQuery.mbBrowser=jQuery.mbBrowser;
2818jQuery.mbBrowser.versionCompare=function(a,e){if("stringstring"!=typeof a+typeof e)return!1;for(var c=a.split("."),d=e.split("."),b=0,f=Math.max(c.length,d.length);b<f;b++){if(c[b]&&!d[b]&&0<parseInt(c[b])||parseInt(c[b])>parseInt(d[b]))return 1;if(d[b]&&!c[b]&&0<parseInt(d[b])||parseInt(c[b])<parseInt(d[b]))return-1}return 0};
vendor: 24,124 bytes, lines 2819-2932
2819/*
2820 * ******************************************************************************
2821 *  jquery.mb.components
2822 *  file: jquery.mb.CSSAnimate.min.js
2823 *
2824 *  Copyright (c) 2001-2014. Matteo Bicocchi (Pupunzi);
2825 *  Open lab srl, Firenze - Italy
2826 *  email: [email protected]
2827 *  site: 	http://pupunzi.com
2828 *  blog:	http://pupunzi.open-lab.com
2829 * 	http://open-lab.com
2830 *
2831 *  Licences: MIT, GPL
2832 *  http://www.opensource.org/licenses/mit-license.php
2833 *  http://www.gnu.org/licenses/gpl.html
2834 *
2835 *  last modified: 26/03/14 21.40
2836 *  *****************************************************************************
2837 */
2838
2839jQuery.support.CSStransition=function(){var d=(document.body||document.documentElement).style;return void 0!==d.transition||void 0!==d.WebkitTransition||void 0!==d.MozTransition||void 0!==d.MsTransition||void 0!==d.OTransition}();function uncamel(d){return d.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()})}function setUnit(d,a){return"string"!==typeof d||d.match(/^[\-0-9\.]+jQuery/)?""+d+a:d}
2840function setFilter(d,a,b){var c=uncamel(a),g=jQuery.mbBrowser.mozilla?"":jQuery.CSS.sfx;d[g+"filter"]=d[g+"filter"]||"";b=setUnit(b>jQuery.CSS.filters[a].max?jQuery.CSS.filters[a].max:b,jQuery.CSS.filters[a].unit);d[g+"filter"]+=c+"("+b+") ";delete d[a]}
2841jQuery.CSS={name:"mb.CSSAnimate",author:"Matteo Bicocchi",version:"2.0.0",transitionEnd:"transitionEnd",sfx:"",filters:{blur:{min:0,max:100,unit:"px"},brightness:{min:0,max:400,unit:"%"},contrast:{min:0,max:400,unit:"%"},grayscale:{min:0,max:100,unit:"%"},hueRotate:{min:0,max:360,unit:"deg"},invert:{min:0,max:100,unit:"%"},saturate:{min:0,max:400,unit:"%"},sepia:{min:0,max:100,unit:"%"}},normalizeCss:function(d){var a=jQuery.extend(!0,{},d);jQuery.mbBrowser.webkit||jQuery.mbBrowser.opera?jQuery.CSS.sfx=
2842		"-webkit-":jQuery.mbBrowser.mozilla?jQuery.CSS.sfx="-moz-":jQuery.mbBrowser.msie&&(jQuery.CSS.sfx="-ms-");jQuery.CSS.sfx="";for(var b in a){"transform"===b&&(a[jQuery.CSS.sfx+"transform"]=a[b],delete a[b]);"transform-origin"===b&&(a[jQuery.CSS.sfx+"transform-origin"]=d[b],delete a[b]);"filter"!==b||jQuery.mbBrowser.mozilla||(a[jQuery.CSS.sfx+"filter"]=d[b],delete a[b]);"blur"===b&&setFilter(a,"blur",d[b]);"brightness"===b&&setFilter(a,"brightness",d[b]);"contrast"===b&&setFilter(a,"contrast",d[b]);"grayscale"===
2843b&&setFilter(a,"grayscale",d[b]);"hueRotate"===b&&setFilter(a,"hueRotate",d[b]);"invert"===b&&setFilter(a,"invert",d[b]);"saturate"===b&&setFilter(a,"saturate",d[b]);"sepia"===b&&setFilter(a,"sepia",d[b]);if("x"===b){var c=jQuery.CSS.sfx+"transform";a[c]=a[c]||"";a[c]+=" translateX("+setUnit(d[b],"px")+")";delete a[b]}"y"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" translateY("+setUnit(d[b],"px")+")",delete a[b]);"z"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" translateZ("+
2844		setUnit(d[b],"px")+")",delete a[b]);"rotate"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" rotate("+setUnit(d[b],"deg")+")",delete a[b]);"rotateX"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" rotateX("+setUnit(d[b],"deg")+")",delete a[b]);"rotateY"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" rotateY("+setUnit(d[b],"deg")+")",delete a[b]);"rotateZ"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" rotateZ("+setUnit(d[b],"deg")+")",delete a[b]);"scale"===b&&
2845(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" scale("+setUnit(d[b],"")+")",delete a[b]);"scaleX"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" scaleX("+setUnit(d[b],"")+")",delete a[b]);"scaleY"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" scaleY("+setUnit(d[b],"")+")",delete a[b]);"scaleZ"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" scaleZ("+setUnit(d[b],"")+")",delete a[b]);"skew"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" skew("+setUnit(d[b],
2846		"deg")+")",delete a[b]);"skewX"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" skewX("+setUnit(d[b],"deg")+")",delete a[b]);"skewY"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" skewY("+setUnit(d[b],"deg")+")",delete a[b]);"perspective"===b&&(c=jQuery.CSS.sfx+"transform",a[c]=a[c]||"",a[c]+=" perspective("+setUnit(d[b],"px")+")",delete a[b])}return a},getProp:function(d){var a=[],b;for(b in d)0>a.indexOf(b)&&a.push(uncamel(b));return a.join(",")},animate:function(d,a,b,c,g){return this.each(function(){function n(){e.called=
2847		!0;e.CSSAIsRunning=!1;h.off(jQuery.CSS.transitionEnd+"."+e.id);clearTimeout(e.timeout);h.css(jQuery.CSS.sfx+"transition","");"function"==typeof g&&g.apply(e);"function"==typeof e.CSSqueue&&(e.CSSqueue(),e.CSSqueue=null)}var e=this,h=jQuery(this);e.id=e.id||"CSSA_"+(new Date).getTime();var k=k||{type:"noEvent"};if(e.CSSAIsRunning&&e.eventType==k.type&&!jQuery.mbBrowser.msie&&9>=jQuery.mbBrowser.version)e.CSSqueue=function(){h.CSSAnimate(d,a,b,c,g)};else if(e.CSSqueue=null,e.eventType=k.type,0!==h.length&&
2848		d){d=jQuery.normalizeCss(d);e.CSSAIsRunning=!0;"function"==typeof a&&(g=a,a=jQuery.fx.speeds._default);"function"==typeof b&&(c=b,b=0);"string"==typeof b&&(g=b,b=0);"function"==typeof c&&(g=c,c="cubic-bezier(0.65,0.03,0.36,0.72)");if("string"==typeof a)for(var l in jQuery.fx.speeds)if(a==l){a=jQuery.fx.speeds[l];break}else a=jQuery.fx.speeds._default;a||(a=jQuery.fx.speeds._default);"string"===typeof g&&(c=g,g=null);if(jQuery.support.CSStransition){var f={"default":"ease","in":"ease-in",out:"ease-out",
2849	"in-out":"ease-in-out",snap:"cubic-bezier(0,1,.5,1)",easeOutCubic:"cubic-bezier(.215,.61,.355,1)",easeInOutCubic:"cubic-bezier(.645,.045,.355,1)",easeInCirc:"cubic-bezier(.6,.04,.98,.335)",easeOutCirc:"cubic-bezier(.075,.82,.165,1)",easeInOutCirc:"cubic-bezier(.785,.135,.15,.86)",easeInExpo:"cubic-bezier(.95,.05,.795,.035)",easeOutExpo:"cubic-bezier(.19,1,.22,1)",easeInOutExpo:"cubic-bezier(1,0,0,1)",easeInQuad:"cubic-bezier(.55,.085,.68,.53)",easeOutQuad:"cubic-bezier(.25,.46,.45,.94)",easeInOutQuad:"cubic-bezier(.455,.03,.515,.955)",
2850	easeInQuart:"cubic-bezier(.895,.03,.685,.22)",easeOutQuart:"cubic-bezier(.165,.84,.44,1)",easeInOutQuart:"cubic-bezier(.77,0,.175,1)",easeInQuint:"cubic-bezier(.755,.05,.855,.06)",easeOutQuint:"cubic-bezier(.23,1,.32,1)",easeInOutQuint:"cubic-bezier(.86,0,.07,1)",easeInSine:"cubic-bezier(.47,0,.745,.715)",easeOutSine:"cubic-bezier(.39,.575,.565,1)",easeInOutSine:"cubic-bezier(.445,.05,.55,.95)",easeInBack:"cubic-bezier(.6,-.28,.735,.045)",easeOutBack:"cubic-bezier(.175, .885,.32,1.275)",easeInOutBack:"cubic-bezier(.68,-.55,.265,1.55)"};
2851	f[c]&&(c=f[c]);h.off(jQuery.CSS.transitionEnd+"."+e.id);f=jQuery.CSS.getProp(d);var m={};jQuery.extend(m,d);m[jQuery.CSS.sfx+"transition-property"]=f;m[jQuery.CSS.sfx+"transition-duration"]=a+"ms";m[jQuery.CSS.sfx+"transition-delay"]=b+"ms";m[jQuery.CSS.sfx+"transition-timing-function"]=c;setTimeout(function(){h.one(jQuery.CSS.transitionEnd+"."+e.id,n);h.css(m)},1);e.timeout=setTimeout(function(){e.called||!g?(e.called=!1,e.CSSAIsRunning=!1):(h.css(jQuery.CSS.sfx+"transition",""),g.apply(e),e.CSSAIsRunning=
2852			!1,"function"==typeof e.CSSqueue&&(e.CSSqueue(),e.CSSqueue=null))},a+b+10)}else{for(f in d)"transform"===f&&delete d[f],"filter"===f&&delete d[f],"transform-origin"===f&&delete d[f],"auto"===d[f]&&delete d[f],"x"===f&&(k=d[f],l="left",d[l]=k,delete d[f]),"y"===f&&(k=d[f],l="top",d[l]=k,delete d[f]),"-ms-transform"!==f&&"-ms-filter"!==f||delete d[f];h.delay(b).animate(d,a,g)}}})}};jQuery.fn.CSSAnimate=jQuery.CSS.animate;jQuery.normalizeCss=jQuery.CSS.normalizeCss;
2853jQuery.fn.css3=function(d){return this.each(function(){var a=jQuery(this),b=jQuery.normalizeCss(d);a.css(b)})};
2854/*___________________________________________________________________________________________________________________________________________________
2855 _ jquery.mb.components                                                                                                                             _
2856 _                                                                                                                                                  _
2857 _ file: jquery.mb.simpleSlider.min.js                                                                                                              _
2858 _ last modified: 09/05/17 19.31                                                                                                                    _
2859 _                                                                                                                                                  _
2860 _ Open Lab s.r.l., Florence - Italy                                                                                                                _
2861 _                                                                                                                                                  _
2862 _ email: [email protected]                                                                                                                       _
2863 _ site: http://pupunzi.com                                                                                                                         _
2864 _       http://open-lab.com                                                                                                                        _
2865 _ blog: http://pupunzi.open-lab.com                                                                                                                _
2866 _ Q&A:  http://jquery.pupunzi.com                                                                                                                  _
2867 _                                                                                                                                                  _
2868 _ Licences: MIT, GPL                                                                                                                               _
2869 _    http://www.opensource.org/licenses/mit-license.php                                                                                            _
2870 _    http://www.gnu.org/licenses/gpl.html                                                                                                          _
2871 _                                                                                                                                                  _
2872 _ Copyright (c) 2001-2017. Matteo Bicocchi (Pupunzi);                                                                                              _
2873 ___________________________________________________________________________________________________________________________________________________*/
2874(function(b){b.simpleSlider={defaults:{initialval:0,maxval:100,orientation:"h",readonly:!1,callback:!1},events:{start:b.mbBrowser.mobile?"touchstart":"mousedown",end:b.mbBrowser.mobile?"touchend":"mouseup",move:b.mbBrowser.mobile?"touchmove":"mousemove"},init:function(d){return this.each(function(){var a=this,c=b(a);c.addClass("simpleSlider");a.opt={};b.extend(a.opt,b.simpleSlider.defaults,d);b.extend(a.opt,c.data());var f="h"===a.opt.orientation?"horizontal":"vertical";f=b("<div/>").addClass("level").addClass(f);
2875		c.prepend(f);a.level=f;c.css({cursor:"default"});"auto"==a.opt.maxval&&(a.opt.maxval=b(a).outerWidth());c.updateSliderVal();a.opt.readonly||(c.on(b.simpleSlider.events.start,function(e){b.mbBrowser.mobile&&(e=e.changedTouches[0]);a.canSlide=!0;c.updateSliderVal(e);"h"===a.opt.orientation?c.css({cursor:"col-resize"}):c.css({cursor:"row-resize"});a.lastVal=a.val;b.mbBrowser.mobile||(e.preventDefault(),e.stopPropagation())}),b(document).on(b.simpleSlider.events.move,function(e){b.mbBrowser.mobile&&(e=e.changedTouches[0]);
2876			a.canSlide&&(b(document).css({cursor:"default"}),c.updateSliderVal(e),b.mbBrowser.mobile||(e.preventDefault(),e.stopPropagation()))}).on(b.simpleSlider.events.end,function(){b(document).css({cursor:"auto"});a.canSlide=!1;c.css({cursor:"auto"})}))})},updateSliderVal:function(d){var a=this.get(0);if(a.opt){a.opt.initialval="number"==typeof a.opt.initialval?a.opt.initialval:a.opt.initialval(a);var c=b(a).outerWidth(),f=b(a).outerHeight();a.x="object"==typeof d?d.clientX+document.body.scrollLeft-this.offset().left:
2877			"number"==typeof d?d*c/a.opt.maxval:a.opt.initialval*c/a.opt.maxval;a.y="object"==typeof d?d.clientY+document.body.scrollTop-this.offset().top:"number"==typeof d?(a.opt.maxval-a.opt.initialval-d)*f/a.opt.maxval:a.opt.initialval*f/a.opt.maxval;a.y=this.outerHeight()-a.y;a.scaleX=a.x*a.opt.maxval/c;a.scaleY=a.y*a.opt.maxval/f;a.outOfRangeX=a.scaleX>a.opt.maxval?a.scaleX-a.opt.maxval:0>a.scaleX?a.scaleX:0;a.outOfRangeY=a.scaleY>a.opt.maxval?a.scaleY-a.opt.maxval:0>a.scaleY?a.scaleY:0;a.outOfRange="h"===
2878	a.opt.orientation?a.outOfRangeX:a.outOfRangeY;a.value="undefined"!=typeof d?"h"===a.opt.orientation?a.x>=this.outerWidth()?a.opt.maxval:0>=a.x?0:a.scaleX:a.y>=this.outerHeight()?a.opt.maxval:0>=a.y?0:a.scaleY:"h"===a.opt.orientation?a.scaleX:a.scaleY;"h"===a.opt.orientation?a.level.width(Math.floor(100*a.x/c)+"%"):a.level.height(Math.floor(100*a.y/f));a.lastVal===a.value&&("h"===a.opt.orientation&&(a.x>=this.outerWidth()||0>=a.x)||"h"!==a.opt.orientation&&(a.y>=this.outerHeight()||0>=a.y))||("function"===
2879	typeof a.opt.callback&&a.opt.callback(a),a.lastVal=a.value)}}};b.fn.simpleSlider=b.simpleSlider.init;b.fn.updateSliderVal=b.simpleSlider.updateSliderVal})(jQuery);
2880/*___________________________________________________________________________________________________________________________________________________
2881 _ jquery.mb.components                                                                                                                             _
2882 _                                                                                                                                                  _
2883 _ file: jquery.mb.storage.min.js                                                                                                                   _
2884 _ last modified: 24/05/15 16.08                                                                                                                    _
2885 _                                                                                                                                                  _
2886 _ Open Lab s.r.l., Florence - Italy                                                                                                                _
2887 _                                                                                                                                                  _
2888 _ email: [email protected]                                                                                                                       _
2889 _ site: http://pupunzi.com                                                                                                                         _
2890 _       http://open-lab.com                                                                                                                        _
2891 _ blog: http://pupunzi.open-lab.com                                                                                                                _
2892 _ Q&A:  http://jquery.pupunzi.com                                                                                                                  _
2893 _                                                                                                                                                  _
2894 _ Licences: MIT, GPL                                                                                                                               _
2895 _    http://www.opensource.org/licenses/mit-license.php                                                                                            _
2896 _    http://www.gnu.org/licenses/gpl.html                                                                                                          _
2897 _                                                                                                                                                  _
2898 _ Copyright (c) 2001-2015. Matteo Bicocchi (Pupunzi);                                                                                              _
2899 ___________________________________________________________________________________________________________________________________________________*/
2900
2901(function(d){d.mbCookie={set:function(a,c,f,b){"object"==typeof c&&(c=JSON.stringify(c));b=b?"; domain="+b:"";var e=new Date,d="";0<f&&(e.setTime(e.getTime()+864E5*f),d="; expires="+e.toGMTString());document.cookie=a+"="+c+d+"; path=/"+b},get:function(a){a+="=";for(var c=document.cookie.split(";"),d=0;d<c.length;d++){for(var b=c[d];" "==b.charAt(0);)b=b.substring(1,b.length);if(0==b.indexOf(a))try{return JSON.parse(b.substring(a.length,b.length))}catch(e){return b.substring(a.length,b.length)}}return null},
2902	remove:function(a){d.mbCookie.set(a,"",-1)}};d.mbStorage={set:function(a,c){"object"==typeof c&&(c=JSON.stringify(c));localStorage.setItem(a,c)},get:function(a){if(localStorage[a])try{return JSON.parse(localStorage[a])}catch(c){return localStorage[a]}else return null},remove:function(a){a?localStorage.removeItem(a):localStorage.clear()}}})(jQuery);
2903/*___________________________________________________________________________________________________________________________________________________
2904 _ jquery.mb.components                                                                                                                             _
2905 _                                                                                                                                                  _
2906 _ file: jquery.mbBrowser.min.js                                                                                                                    _
2907 _ last modified: 1/23/21 4:18 PM                                                                                                                   _
2908 _                                                                                                                                                  _
2909 _ Open Lab s.r.l., Florence - Italy                                                                                                                _
2910 _                                                                                                                                                  _
2911 _ email: [email protected]                                                                                                                       _
2912 _ site: http://pupunzi.com                                                                                                                         _
2913 _       http://open-lab.com                                                                                                                        _
2914 _ blog: http://pupunzi.open-lab.com                                                                                                                _
2915 _ Q&A:  http://jquery.pupunzi.com                                                                                                                  _
2916 _                                                                                                                                                  _
2917 _ Licences: MIT, GPL                                                                                                                               _
2918 _    http://www.opensource.org/licenses/mit-license.php                                                                                            _
2919 _    http://www.gnu.org/licenses/gpl.html                                                                                                          _
2920 _                                                                                                                                                  _
2921 _ Copyright (c) 2001-2021. Matteo Bicocchi (Pupunzi);                                                                                              _
2922 ___________________________________________________________________________________________________________________________________________________*/
2923
2924var nAgt=navigator.userAgent;jQuery.mbBrowser={};jQuery.mbBrowser.mozilla=!1;jQuery.mbBrowser.webkit=!1;jQuery.mbBrowser.opera=!1;jQuery.mbBrowser.safari=!1;jQuery.mbBrowser.chrome=!1;jQuery.mbBrowser.androidStock=!1;jQuery.mbBrowser.msie=!1;jQuery.mbBrowser.edge=!1;jQuery.mbBrowser.ua=nAgt;function isTouchSupported(){var a=nAgt.msMaxTouchPoints,e="ontouchstart"in document.createElement("div");return a||e?!0:!1}
2925var getOS=function(){var a={version:"Unknown version",name:"Unknown OS"};-1!=navigator.appVersion.indexOf("Win")&&(a.name="Windows");-1!=navigator.appVersion.indexOf("Mac")&&0>navigator.appVersion.indexOf("Mobile")&&(a.name="Mac");-1!=navigator.appVersion.indexOf("Linux")&&(a.name="Linux");/Mac OS X/.test(nAgt)&&!/Mobile/.test(nAgt)&&(a.version=/Mac OS X ([\._\d]+)/.exec(nAgt)[1],a.version=a.version.replace(/_/g,".").substring(0,5));/Windows/.test(nAgt)&&(a.version="Unknown.Unknown");/Windows NT 5.1/.test(nAgt)&&
2926(a.version="5.1");/Windows NT 6.0/.test(nAgt)&&(a.version="6.0");/Windows NT 6.1/.test(nAgt)&&(a.version="6.1");/Windows NT 6.2/.test(nAgt)&&(a.version="6.2");/Windows NT 10.0/.test(nAgt)&&(a.version="10.0");/Linux/.test(nAgt)&&/Linux/.test(nAgt)&&(a.version="Unknown.Unknown");a.name=a.name.toLowerCase();a.major_version="Unknown";a.minor_version="Unknown";"Unknown.Unknown"!=a.version&&(a.major_version=parseFloat(a.version.split(".")[0]),a.minor_version=parseFloat(a.version.split(".")[1]));return a};
2927jQuery.mbBrowser.os=getOS();jQuery.mbBrowser.hasTouch=isTouchSupported();jQuery.mbBrowser.name=navigator.appName;jQuery.mbBrowser.fullVersion=""+parseFloat(navigator.appVersion);jQuery.mbBrowser.majorVersion=parseInt(navigator.appVersion,10);var nameOffset,verOffset,ix;
2928if(-1!=(verOffset=nAgt.indexOf("Opera")))jQuery.mbBrowser.opera=!0,jQuery.mbBrowser.name="Opera",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+6),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8));else if(-1!=(verOffset=nAgt.indexOf("OPR")))jQuery.mbBrowser.opera=!0,jQuery.mbBrowser.name="Opera",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+4);else if(-1!=(verOffset=nAgt.indexOf("MSIE")))jQuery.mbBrowser.msie=!0,jQuery.mbBrowser.name=
2929		"Microsoft Internet Explorer",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+5);else if(-1!=nAgt.indexOf("Trident")){jQuery.mbBrowser.msie=!0;jQuery.mbBrowser.name="Microsoft Internet Explorer";var start=nAgt.indexOf("rv:")+3,end=start+4;jQuery.mbBrowser.fullVersion=nAgt.substring(start,end)}else-1!=(verOffset=nAgt.indexOf("Edge"))?(jQuery.mbBrowser.edge=!0,jQuery.mbBrowser.name="Microsoft Edge",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+5)):-1!=(verOffset=nAgt.indexOf("Chrome"))?
2930		(jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.chrome=!0,jQuery.mbBrowser.name="Chrome",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7)):-1<nAgt.indexOf("mozilla/5.0")&&-1<nAgt.indexOf("android ")&&-1<nAgt.indexOf("applewebkit")&&!(-1<nAgt.indexOf("chrome"))?(verOffset=nAgt.indexOf("Chrome"),jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.androidStock=!0,jQuery.mbBrowser.name="androidStock",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7)):-1!=(verOffset=nAgt.indexOf("Safari"))?(jQuery.mbBrowser.webkit=
2931				!0,jQuery.mbBrowser.safari=!0,jQuery.mbBrowser.name="Safari",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8))):-1!=(verOffset=nAgt.indexOf("AppleWebkit"))?(jQuery.mbBrowser.webkit=!0,jQuery.mbBrowser.safari=!0,jQuery.mbBrowser.name="Safari",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+7),-1!=(verOffset=nAgt.indexOf("Version"))&&(jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+
2932				8))):-1!=(verOffset=nAgt.indexOf("Firefox"))?(jQuery.mbBrowser.mozilla=!0,jQuery.mbBrowser.name="Firefox",jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+8)):(nameOff
2932set=nAgt.lastIndexOf(" ")+1)<(verOffset=nAgt.lastIndexOf("/"))&&(jQuery.mbBrowser.name=nAgt.substring(nameOffset,verOffset),jQuery.mbBrowser.fullVersion=nAgt.substring(verOffset+1),jQuery.mbBrowser.name.toLowerCase()==jQuery.mbBrowser.name.toUpperCase()&&(jQuery.mbBrowser.name=navigator.appName));
2933-1!=(ix=jQuery.mbBrowser.fullVersion.indexOf(";"))&&(jQuery.mbBrowser.fullVersion=jQuery.mbBrowser.fullVersion.substring(0,ix));-1!=(ix=jQuery.mbBrowser.fullVersion.indexOf(" "))&&(jQuery.mbBrowser.fullVersion=jQuery.mbBrowser.fullVersion.substring(0,ix));jQuery.mbBrowser.majorVersion=parseInt(""+jQuery.mbBrowser.fullVersion,10);isNaN(jQuery.mbBrowser.majorVersion)&&(jQuery.mbBrowser.fullVersion=""+parseFloat(navigator.appVersion),jQuery.mbBrowser.majorVersion=parseInt(navigator.appVersion,10));
2934jQuery.mbBrowser.version=jQuery.mbBrowser.majorVersion;jQuery.mbBrowser.android=/Android/i.test(nAgt);jQuery.mbBrowser.blackberry=/BlackBerry|BB|PlayBook/i.test(nAgt);jQuery.mbBrowser.ios=/iPhone|iPad|iPod|webOS/i.test(nAgt);jQuery.mbBrowser.operaMobile=/Opera Mini/i.test(nAgt);jQuery.mbBrowser.windowsMobile=/IEMobile|Windows Phone/i.test(nAgt);jQuery.mbBrowser.kindle=/Kindle|Silk/i.test(nAgt);
2935jQuery.mbBrowser.mobile=jQuery.mbBrowser.android||jQuery.mbBrowser.blackberry||jQuery.mbBrowser.ios||jQuery.mbBrowser.windowsMobile||jQuery.mbBrowser.operaMobile||jQuery.mbBrowser.kindle;jQuery.isMobile=jQuery.mbBrowser.mobile;jQuery.isTablet=jQuery.mbBrowser.mobile&&765<jQuery(window).width();jQuery.isAndroidDefault=jQuery.mbBrowser.android&&!/chrome/i.test(nAgt);jQuery.mbBrowser=jQuery.mbBrowser;
2936jQuery.mbBrowser.versionCompare=function(a,e){if("stringstring"!=typeof a+typeof e)return!1;for(var c=a.split("."),d=e.split("."),b=0,f=Math.max(c.length,d.length);b<f;b++){if(c[b]&&!d[b]&&0<parseInt(c[b])||parseInt(c[b])>parseInt(d[b]))return 1;if(d[b]&&!c[b]&&0<parseInt(d[b])||parseInt(c[b])<parseInt(d[b]))return-1}return 0};
2937;
2938/**
2939 * Makes "skip to content" link work correctly in IE9, Chrome, and Opera
2940 * for better accessibility.
2941 *
2942 * @link http://www.nczonline.net/blog/2013/01/15/fixing-skip-to-content-links/
2943 */
2944
2945( function() {
2946	var ua = navigator.userAgent.toLowerCase();
2947
2948	if ( ( ua.indexOf( 'webkit' ) > -1 || ua.indexOf( 'opera' ) > -1 || ua.indexOf( 'msie' ) > -1 ) &&
2949		document.getElementById && window.addEventListener ) {
2950
2951		window.addEventListener( 'hashchange', function() {
2952			var element = document.getElementById( location.hash.substring( 1 ) );
2953
2954			if ( element ) {
2955				if ( ! /^(?:a|select|input|button|textarea)$/i.test( element.nodeName ) ) {
2956					element.tabIndex = -1;
2957				}
2958
2959				element.focus();
2960			}
2961		}, false );
2962	}
2963} )();
2964;
2965/* global screenReaderText */
2966/**
2967 * Theme functions file.
2968 *
2969 * Contains handlers for navigation and widget area.
2970 */
2971
2972( function( $ ) {
2973	var $body, $window, $sidebar, resizeTimer,
2974		secondary, button;
2975
2976	function initMainNavigation( container ) {
2977		// Add dropdown toggle that display child menu items.
2978		container.find( '.menu-item-has-children > a' ).after( '<button class="dropdown-toggle" aria-expanded="false">' + screenReaderText.expand + '</button>' );
2979
2980		// Toggle buttons and submenu items with active children menu items.
2981		container.find( '.current-menu-ancestor > button' ).addClass( 'toggle-on' );
2982		container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
2983
2984		container.find( '.dropdown-toggle' ).on( 'click', function( e ) {
2985			var _this = $( this );
2986			e.preventDefault();
2987			_this.toggleClass( 'toggle-on' );
2988			_this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
2989			_this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
2990			_this.html( _this.html() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand );
2991		} );
2992	}
2993	initMainNavigation( $( '.main-navigation' ) );
2994
2995	// Re-initialize the main navigation when it is updated, persisting any existing submenu expanded states.
2996	$( document ).on( 'customize-preview-menu-refreshed', function( e, params ) {
2997		if ( 'primary' === params.wpNavMenuArgs.theme_location ) {
2998			initMainNavigation( params.newContainer );
2999
3000			// Re-sync expanded states from oldContainer.
3001			params.oldContainer.find( '.dropdown-toggle.toggle-on' ).each(function() {
3002				var containerId = $( this ).parent().prop( 'id' );
3003				$( params.newContainer ).find( '#' + containerId + ' > .dropdown-toggle' ).triggerHandler( 'click' );
3004			});
3005		}
3006	});
3007
3008	secondary = $( '#secondary' );
3009	button = $( '.site-branding' ).find( '.secondary-toggle' );
3010
3011	// Enable menu toggle for small screens.
3012	( function() {
3013		var menu, widgets, social;
3014		if ( ! secondary.length || ! button.length ) {
3015			return;
3016		}
3017
3018		// Hide button if there are no widgets and the menus are missing or empty.
3019		menu    = secondary.find( '.nav-menu' );
3020		widgets = secondary.find( '#widget-area' );
3021		social  = secondary.find( '#social-navigation' );
3022		if ( ! widgets.length && ! social.length && ( ! menu.length || ! menu.children().length ) ) {
3023			button.hide();
3024			return;
3025		}
3026
3027		button.on( 'click.twentyfifteen', function() {
3028			secondary.toggleClass( 'toggled-on' );
3029			secondary.trigger( 'resize' );
3030			$( this ).toggleClass( 'toggled-on' );
3031			if ( $( this, secondary ).hasClass( 'toggled-on' ) ) {
3032				$( this ).attr( 'aria-expanded', 'true' );
3033				secondary.attr( 'aria-expanded', 'true' );
3034			} else {
3035				$( this ).attr( 'aria-expanded', 'false' );
3036				secondary.attr( 'aria-expanded', 'false' );
3037			}
3038		} );
3039	} )();
3040
3041	/**
3042	 * Add or remove ARIA attributes.
3043	 *
3044	 * Uses jQuery's width() function to determine the size of the window and add
3045	 * the default ARIA attributes for the menu toggle if it's visible.
3046	 *
3047	 * @since Twenty Fifteen 1.1
3048	 */
3049	function onResizeARIA() {
3050		if ( 955 > $window.width() ) {
3051			button.attr( 'aria-expanded', 'false' );
3052			secondary.attr( 'aria-expanded', 'false' );
3053			button.attr( 'aria-controls', 'secondary' );
3054		} else {
3055			button.removeAttr( 'aria-expanded' );
3056			secondary.removeAttr( 'aria-expanded' );
3057			button.removeAttr( 'aria-controls' );
3058		}
3059	}
3060
3061	// Sidebar scrolling.
3062	function resizeAndScroll() {
3063		var windowPos = $window.scrollTop(),
3064			windowHeight = $window.height(),
3065			sidebarHeight = $sidebar.height(),
3066			bodyHeight = $body.height();
3067
3068		if( 955 < $window.width() && bodyHeight > sidebarHeight && ( windowPos + windowHeight ) >= sidebarHeight ) {
3069			$sidebar.css({
3070				position: 'fixed',
3071				bottom: sidebarHeight > windowHeight ? 0 : 'auto'
3072			});
3073		} else {
3074			$sidebar.css('position', 'relative');
3075		}
3076	}
3077
3078	$( document ).ready( function() {
3079		$body          = $( document.body );
3080		$window        = $( window );
3081		$sidebar       = $( '#sidebar' ).first();
3082
3083		$window
3084			.on( 'scroll.twentyfifteen', resizeAndScroll )
3085			.on( 'load.twentyfifteen', onResizeARIA )
3086			.on( 'resize.twentyfifteen', function() {
3087				clearTimeout( resizeTimer );
3088				resizeTimer = setTimeout( resizeAndScroll, 500 );
3089				onResizeARIA();
3090			} );
3091		$sidebar.on( 'click.twentyfifteen keydown.twentyfifteen', 'button', resizeAndScroll );
3092
3093		for ( var i = 0; i < 6; i++ ) {
3094			setTimeout( resizeAndScroll, 100 * i );
3095		}
3096	} );
3097
3098} )( jQuery );
3099;
3100// For compatibility with optimizers
3101if (document.readyState !== 'loading') {
3102    //console.log('Newsletter loaded (late)');
3103    tnp_ajax_init();
3104} else {
3105    document.addEventListener("DOMContentLoaded", function () {
3106        //console.log('Newsletter loaded');
3107        tnp_ajax_init();
3108    });
3109}
3110
3111function tnp_ajax_init() {
3112    document.querySelectorAll('form.tnp-ajax').forEach(el => {
3113        el.addEventListener('submit', async function(ev) {
3114            ev.preventDefault();
3115            ev.stopPropagation();
3116            const response = await fetch(newsletter_data.action_url + '?action=tnp&na=sa', {
3117                method: "POST",
3118                body: new FormData(this)
3119            });
3120            this.innerHTML = await response.text();
3121        });
3122    });
3123}
3124
3125
3126
3127;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.