/* Minification failed. Returning unminified contents.
(7379,46-47): run-time error JS1195: Expected expression: .
(7379,59-60): run-time error JS1003: Expected ':': )
(7380,6-7): run-time error JS1009: Expected '}': s
(7380,6-7): run-time error JS1006: Expected ')': s
(7383,5-7): run-time error JS1009: Expected '}': if
(7383,5-7): run-time error JS1006: Expected ')': if
(7394,66-67): run-time error JS1195: Expected expression: .
(7394,79-80): run-time error JS1003: Expected ':': )
(7395,8-9): run-time error JS1009: Expected '}': s
(7395,8-9): run-time error JS1006: Expected ')': s
(7397,6-7): run-time error JS1006: Expected ')': }
(7396,8): run-time error JS1004: Expected ';'
(7397,7-8): run-time error JS1195: Expected expression: )
(7426,65-66): run-time error JS1195: Expected expression: .
(7426,78-79): run-time error JS1003: Expected ':': )
(7427,9-10): run-time error JS1009: Expected '}': s
(7427,9-10): run-time error JS1006: Expected ')': s
(7431,6-10): run-time error JS1006: Expected ')': else
(7433,66-67): run-time error JS1195: Expected expression: .
(7433,79-80): run-time error JS1003: Expected ':': )
(7434,8-9): run-time error JS1009: Expected '}': s
(7434,8-9): run-time error JS1006: Expected ')': s
(7437,6): run-time error JS1004: Expected ';'
(7437,6-7): run-time error JS1195: Expected expression: )
(7441,65-66): run-time error JS1195: Expected expression: .
(7441,78-79): run-time error JS1003: Expected ':': )
(7442,7-8): run-time error JS1009: Expected '}': s
(7442,7-8): run-time error JS1006: Expected ')': s
(7446,5-6): run-time error JS1002: Syntax error: }
(7465,4-5): run-time error JS1002: Syntax error: }
(7465,5-6): run-time error JS1195: Expected expression: ,
(7466,20-21): run-time error JS1010: Expected identifier: (
(7470,3-4): run-time error JS1002: Syntax error: }
(7470,4-5): run-time error JS1195: Expected expression: )
(7471,2-3): run-time error JS1002: Syntax error: }
(7994,1-2): run-time error JS1002: Syntax error: }
 */
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
 * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-flexbox_legacy-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
 */
;window.Modernizr=function(a,b,c){function C(a){i.cssText=a}function D(a,b){return C(m.join(a+";")+(b||""))}function E(a,b){return typeof a===b}function F(a,b){return!!~(""+a).indexOf(b)}function G(a,b){for(var d in a){var e=a[d];if(!F(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function H(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:E(f,"function")?f.bind(d||b):f}return!1}function I(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+o.join(d+" ")+d).split(" ");return E(b,"string")||E(b,"undefined")?G(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),H(e,b,c))}function J(){e.input=function(c){for(var d=0,e=c.length;d<e;d++)t[c[d]]=c[d]in j;return t.list&&(t.list=!!b.createElement("datalist")&&!!a.HTMLDataListElement),t}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),e.inputtypes=function(a){for(var d=0,e,g,h,i=a.length;d<i;d++)j.setAttribute("type",g=a[d]),e=j.type!=="text",e&&(j.value=k,j.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(g)&&j.style.WebkitAppearance!==c?(f.appendChild(j),h=b.defaultView,e=h.getComputedStyle&&h.getComputedStyle(j,null).WebkitAppearance!=="textfield"&&j.offsetHeight!==0,f.removeChild(j)):/^(search|tel)$/.test(g)||(/^(url|email)$/.test(g)?e=j.checkValidity&&j.checkValidity()===!1:e=j.value!=k)),s[a[d]]=!!e;return s}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var d="2.6.2",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j=b.createElement("input"),k=":)",l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n="Webkit Moz O ms",o=n.split(" "),p=n.toLowerCase().split(" "),q={svg:"http://www.w3.org/2000/svg"},r={},s={},t={},u=[],v=u.slice,w,x=function(a,c,d,e){var h,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),l.appendChild(j);return h=["&#173;",'<style id="s',g,'">',a,"</style>"].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},y=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return x("@media "+b+" { #"+g+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},z=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=E(e[d],"function"),E(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),A={}.hasOwnProperty,B;!E(A,"undefined")&&!E(A.call,"undefined")?B=function(a,b){return A.call(a,b)}:B=function(a,b){return b in a&&E(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=v.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(v.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(v.call(arguments)))};return e}),r.flexbox=function(){return I("flexWrap")},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!E(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:x(["@media (",m.join("touch-enabled),("),g,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},r.geolocation=function(){return"geolocation"in navigator},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){return!!a.openDatabase},r.indexedDB=function(){return!!I("indexedDB",a)},r.hashchange=function(){return z("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},r.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},r.rgba=function(){return C("background-color:rgba(150,255,150,.5)"),F(i.backgroundColor,"rgba")},r.hsla=function(){return C("background-color:hsla(120,40%,100%,.5)"),F(i.backgroundColor,"rgba")||F(i.backgroundColor,"hsla")},r.multiplebgs=function(){return C("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(i.background)},r.backgroundsize=function(){return I("backgroundSize")},r.borderimage=function(){return I("borderImage")},r.borderradius=function(){return I("borderRadius")},r.boxshadow=function(){return I("boxShadow")},r.textshadow=function(){return b.createElement("div").style.textShadow===""},r.opacity=function(){return D("opacity:.55"),/^0.55$/.test(i.opacity)},r.cssanimations=function(){return I("animationName")},r.csscolumns=function(){return I("columnCount")},r.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return C((a+"-webkit- ".split(" ").join(b+a)+m.join(c+a)).slice(0,-a.length)),F(i.backgroundImage,"gradient")},r.cssreflections=function(){return I("boxReflect")},r.csstransforms=function(){return!!I("transform")},r.csstransitions=function(){return I("transition")},r.fontface=function(){var a;return x('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},r.generatedcontent=function(){var a;return x(["#",g,"{font:0/0 a}#",g,':after{content:"',k,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},r.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},r.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},r.localstorage=function(){try{return localStorage.setItem(g,g),localStorage.removeItem(g),!0}catch(a){return!1}},r.sessionstorage=function(){try{return sessionStorage.setItem(g,g),sessionStorage.removeItem(g),!0}catch(a){return!1}},r.webworkers=function(){return!!a.Worker},r.applicationcache=function(){return!!a.applicationCache},r.svg=function(){return!!b.createElementNS&&!!b.createElementNS(q.svg,"svg").createSVGRect},r.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="<svg/>",(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(l.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(l.call(b.createElementNS(q.svg,"clipPath")))};for(var K in r)B(r,K)&&(w=K.toLowerCase(),e[w]=r[K](),u.push((e[w]?"":"no-")+w));return e.input||J(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)B(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof enableClasses!="undefined"&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},C(""),h=j=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e<g;e++)d.createElement(f[e]);return d}function p(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return r.shivMethods?n(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+l().join().replace(/\w+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(r,b.frag)}function q(a){a||(a=b);var c=m(a);return r.shivCSS&&!f&&!c.hasCSS&&(c.hasCSS=!!k(a,"article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}")),j||p(a,c),a}var c=a.html5||{},d=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,e=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,f,g="_html5shiv",h=0,i={},j;(function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.mq=y,e.hasEvent=z,e.testProp=function(a){return G([a])},e.testAllProps=I,e.testStyles=x,e.prefixed=function(a,b,c){return b?I(a,b,c):I(a,"pfx")},e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};;
Modernizr.addTest("csscalc",function(){var n="width:",t=document.createElement("div");return t.style.cssText=n+Modernizr._prefixes.join("calc(10px);"+n),!!t.style.length});Modernizr.addTest("svganimation",function(){return!/msie/.test(navigator.userAgent.toLowerCase())&&!/trident/.test(navigator.userAgent.toLowerCase())});;
// Declare namespaces
var Global = Global || {};
Global.Controls = Global.Controls || {};

//Create classes
Global.Controls.HeaderMenu = function (args)
{
	//#region Properties
	var impersonatePublicUser = args.impersonatePublicUser;
	var module = args.module;
	var entityId = args.entityId;
	var recycleBin = args.recycleBin;
	var selectLanguageLabelText = args.selectLanguageLabelText;
	var feedbackData = args.feedbackData;

	var selectedCulture = args.selectedCulture;
	var availableCultures = args.availableCultures;

	var cultureSelectorContainerClientId = 'CultureSelectorContainer';
	var cultureSelectorListClientId = 'CultureSelectorList';

	var signInLocalization = args.signInLocalization;
	//#endregion

	//#region Event Handlers
	var cultureDisplayClick = function ()
	{
		createCultureSelector();
	};

	var cultureSelectorMouseLeave = function ()
	{
		destroyCultureSelector();
	};

	var cultureSelectorItemClick = function (e)
	{
		CivicWeb.Common.Instrumentation.recordAction('Changed the selected language - header.js')
			.then(function ()
			{
				var listItem = $(e.target).closest('li');
				CivicWeb.Common.Cookie.set('Culture', listItem.attr('data-culture'), 365).then(function ()
				{
					destroyCultureSelector();
					window.location.href = window.location.href;
				});
			});
	};

	var dropDownToggleOver = function ()
	{
		tooglePdfIframes(false);
	};

	var dropDownToggleOut = function ()
	{
		if ($('.dropdown.open').length === 0)
		{
			tooglePdfIframes(true);
		}
	};

	var feedBackClosed = function (e)
	{
		tooglePdfIframes(true);
		e.preventDefault();
	};

	var videoGuideLinkClick = function (e)
	{
		var link = $(e.target);
		var videoWindow = window.open('', 'VideoGuide', 'status=0, height=338, width=575, titlebar=0, toolbar=0');
		videoWindow.document.write('<video id=\'video-guide\' style=\'width: 100%;\' controls autoplay preload><source src=\'' + link.attr('href') + '\' type=\'video/mp4\'></video>');
		e.preventDefault();
	};

	var thirPartyLinkClick = function ()
	{
		CivicWeb.Common.Instrumentation.recordAction($(this).text() + ' thirdparty header link - header.js');
	};
	//#endregion

	//#region Methods
	var loadCultures = function ()
	{
		var $cultureSelector = $('.culture-selector');

		if (availableCultures.length > 1 && $cultureSelector.length > 0 && $cultureSelector.html().indexOf('\u25bc') === -1)
		{
			$cultureSelector.append(' &#9660;').off('click').on('click', cultureDisplayClick);
		}
	};

	var createCultureSelector = function ()
	{
		var $cultureSelector = $('.culture-selector');
		var position = $cultureSelector.offset();

		//Selector container
		var cultureSelectorContainer = $('<div></div>').attr({ 'id': cultureSelectorContainerClientId, 'class': 'culture-selector-container' }).css({ 'left': position.left.toString() + 'px', 'top': position.top.toString() + 'px' }).on('mouseleave', cultureSelectorMouseLeave);

		//Selector label
		cultureSelectorContainer.append($('<label></label>').attr({ 'for': cultureSelectorListClientId }).text(selectLanguageLabelText));

		//Culture list
		var list = $('<ul></ul>').attr({ 'id': cultureSelectorListClientId });
		cultureSelectorContainer.append(list);
		for (var index = 0; index < availableCultures.length; index++)
		{
			var listItem = $('<li></li>').attr({ 'data-culture': availableCultures[index].name }).on('click', cultureSelectorItemClick).text(availableCultures[index].nativeName);
			if (availableCultures[index].name === selectedCulture)
			{
				listItem.css({ 'font-weight': 'bold' });
			}
			list.append(listItem);
		}

		$('body').append(cultureSelectorContainer);

		var displayPadding = $cultureSelector.outerWidth() - $cultureSelector.width();
		var selectorPadding = cultureSelectorContainer.outerWidth() - cultureSelectorContainer.width();
		cultureSelectorContainer.css({ 'min-width': ($cultureSelector.width() + (displayPadding - selectorPadding)).toString() + 'px' });
	};

	var destroyCultureSelector = function ()
	{
		$(document.getElementById(cultureSelectorContainerClientId)).remove();
	};

	var loadSearchbar = function myfunction()
	{
		var $searchTxtBoxControl = $('.search-text-box:not([id="ctl00_MainContent_SearchTextBox"]):not(.large-text-box)');

		$searchTxtBoxControl.keydown(function (e)
		{
			if (e.which === 13)
			{
				search();
				e.preventDefault();
			}

			$(this).addClass('search-text-box-expand', 'slow');
		});

		$searchTxtBoxControl.blur(function ()
		{
			$(this).removeClass('search-text-box-expand', 'slow');
		});
	};
	var viewModeMenuLinkClick = function (e)
	{
		$.ajax({
			url: '/Services/SecurityService.svc/security/users/impersonatepublic?impersonate=' + (!impersonatePublicUser ? 'True' : 'False'),
			contentType: 'application/json', dataType: 'json', async: true, type: 'POST', timeout: 30000, data: null,
			success: function (data)
			{
				if (data.Result)
				{
					window.location.href = window.location.href;
				}
			},
			error: function ()
			{
			}
		});

		e.preventDefault();
	};
	var logOffUser = function ()
	{		
		CivicWeb.Common.ConcurrentEditors.signOut();
		$.ajax({
			url: '/Services/SecurityService.svc/security/logoff',
			contentType: 'application/json', dataType: 'json', async: true, type: 'POST', timeout: 30000, data: null,
			success: function (data)
			{
				if (data.Result)
				{
					if (window.location.href.indexOf('notices=True') >= 0 || window.location.href.indexOf('securityPolicy=True') >= 0)
					{
						window.location.href = window.location.href.replace('?notices=True', '').replace('&notices=True', '').replace('?securityPolicy=True', '').replace('&securityPolicy=True', '');
					}
					else
					{
						window.location.reload();
					}					
				}				
			},
			error: function ()
			{
			}
		});
	};
	var search = function ()
	{
		var searchButtonId = $('.search-button').attr('id');
		var searchText = $('.search-text-box').val();
		if (module === 'Portal')
		{
			window.location.href = '/Portal/VirtualLibrary.aspx?SearchText=' + searchText;
		}
		else if (module === 'DocumentCenter')
		{
			window.location.href = '/filepro/documents/search?keywords=' + searchText + (entityId > 0 ? '&location=' + entityId : '') + (recycleBin ? '&deleted=True' : '');
		}
		else if ('ActionTracking' === module)
		{
			window.location.href = '/items/search?keywords=' + searchText + (recycleBin ? '&deleted=True' : '');
		}
		else
		{
			window.__doPostBack(searchButtonId, searchText);
		}
		return false;
	};
	this.OnSearchButtonClick = function ()
	{
		return search();
	};
	var tooglePdfIframes = function (show)
	{
		var feedBackOpen = $(document.getElementById('FeedbackModal')).length > 0;
		var folderList = $(document.getElementById('preview-folder-list')).attr('data-show') === 'true';

		if (!feedBackOpen && !folderList)
		{
			if (show)
			{
				$('iframe:not([data-hidden="True"])').removeClass('invisible hidden');
			}
			else
			{
				$('iframe:not([data-hidden="True"])').filter(function ()
				{
					var iframe = $(this);
					if (iframe.attr('src') != null && iframe.attr('src').indexOf('.pdf') > -1)
					{
						return iframe;
					}

					return null;
				}).addClass('invisible hidden');
			}
		}

	};
	//#endregion

	//#region Feeback
	var feedbackModal;

	var openFeedbackModal = function ()
	{
		tooglePdfIframes(false);
		feedbackModal.open();
		$('.feedback-close').off('click', feedBackClosed).on('click', feedBackClosed);
	}; //#endregion

	(function ()
	{
		$('.view-mode').off('click').on('click', viewModeMenuLinkClick);
		$('.user-sign-out').off('click').on('click', logOffUser);
		$('.user-feedback').off('click').on('click', openFeedbackModal);
		$('.dropdown-toggle:not(.show-pdf-iframe)').off('mouseover').off('mouseout').on('mouseover', dropDownToggleOver).on('mouseout', dropDownToggleOut);
		$('.dropdown-menu:not(.show-pdf-iframe)').off('mouseenter').off('mouseleave').on('mouseenter', dropDownToggleOver).on('mouseleave', dropDownToggleOut);
		$('#header-help-video').off('click').on('click', videoGuideLinkClick);

		loadCultures();
		loadSearchbar();

		CivicWeb.Common.SignIn.load({ clientId: 'logOn', signInButton: $('.user-sign-in'), localization: signInLocalization });

		feedbackModal = window.Feedback(feedbackData);
		$('ul.nav li.dropdown').hover(function ()
		{
			$(this).find('.dropdown-menu').stop(true, true).delay(0).fadeIn(5);
		}, function ()
			{
				if (!$(this).hasClass('open'))
				{
					$(this).find('.dropdown-menu').stop(true, true).delay(250).fadeOut(5);
				}
			});

		$('ul.nav li.dropdown').click(function ()
		{
			$('ul.nav li.dropdown').not(this).find('.dropdown-menu').stop(true, true).delay(0).fadeOut(5);
		});

		var thirdPartyLinks = $('#header-links').closest('li.dropdown').find('a:not(.dropdown-toggle)');
		if (thirdPartyLinks && thirdPartyLinks.length)
		{
			thirdPartyLinks.off('click', thirPartyLinkClick).on('click', thirPartyLinkClick);
		}
	})();

	// Fixes Jquery update for tool tips
	$('#header-search').find("[title-tootip]").each(function (i, e) {
		var tag = $(e);
		if (tag.is("[title]") === false) { tag.attr("title", ""); }
	});

	$('#header-search').children().tooltip({
		delay: { show: 300, hide: 150 }, placement: 'auto', trigger: 'hover', content: function () { return this.getAttribute("title-tootip"); }
	});

};

//Objects
Global.Controls.HeaderMenus = {
	//Properties
	instance: null,

	//Methods
	createInstance: function (args)
	{
		if (this.instance)
		{
			delete this.instance;
		}
		this.instance = new Global.Controls.HeaderMenu(args);
	},

	//Events
	Events: {
		OnSearchButtonClick: function ()
		{
			Global.Controls.HeaderMenus.instance.OnSearchButtonClick();
		}
	}
};
;
/*!
 * Bootstrap v3.4.1 (https://getbootstrap.com/)
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under the MIT license
 */
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");!function(t){"use strict";var e=jQuery.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||3<e[0])throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(),function(n){"use strict";n.fn.emulateTransitionEnd=function(t){var e=!1,i=this;n(this).one("bsTransitionEnd",function(){e=!0});return setTimeout(function(){e||n(i).trigger(n.support.transition.end)},t),this},n(function(){n.support.transition=function o(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(t.style[i]!==undefined)return{end:e[i]};return!1}(),n.support.transition&&(n.event.special.bsTransitionEnd={bindType:n.support.transition.end,delegateType:n.support.transition.end,handle:function(t){if(n(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(s){"use strict";var e='[data-dismiss="alert"]',a=function(t){s(t).on("click",e,this.close)};a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.close=function(t){var e=s(this),i=e.attr("data-target");i||(i=(i=e.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),i="#"===i?[]:i;var o=s(document).find(i);function n(){o.detach().trigger("closed.bs.alert").remove()}t&&t.preventDefault(),o.length||(o=e.closest(".alert")),o.trigger(t=s.Event("close.bs.alert")),t.isDefaultPrevented()||(o.removeClass("in"),s.support.transition&&o.hasClass("fade")?o.one("bsTransitionEnd",n).emulateTransitionEnd(a.TRANSITION_DURATION):n())};var t=s.fn.alert;s.fn.alert=function o(i){return this.each(function(){var t=s(this),e=t.data("bs.alert");e||t.data("bs.alert",e=new a(this)),"string"==typeof i&&e[i].call(t)})},s.fn.alert.Constructor=a,s.fn.alert.noConflict=function(){return s.fn.alert=t,this},s(document).on("click.bs.alert.data-api",e,a.prototype.close)}(jQuery),function(s){"use strict";var n=function(t,e){this.$element=s(t),this.options=s.extend({},n.DEFAULTS,e),this.isLoading=!1};function i(o){return this.each(function(){var t=s(this),e=t.data("bs.button"),i="object"==typeof o&&o;e||t.data("bs.button",e=new n(this,i)),"toggle"==o?e.toggle():o&&e.setState(o)})}n.VERSION="3.4.1",n.DEFAULTS={loadingText:"loading..."},n.prototype.setState=function(t){var e="disabled",i=this.$element,o=i.is("input")?"val":"html",n=i.data();t+="Text",null==n.resetText&&i.data("resetText",i[o]()),setTimeout(s.proxy(function(){i[o](null==n[t]?this.options[t]:n[t]),"loadingText"==t?(this.isLoading=!0,i.addClass(e).attr(e,e).prop(e,!0)):this.isLoading&&(this.isLoading=!1,i.removeClass(e).removeAttr(e).prop(e,!1))},this),0)},n.prototype.toggle=function(){var t=!0,e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var i=this.$element.find("input");"radio"==i.prop("type")?(i.prop("checked")&&(t=!1),e.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==i.prop("type")&&(i.prop("checked")!==this.$element.hasClass("active")&&(t=!1),this.$element.toggleClass("active")),i.prop("checked",this.$element.hasClass("active")),t&&i.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var t=s.fn.button;s.fn.button=i,s.fn.button.Constructor=n,s.fn.button.noConflict=function(){return s.fn.button=t,this},s(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(t){var e=s(t.target).closest(".btn");i.call(e,"toggle"),s(t.target).is('input[type="radio"], input[type="checkbox"]')||(t.preventDefault(),e.is("input,button")?e.trigger("focus"):e.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(t){s(t.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(t.type))})}(jQuery),function(p){"use strict";var c=function(t,e){this.$element=p(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=e,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",p.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",p.proxy(this.pause,this)).on("mouseleave.bs.carousel",p.proxy(this.cycle,this))};function r(n){return this.each(function(){var t=p(this),e=t.data("bs.carousel"),i=p.extend({},c.DEFAULTS,t.data(),"object"==typeof n&&n),o="string"==typeof n?n:i.slide;e||t.data("bs.carousel",e=new c(this,i)),"number"==typeof n?e.to(n):o?e[o]():i.interval&&e.pause().cycle()})}c.VERSION="3.4.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(t){if(!/input|textarea/i.test(t.target.tagName)){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()}},c.prototype.cycle=function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(p.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},c.prototype.getItemForDirection=function(t,e){var i=this.getItemIndex(e);if(("prev"==t&&0===i||"next"==t&&i==this.$items.length-1)&&!this.options.wrap)return e;var o=(i+("prev"==t?-1:1))%this.$items.length;return this.$items.eq(o)},c.prototype.to=function(t){var e=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(t>this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(i<t?"next":"prev",this.$items.eq(t))},c.prototype.pause=function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&p.support.transition&&(this.$element.trigger(p.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(t,e){var i=this.$element.find(".item.active"),o=e||this.getItemForDirection(t,i),n=this.interval,s="next"==t?"left":"right",a=this;if(o.hasClass("active"))return this.sliding=!1;var r=o[0],l=p.Event("slide.bs.carousel",{relatedTarget:r,direction:s});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,n&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var h=p(this.$indicators.children()[this.getItemIndex(o)]);h&&h.addClass("active")}var d=p.Event("slid.bs.carousel",{relatedTarget:r,direction:s});return p.support.transition&&this.$element.hasClass("slide")?(o.addClass(t),"object"==typeof o&&o.length&&o[0].offsetWidth,i.addClass(s),o.addClass(s),i.one("bsTransitionEnd",function(){o.removeClass([t,s].join(" ")).addClass("active"),i.removeClass(["active",s].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger(d)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(i.removeClass("active"),o.addClass("active"),this.sliding=!1,this.$element.trigger(d)),n&&this.cycle(),this}};var t=p.fn.carousel;p.fn.carousel=r,p.fn.carousel.Constructor=c,p.fn.carousel.noConflict=function(){return p.fn.carousel=t,this};var e=function(t){var e=p(this),i=e.attr("href");i&&(i=i.replace(/.*(?=#[^\s]+$)/,""));var o=e.attr("data-target")||i,n=p(document).find(o);if(n.hasClass("carousel")){var s=p.extend({},n.data(),e.data()),a=e.attr("data-slide-to");a&&(s.interval=!1),r.call(n,s),a&&n.data("bs.carousel").to(a),t.preventDefault()}};p(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),p(window).on("load",function(){p('[data-ride="carousel"]').each(function(){var t=p(this);r.call(t,t.data())})})}(jQuery),function(a){"use strict";var r=function(t,e){this.$element=a(t),this.options=a.extend({},r.DEFAULTS,e),this.$trigger=a('[data-toggle="collapse"][href="#'+t.id+'"],[data-toggle="collapse"][data-target="#'+t.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};function n(t){var e,i=t.attr("data-target")||(e=t.attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"");return a(document).find(i)}function l(o){return this.each(function(){var t=a(this),e=t.data("bs.collapse"),i=a.extend({},r.DEFAULTS,t.data(),"object"==typeof o&&o);!e&&i.toggle&&/show|hide/.test(o)&&(i.toggle=!1),e||t.data("bs.collapse",e=new r(this,i)),"string"==typeof o&&e[o]()})}r.VERSION="3.4.1",r.TRANSITION_DURATION=350,r.DEFAULTS={toggle:!0},r.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},r.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var t,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(t=e.data("bs.collapse"))&&t.transitioning)){var i=a.Event("show.bs.collapse");if(this.$element.trigger(i),!i.isDefaultPrevented()){e&&e.length&&(l.call(e,"hide"),t||e.data("bs.collapse",null));var o=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[o](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var n=function(){this.$element.removeClass("collapsing").addClass("collapse in")[o](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return n.call(this);var s=a.camelCase(["scroll",o].join("-"));this.$element.one("bsTransitionEnd",a.proxy(n,this)).emulateTransitionEnd(r.TRANSITION_DURATION)[o](this.$element[0][s])}}}},r.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var t=a.Event("hide.bs.collapse");if(this.$element.trigger(t),!t.isDefaultPrevented()){var e=this.dimension();this.$element[e](this.$element[e]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var i=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!a.support.transition)return i.call(this);this.$element[e](0).one("bsTransitionEnd",a.proxy(i,this)).emulateTransitionEnd(r.TRANSITION_DURATION)}}},r.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},r.prototype.getParent=function(){return a(document).find(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(t,e){var i=a(e);this.addAriaAndCollapsedClass(n(i),i)},this)).end()},r.prototype.addAriaAndCollapsedClass=function(t,e){var i=t.hasClass("in");t.attr("aria-expanded",i),e.toggleClass("collapsed",!i).attr("aria-expanded",i)};var t=a.fn.collapse;a.fn.collapse=l,a.fn.collapse.Constructor=r,a.fn.collapse.noConflict=function(){return a.fn.collapse=t,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(t){var e=a(this);e.attr("data-target")||t.preventDefault();var i=n(e),o=i.data("bs.collapse")?"toggle":e.data();l.call(i,o)})}(jQuery),function(a){"use strict";var r='[data-toggle="dropdown"]',o=function(t){a(t).on("click.bs.dropdown",this.toggle)};function l(t){var e=t.attr("data-target");e||(e=(e=t.attr("href"))&&/#[A-Za-z]/.test(e)&&e.replace(/.*(?=#[^\s]*$)/,""));var i="#"!==e?a(document).find(e):null;return i&&i.length?i:t.parent()}function s(o){o&&3===o.which||(a(".dropdown-backdrop").remove(),a(r).each(function(){var t=a(this),e=l(t),i={relatedTarget:this};e.hasClass("open")&&(o&&"click"==o.type&&/input|textarea/i.test(o.target.tagName)&&a.contains(e[0],o.target)||(e.trigger(o=a.Event("hide.bs.dropdown",i)),o.isDefaultPrevented()||(t.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",i)))))}))}o.VERSION="3.4.1",o.prototype.toggle=function(t){var e=a(this);if(!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(s(),!o){"ontouchstart"in document.documentElement&&!i.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",s);var n={relatedTarget:this};if(i.trigger(t=a.Event("show.bs.dropdown",n)),t.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),i.toggleClass("open").trigger(a.Event("shown.bs.dropdown",n))}return!1}},o.prototype.keydown=function(t){if(/(38|40|27|32)/.test(t.which)&&!/input|textarea/i.test(t.target.tagName)){var e=a(this);if(t.preventDefault(),t.stopPropagation(),!e.is(".disabled, :disabled")){var i=l(e),o=i.hasClass("open");if(!o&&27!=t.which||o&&27==t.which)return 27==t.which&&i.find(r).trigger("focus"),e.trigger("click");var n=i.find(".dropdown-menu li:not(.disabled):visible a");if(n.length){var s=n.index(t.target);38==t.which&&0<s&&s--,40==t.which&&s<n.length-1&&s++,~s||(s=0),n.eq(s).trigger("focus")}}}};var t=a.fn.dropdown;a.fn.dropdown=function e(i){return this.each(function(){var t=a(this),e=t.data("bs.dropdown");e||t.data("bs.dropdown",e=new o(this)),"string"==typeof i&&e[i].call(t)})},a.fn.dropdown.Constructor=o,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=t,this},a(document).on("click.bs.dropdown.data-api",s).on("click.bs.dropdown.data-api",".dropdown form",function(t){t.stopPropagation()}).on("click.bs.dropdown.data-api",r,o.prototype.toggle).on("keydown.bs.dropdown.data-api",r,o.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",o.prototype.keydown)}(jQuery),function(a){"use strict";var s=function(t,e){this.options=e,this.$body=a(document.body),this.$element=a(t),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.fixedContent=".navbar-fixed-top, .navbar-fixed-bottom",this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};function r(o,n){return this.each(function(){var t=a(this),e=t.data("bs.modal"),i=a.extend({},s.DEFAULTS,t.data(),"object"==typeof o&&o);e||t.data("bs.modal",e=new s(this,i)),"string"==typeof o?e[o](n):i.show&&e.show(n)})}s.VERSION="3.4.1",s.TRANSITION_DURATION=300,s.BACKDROP_TRANSITION_DURATION=150,s.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},s.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},s.prototype.show=function(i){var o=this,t=a.Event("show.bs.modal",{relatedTarget:i});this.$element.trigger(t),this.isShown||t.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(t){a(t.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var t=a.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),t&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:i});t?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(s.TRANSITION_DURATION):o.$element.trigger("focus").trigger(e)}))},s.prototype.hide=function(t){t&&t.preventDefault(),t=a.Event("hide.bs.modal"),this.$element.trigger(t),this.isShown&&!t.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(s.TRANSITION_DURATION):this.hideModal())},s.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(t){document===t.target||this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},s.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},s.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},s.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},s.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},s.prototype.backdrop=function(t){var e=this,i=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var o=a.support.transition&&i;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+i).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(t){this.ignoreBackdropClick?this.ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide())},this)),o&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!t)return;o?this.$backdrop.one("bsTransitionEnd",t).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):t()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var n=function(){e.removeBackdrop(),t&&t()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",n).emulateTransitionEnd(s.BACKDROP_TRANSITION_DURATION):n()}else t&&t()},s.prototype.handleUpdate=function(){this.adjustDialog()},s.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},s.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},s.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth<t,this.scrollbarWidth=this.measureScrollbar()},s.prototype.setScrollbar=function(){var t=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"";var n=this.scrollbarWidth;this.bodyIsOverflowing&&(this.$body.css("padding-right",t+n),a(this.fixedContent).each(function(t,e){var i=e.style.paddingRight,o=a(e).css("padding-right");a(e).data("padding-right",i).css("padding-right",parseFloat(o)+n+"px")}))},s.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad),a(this.fixedContent).each(function(t,e){var i=a(e).data("padding-right");a(e).removeData("padding-right"),e.style.paddingRight=i||""})},s.prototype.measureScrollbar=function(){var t=document.createElement("div");t.className="modal-scrollbar-measure",this.$body.append(t);var e=t.offsetWidth-t.clientWidth;return this.$body[0].removeChild(t),e};var t=a.fn.modal;a.fn.modal=r,a.fn.modal.Constructor=s,a.fn.modal.noConflict=function(){return a.fn.modal=t,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(t){var e=a(this),i=e.attr("href"),o=e.attr("data-target")||i&&i.replace(/.*(?=#[^\s]+$)/,""),n=a(document).find(o),s=n.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(i)&&i},n.data(),e.data());e.is("a")&&t.preventDefault(),n.one("show.bs.modal",function(t){t.isDefaultPrevented()||n.one("hidden.bs.modal",function(){e.is(":visible")&&e.trigger("focus")})}),r.call(n,s,this)})}(jQuery),function(g){"use strict";var o=["sanitize","whiteList","sanitizeFn"],a=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],t={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},r=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,l=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function u(t,e){var i=t.nodeName.toLowerCase();if(-1!==g.inArray(i,e))return-1===g.inArray(i,a)||Boolean(t.nodeValue.match(r)||t.nodeValue.match(l));for(var o=g(e).filter(function(t,e){return e instanceof RegExp}),n=0,s=o.length;n<s;n++)if(i.match(o[n]))return!0;return!1}function n(t,e,i){if(0===t.length)return t;if(i&&"function"==typeof i)return i(t);if(!document.implementation||!document.implementation.createHTMLDocument)return t;var o=document.implementation.createHTMLDocument("sanitization");o.body.innerHTML=t;for(var n=g.map(e,function(t,e){return e}),s=g(o.body).find("*"),a=0,r=s.length;a<r;a++){var l=s[a],h=l.nodeName.toLowerCase();if(-1!==g.inArray(h,n))for(var d=g.map(l.attributes,function(t){return t}),p=[].concat(e["*"]||[],e[h]||[]),c=0,f=d.length;c<f;c++)u(d[c],p)||l.removeAttribute(d[c].nodeName);else l.parentNode.removeChild(l)}return o.body.innerHTML}var m=function(t,e){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",t,e)};m.VERSION="3.4.1",m.TRANSITION_DURATION=150,m.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:t},m.prototype.init=function(t,e,i){if(this.enabled=!0,this.type=t,this.$element=g(e),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var o=this.options.trigger.split(" "),n=o.length;n--;){var s=o[n];if("click"==s)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=s){var a="hover"==s?"mouseenter":"focusin",r="hover"==s?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(r+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},m.prototype.getDefaults=function(){return m.DEFAULTS},m.prototype.getOptions=function(t){var e=this.$element.data();for(var i in e)e.hasOwnProperty(i)&&-1!==g.inArray(i,o)&&delete e[i];return(t=g.extend({},this.getDefaults(),e,t)).delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.sanitize&&(t.template=n(t.template,t.whiteList,t.sanitizeFn)),t},m.prototype.getDelegateOptions=function(){var i={},o=this.getDefaults();return this._options&&g.each(this._options,function(t,e){o[t]!=e&&(i[t]=e)}),i},m.prototype.enter=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusin"==t.type?"focus":"hover"]=!0),e.tip().hasClass("in")||"in"==e.hoverState)e.hoverState="in";else{if(clearTimeout(e.timeout),e.hoverState="in",!e.options.delay||!e.options.delay.show)return e.show();e.timeout=setTimeout(function(){"in"==e.hoverState&&e.show()},e.options.delay.show)}},m.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},m.prototype.leave=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusout"==t.type?"focus":"hover"]=!1),!e.isInStateTrue()){if(clearTimeout(e.timeout),e.hoverState="out",!e.options.delay||!e.options.delay.hide)return e.hide();e.timeout=setTimeout(function(){"out"==e.hoverState&&e.hide()},e.options.delay.hide)}},m.prototype.show=function(){var t=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var e=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!e)return;var i=this,o=this.tip(),n=this.getUID(this.type);this.setContent(),o.attr("id",n),this.$element.attr("aria-describedby",n),this.options.animation&&o.addClass("fade");var s="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,r=a.test(s);r&&(s=s.replace(a,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(s).data("bs."+this.type,this),this.options.container?o.appendTo(g(document).find(this.options.container)):o.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),h=o[0].offsetWidth,d=o[0].offsetHeight;if(r){var p=s,c=this.getPosition(this.$viewport);s="bottom"==s&&l.bottom+d>c.bottom?"top":"top"==s&&l.top-d<c.top?"bottom":"right"==s&&l.right+h>c.width?"left":"left"==s&&l.left-h<c.left?"right":s,o.removeClass(p).addClass(s)}var f=this.getCalculatedOffset(s,l,h,d);this.applyPlacement(f,s);var u=function(){var t=i.hoverState;i.$element.trigger("shown.bs."+i.type),i.hoverState=null,"out"==t&&i.leave(i)};g.support.transition&&this.$tip.hasClass("fade")?o.one("bsTransitionEnd",u).emulateTransitionEnd(m.TRANSITION_DURATION):u()}},m.prototype.applyPlacement=function(t,e){var i=this.tip(),o=i[0].offsetWidth,n=i[0].offsetHeight,s=parseInt(i.css("margin-top"),10),a=parseInt(i.css("margin-left"),10);isNaN(s)&&(s=0),isNaN(a)&&(a=0),t.top+=s,t.left+=a,g.offset.setOffset(i[0],g.extend({using:function(t){i.css({top:Math.round(t.top),left:Math.round(t.left)})}},t),0),i.addClass("in");var r=i[0].offsetWidth,l=i[0].offsetHeight;"top"==e&&l!=n&&(t.top=t.top+n-l);var h=this.getViewportAdjustedDelta(e,t,r,l);h.left?t.left+=h.left:t.top+=h.top;var d=/top|bottom/.test(e),p=d?2*h.left-o+r:2*h.top-n+l,c=d?"offsetWidth":"offsetHeight";i.offset(t),this.replaceArrow(p,i[0][c],d)},m.prototype.replaceArrow=function(t,e,i){this.arrow().css(i?"left":"top",50*(1-t/e)+"%").css(i?"top":"left","")},m.prototype.setContent=function(){var t=this.tip(),e=this.getTitle();this.options.html?(this.options.sanitize&&(e=n(e,this.options.whiteList,this.options.sanitizeFn)),t.find(".tooltip-inner").html(e)):t.find(".tooltip-inner").text(e),t.removeClass("fade in top bottom left right")},m.prototype.hide=function(t){var e=this,i=g(this.$tip),o=g.Event("hide.bs."+this.type);function n(){"in"!=e.hoverState&&i.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),t&&t()}if(this.$element.trigger(o),!o.isDefaultPrevented())return i.removeClass("in"),g.support.transition&&i.hasClass("fade")?i.one("bsTransitionEnd",n).emulateTransitionEnd(m.TRANSITION_DURATION):n(),this.hoverState=null,this},m.prototype.fixTitle=function(){var t=this.$element;(t.attr("title")||"string"!=typeof t.attr("data-original-title"))&&t.attr("data-original-title",t.attr("title")||"").attr("title","")},m.prototype.hasContent=function(){return this.getTitle()},m.prototype.getPosition=function(t){var e=(t=t||this.$element)[0],i="BODY"==e.tagName,o=e.getBoundingClientRect();null==o.width&&(o=g.extend({},o,{width:o.right-o.left,height:o.bottom-o.top}));var n=window.SVGElement&&e instanceof window.SVGElement,s=i?{top:0,left:0}:n?null:t.offset(),a={scroll:i?document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop()},r=i?{width:g(window).width(),height:g(window).height()}:null;return g.extend({},o,a,r,s)},m.prototype.getCalculatedOffset=function(t,e,i,o){return"bottom"==t?{top:e.top+e.height,left:e.left+e.width/2-i/2}:"top"==t?{top:e.top-o,left:e.left+e.width/2-i/2}:"left"==t?{top:e.top+e.height/2-o/2,left:e.left-i}:{top:e.top+e.height/2-o/2,left:e.left+e.width}},m.prototype.getViewportAdjustedDelta=function(t,e,i,o){var n={top:0,left:0};if(!this.$viewport)return n;var s=this.options.viewport&&this.options.viewport.padding||0,a=this.getPosition(this.$viewport);if(/right|left/.test(t)){var r=e.top-s-a.scroll,l=e.top+s-a.scroll+o;r<a.top?n.top=a.top-r:l>a.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;h<a.left?n.left=a.left-h:d>a.right&&(n.left=a.left+a.width-d)}return n},m.prototype.getTitle=function(){var t=this.$element,e=this.options;return t.attr("data-original-title")||("function"==typeof e.title?e.title.call(t[0]):e.title)},m.prototype.getUID=function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},m.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},m.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},m.prototype.enable=function(){this.enabled=!0},m.prototype.disable=function(){this.enabled=!1},m.prototype.toggleEnabled=function(){this.enabled=!this.enabled},m.prototype.toggle=function(t){var e=this;t&&((e=g(t.currentTarget).data("bs."+this.type))||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e))),t?(e.inState.click=!e.inState.click,e.isInStateTrue()?e.enter(e):e.leave(e)):e.tip().hasClass("in")?e.leave(e):e.enter(e)},m.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})},m.prototype.sanitizeHtml=function(t){return n(t,this.options.whiteList,this.options.sanitizeFn)};var e=g.fn.tooltip;g.fn.tooltip=function i(o){return this.each(function(){var t=g(this),e=t.data("bs.tooltip"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.tooltip",e=new m(this,i)),"string"==typeof o&&e[o]())})},g.fn.tooltip.Constructor=m,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=e,this}}(jQuery),function(n){"use strict";var s=function(t,e){this.init("popover",t,e)};if(!n.fn.tooltip)throw new Error("Popover requires tooltip.js");s.VERSION="3.4.1",s.DEFAULTS=n.extend({},n.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),((s.prototype=n.extend({},n.fn.tooltip.Constructor.prototype)).constructor=s).prototype.getDefaults=function(){return s.DEFAULTS},s.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();if(this.options.html){var o=typeof i;this.options.sanitize&&(e=this.sanitizeHtml(e),"string"===o&&(i=this.sanitizeHtml(i))),t.find(".popover-title").html(e),t.find(".popover-content").children().detach().end()["string"===o?"html":"append"](i)}else t.find(".popover-title").text(e),t.find(".popover-content").children().detach().end().text(i);t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},s.prototype.hasContent=function(){return this.getTitle()||this.getContent()},s.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},s.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var t=n.fn.popover;n.fn.popover=function e(o){return this.each(function(){var t=n(this),e=t.data("bs.popover"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.popover",e=new s(this,i)),"string"==typeof o&&e[o]())})},n.fn.popover.Constructor=s,n.fn.popover.noConflict=function(){return n.fn.popover=t,this}}(jQuery),function(s){"use strict";function n(t,e){this.$body=s(document.body),this.$scrollElement=s(t).is(document.body)?s(window):s(t),this.options=s.extend({},n.DEFAULTS,e),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",s.proxy(this.process,this)),this.refresh(),this.process()}function e(o){return this.each(function(){var t=s(this),e=t.data("bs.scrollspy"),i="object"==typeof o&&o;e||t.data("bs.scrollspy",e=new n(this,i)),"string"==typeof o&&e[o]()})}n.VERSION="3.4.1",n.DEFAULTS={offset:10},n.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},n.prototype.refresh=function(){var t=this,o="offset",n=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),s.isWindow(this.$scrollElement[0])||(o="position",n=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var t=s(this),e=t.data("target")||t.attr("href"),i=/^#./.test(e)&&s(e);return i&&i.length&&i.is(":visible")&&[[i[o]().top+n,e]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},n.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),o<=e)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e<n[0])return this.activeTarget=null,this.clear();for(t=n.length;t--;)a!=s[t]&&e>=n[t]&&(n[t+1]===undefined||e<n[t+1])&&this.activate(s[t])},n.prototype.activate=function(t){this.activeTarget=t,this.clear();var e=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',i=s(e).parents("li").addClass("active");i.parent(".dropdown-menu").length&&(i=i.closest("li.dropdown").addClass("active")),i.trigger("activate.bs.scrollspy")},n.prototype.clear=function(){s(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var t=s.fn.scrollspy;s.fn.scrollspy=e,s.fn.scrollspy.Constructor=n,s.fn.scrollspy.noConflict=function(){return s.fn.scrollspy=t,this},s(window).on("load.bs.scrollspy.data-api",function(){s('[data-spy="scroll"]').each(function(){var t=s(this);e.call(t,t.data())})})}(jQuery),function(r){"use strict";var a=function(t){this.element=r(t)};function e(i){return this.each(function(){var t=r(this),e=t.data("bs.tab");e||t.data("bs.tab",e=new a(this)),"string"==typeof i&&e[i]()})}a.VERSION="3.4.1",a.TRANSITION_DURATION=150,a.prototype.show=function(){var t=this.element,e=t.closest("ul:not(.dropdown-menu)"),i=t.data("target");if(i||(i=(i=t.attr("href"))&&i.replace(/.*(?=#[^\s]*$)/,"")),!t.parent("li").hasClass("active")){var o=e.find(".active:last a"),n=r.Event("hide.bs.tab",{relatedTarget:t[0]}),s=r.Event("show.bs.tab",{relatedTarget:o[0]});if(o.trigger(n),t.trigger(s),!s.isDefaultPrevented()&&!n.isDefaultPrevented()){var a=r(document).find(i);this.activate(t.closest("li"),e),this.activate(a,a.parent(),function(){o.trigger({type:"hidden.bs.tab",relatedTarget:t[0]}),t.trigger({type:"shown.bs.tab",relatedTarget:o[0]})})}}},a.prototype.activate=function(t,e,i){var o=e.find("> .active"),n=i&&r.support.transition&&(o.length&&o.hasClass("fade")||!!e.find("> .fade").length);function s(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),t.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),n?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu").length&&t.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),i&&i()}o.length&&n?o.one("bsTransitionEnd",s).emulateTransitionEnd(a.TRANSITION_DURATION):s(),o.removeClass("in")};var t=r.fn.tab;r.fn.tab=e,r.fn.tab.Constructor=a,r.fn.tab.noConflict=function(){return r.fn.tab=t,this};var i=function(t){t.preventDefault(),e.call(r(this),"show")};r(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery),function(l){"use strict";var h=function(t,e){this.options=l.extend({},h.DEFAULTS,e);var i=this.options.target===h.DEFAULTS.target?l(this.options.target):l(document).find(this.options.target);this.$target=i.on("scroll.bs.affix.data-api",l.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",l.proxy(this.checkPositionWithEventLoop,this)),this.$element=l(t),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};function i(o){return this.each(function(){var t=l(this),e=t.data("bs.affix"),i="object"==typeof o&&o;e||t.data("bs.affix",e=new h(this,i)),"string"==typeof o&&e[o]()})}h.VERSION="3.4.1",h.RESET="affix affix-top affix-bottom",h.DEFAULTS={offset:0,target:window},h.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return n<i&&"top";if("bottom"==this.affixed)return null!=i?!(n+this.unpin<=s.top)&&"bottom":!(n+a<=t-o)&&"bottom";var r=null==this.affixed,l=r?n:s.top;return null!=i&&n<=i?"top":null!=o&&t-o<=l+(r?a:e)&&"bottom"},h.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(h.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},h.prototype.checkPositionWithEventLoop=function(){setTimeout(l.proxy(this.checkPosition,this),1)},h.prototype.checkPosition=function(){if(this.$element.is(":visible")){var t=this.$element.height(),e=this.options.offset,i=e.top,o=e.bottom,n=Math.max(l(document).height(),l(document.body).height());"object"!=typeof e&&(o=i=e),"function"==typeof i&&(i=e.top(this.$element)),"function"==typeof o&&(o=e.bottom(this.$element));var s=this.getState(n,t,i,o);if(this.affixed!=s){null!=this.unpin&&this.$element.css("top","");var a="affix"+(s?"-"+s:""),r=l.Event(a+".bs.affix");if(this.$element.trigger(r),r.isDefaultPrevented())return;this.affixed=s,this.unpin="bottom"==s?this.getPinnedOffset():null,this.$element.removeClass(h.RESET).addClass(a).trigger(a.replace("affix","affixed")+".bs.affix")}"bottom"==s&&this.$element.offset({top:n-t-o})}};var t=l.fn.affix;l.fn.affix=i,l.fn.affix.Constructor=h,l.fn.affix.noConflict=function(){return l.fn.affix=t,this},l(window).on("load",function(){l('[data-spy="affix"]').each(function(){var t=l(this),e=t.data();e.offset=e.offset||{},null!=e.offsetBottom&&(e.offset.bottom=e.offsetBottom),null!=e.offsetTop&&(e.offset.top=e.offsetTop),i.call(t,e)})})}(jQuery);;

(function (window, document, undefined)
{
	if (window.Feedback !== undefined)
	{
		return;
	}

	var removeElements = function (remove)
	{
		for (var i = 0, len = remove.length; i < len; i++)
		{
			var item = Array.prototype.pop.call(remove);
			if (item)
			{
				if (item.parentNode !== null)
				{ // check that the item was actually added to DOM
					item.parentNode.removeChild(item);
				}
			}
		}
	},
		emptyElements = function (el)
		{
			var item;
			while (((item = el.firstChild) !== null ? el.removeChild(item) : false)) { }
		},
		element = function (name, text)
		{
			var el = document.createElement(name);
			el.appendChild(document.createTextNode(text));
			return el;
		},
		nextButton,
		h2CIgnore = 'data-html2canvas-ignore',
		modalBody = document.createElement('div');

	var dictionaryToHtml = function (dict)
	{
		var str = '';
		for (var key in dict)
		{
			if (dict.hasOwnProperty(key))
			{
				str += key + ': ' + dict[key] + '<br/>';
			}
		}

		return str;
	};

	var checkUserOs = function ()
	{
		var os = 'unknown';
		var userAgent = navigator.userAgent;
		var clientStrings = [
			{ s: 'Windows 3.11', r: /Win16/ },
			{ s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ },
			{ s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ },
			{ s: 'Windows 98', r: /(Windows 98|Win98)/ },
			{ s: 'Windows CE', r: /Windows CE/ },
			{ s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ },
			{ s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ },
			{ s: 'Windows Server 2003', r: /Windows NT 5.2/ },
			{ s: 'Windows Vista', r: /Windows NT 6.0/ },
			{ s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ },
			{ s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ },
			{ s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ },
			{ s: 'Windows 10', r: /(Windows 10|Windows NT 10|Windows 10.0|Windows NT 10.0)/ },
			{ s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ },
			{ s: 'Windows ME', r: /Windows ME/ },
			{ s: 'Android', r: /Android/ },
			{ s: 'Open BSD', r: /OpenBSD/ },
			{ s: 'Sun OS', r: /SunOS/ },
			{ s: 'Linux', r: /(Linux|X11)/ },
			{ s: 'iOS', r: /(iPhone|iPad|iPod)/ },
			{ s: 'Mac OS X', r: /Mac OS X/ },
			{ s: 'Mac OS', r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ },
			{ s: 'QNX', r: /QNX/ },
			{ s: 'UNIX', r: /UNIX/ },
			{ s: 'BeOS', r: /BeOS/ },
			{ s: 'OS/2', r: /OS\/2/ },
			{ s: 'Search Bot', r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ }
		];
		for (var id in clientStrings)
		{
			if (clientStrings.hasOwnProperty(id))
			{
				var cs = clientStrings[id];
				if (userAgent.match(cs.r))
				{
					return cs.s;
				}
			}
		}
		return '';
	};

	window.Feedback = function (options)
	{
		window.Feedback.options = options = options || {};
		options.describePanel = {};
		options.annotatePanel = {};
		options.reviewPanel = {};
		options.thankYouPanel = {};

		options.descriptonLabel = 'Description';
		options.screenshotLabel = 'Screenshot';

		options.describePanel.descriptionLabel = 'What do you need help with?';
		options.describePanel.annotateLabel = 'Next we\'ll let you select areas of the page related to your description.';

		options.annotatePanel.descriptionLabel = 'Select important information';

		options.reviewPanel.browserInfoLabel = 'Browser Info';
		options.reviewPanel.userInfoLabel = 'User Info';
		options.reviewPanel.pageInfoLabel = 'Page Info';
		options.reviewPanel.creatingImageLabel = 'Creating Image. Please wait...';
		options.localization = options.Localization;

		options.reviewPanel.browserData = dictionaryToHtml(options.BrowserData);
		options.reviewPanel.userData = dictionaryToHtml(options.UserData);
		options.reviewPanel.pageData = dictionaryToHtml(options.PageData);
		options.AgendaFree = options.AgendaFree;

		options.thankYouPanel.descriptionLabel = 'Thank you for your feedback.';

		options.label = options.label || 'Send Feedback';
		options.header = options.header || 'Your Support team are here for you 24/7!';
		options.url = options.Url || '/';

		options.nextLabel = options.nextLabel || 'Continue';
		options.reviewLabel = options.reviewLabel || 'Next Review';
		options.sendLabel = options.sendLabel || 'Send';
		options.closeLabel = options.closeLabel || 'Close';

		options.messageSuccess = options.messageSuccess || 'Thank you, your feedback was sent successfully.';
		options.messageError = options.messageError || 'There was an error sending your feedback. Please contact our Customer Success Team at 1-800-260-7409. ';

		if (options.pages === undefined)
		{
			options.pages = [
				new window.Feedback.Describe(),
				new window.Feedback.Annotate(options),
				new window.Feedback.Review(),
				new window.Feedback.ThankYou()
			];
		}
		var modal;
		var currentPage;
		var glass = document.createElement('div');
		var returnMethods = {

			// open send feedback modal window
			open: function ()
			{
				var len = options.pages.length;
				currentPage = 0;
				for (; currentPage < len; currentPage++)
				{
					// create DOM for each page in the wizard
					if (!(options.pages[currentPage] instanceof window.Feedback.Review))
					{
						options.pages[currentPage].render(options);
					}
				}

				var a = element('a', '×'),
					modalHeader = document.createElement('div'),
					// modal container
					modalFooter = document.createElement('div');

				modal = document.createElement('div');
				modal.id = 'FeedbackModal';
				modal.style.zIndex = '9999';
				glass.id = 'glass';
				glass.style.width = document.body.clientWidth + 'px';
				glass.style.height = document.body.clientHeight + 'px';
				glass.style.top = 0;
				glass.style.left = 0;
				glass.style.position = 'absolute';
				glass.style.backgroundColor = '#333333';
				glass.style.opacity = '0.2';
				document.body.appendChild(glass);

				// modal close button
				a.className = 'feedback-close';
				a.onclick = returnMethods.close;
				a.href = '#';

				// build header element
				modalHeader.appendChild(a);

				var h3 = document.createElement('h3');
				var h3ImgSpan = document.createElement('span');
				h3ImgSpan.className = 'glyphicon glyphicon-info-sign';
				h3.appendChild(h3ImgSpan);
				h3.appendChild(document.createTextNode(' ' + options.header));

				modalHeader.appendChild(h3);
				modalHeader.className = 'feedback-header';

				modalBody.className = 'feedback-body';

				emptyElements(modalBody);
				currentPage = 0;
				modalBody.appendChild(options.pages[currentPage++].dom);

				// Next button
				nextButton = element('button', options.nextLabel);
				nextButton.className = 'feedback-btn';
				nextButton.setAttribute('disabled', 'disabled');
				nextButton.onclick = function ()
				{
					if (currentPage > 0)
					{
						if (options.pages[currentPage - 1] instanceof window.Feedback.Review)
						{
							var obj = new Object();
							obj.ErrorDescription = window.Feedback.Describe.Description.replace(/\n/g, '<br />');
							obj.Image = options.reviewPanel.imageData;
							obj.BrowserData = JSON.stringify(options.BrowserData);
							obj.UserAgent = window.navigator.userAgent;
							obj.OS = checkUserOs();
							obj.UserData = JSON.stringify(options.UserData);
							obj.PageData = JSON.stringify(options.PageData);
							obj.Priority = window.Feedback.Describe.Priority;

							$.ajax({
								url: '/Services/ExceptionsService.svc/userErrorSubmit',
								contentType: 'application/json',
								dataType: 'json',
								async: true,
								type: 'POST',
								cache: false,
								timeout: 45000,
								data: JSON.stringify(obj),
								beforeSend: function ()
								{
									$('#loaderImage').show();
								},
								success: function ()
								{
									$('#loaderImage').hide();
									updateModal();
									$('.feedback-body > div > label').html(options.messageSuccess);
								},
								error: function ()
								{
									$('.feedback-body > div > label').html(options.messageError);
									alert('Failed submission');
								}
							});
						}
						else
						{
							updateModal();
						}
					}
				};

				var updateModal = function ()
				{
					if (options.pages[currentPage - 1].end(modal) === false)
					{
						// page failed validation, cancel onclick
						return;
					}
					emptyElements(modalBody);

					options.pages[currentPage].start(modal, modalHeader, modalFooter, nextButton, options);

					if (options.pages[currentPage] instanceof window.Feedback.Annotate)
					{
						annotate.init('body');
						annotate.show();
					}

					if (options.pages[currentPage] instanceof window.Feedback.Review)
					{
						// create DOM for review page, based on collected data
						options.pages[currentPage].render(modal, options.pages, options);
					}
					// add page DOM to modal
					modalBody.appendChild(options.pages[currentPage++].dom);

					if ($('#accordionInfo').length)
					{
						$('#accordionInfo').accordion({
							collapsible: true,
							active: false
						});
					}

					// if last page, change button label to send
					if (currentPage === len)
					{
						nextButton.firstChild.nodeValue = options.closeLabel;
						nextButton.onclick = returnMethods.close;
					}

					// if next page is review page, change button label
					if (options.pages[currentPage] instanceof window.Feedback.Review)
					{
						nextButton.firstChild.nodeValue = options.reviewLabel;
					}

					if (options.pages[currentPage] instanceof window.Feedback.ThankYou)
					{
						nextButton.firstChild.nodeValue = options.sendLabel;
					}
				};
				modalFooter.className = 'feedback-footer';
				modalFooter.appendChild(nextButton);

				var loaderImage = document.createElement('span');
				loaderImage.id = 'loaderImage';
				loaderImage.style.width = '25px';
				loaderImage.style.height = '25px';
				loaderImage.style.fontSize = '2em';
				loaderImage.style.cssFloat = 'right';
				loaderImage.style.display = 'none';
				loaderImage.innerHTML = '<span class="fa fa-spinner fa-spin"></span>';
				modalFooter.appendChild(loaderImage);

				modal.className = 'feedback-modal';
				modal.setAttribute(h2CIgnore, true); // don't render in html2canvas

				modal.appendChild(modalHeader);
				modal.appendChild(modalBody);
				modal.appendChild(modalFooter);

				document.body.appendChild(modal);
			},

			// close modal window
			close: function ()
			{
				if (annotate.options != undefined)
				{
					annotate.hide();
					annotate.clear();
				}
				// remove feedback elements
				removeElements([modal, glass]);

				// call end event for current page
				if (currentPage > 0)
				{
					options.pages[currentPage - 1].end(modal);
				}

				// call close events for all pages    
				for (var i = 0, len = options.pages.length; i < len; i++)
				{
					options.pages[i].close();
				}

				return false;
			}
		};

		return returnMethods;
	};

	window.Feedback.refreshPriorityOptions = function ()
	{
		return $.ajax({
			url: '/api/settings/fullsupport',
			contentType: 'application/json',
			dataType: 'json',
			async: true,
			type: 'GET',
			cache: false
		}).done(function (data)
		{
			if (data)
			{
				var container = $(document.getElementById('FeedbackModal'));
				container.find('input[type="radio"][name="priority"][value="High"]').removeAttr('disabled').closest('label').css({ 'color': '' }).find('span').text(window.Feedback.options.localization.optionHighPrioritySupport);
				container.find('.upgrade-request').addClass('hidden');

				window.Feedback.options.FullSupport = true;
			}
		});
	};

	window.Feedback.Page = function () { };

	window.Feedback.Page.prototype = {

		render: function (dom)
		{
			this.dom = dom;
		},
		start: function () { },
		close: function () { },
		data: function ()
		{
			// don't collect data from page by default
			return false;
		},
		review: function ()
		{
			return null;
		},
		end: function () { return true; }

	};

	window.Feedback.Describe = function ()
	{
		this.dom = document.createElement('div');
	};

	window.Feedback.Describe.prototype = new window.Feedback.Page();

	window.Feedback.Describe.prototype.render = function (options)
	{
		emptyElements(this.dom);
		if (options.AgendaFree)
		{
			var faqLink = document.createElement('a');
			faqLink.text = options.localization.faq;
			faqLink.href = '/Help/FAQ';
			faqLink.target = '_blank';
			faqLink.className = 'pull-right';
			this.dom.appendChild(faqLink);
			this.dom.appendChild(document.createElement('br'));
		}
		var label = document.createElement('label');
		label.innerHTML = options.describePanel.descriptionLabel;
		this.dom.appendChild(label);
		var textarea = document.createElement('textarea');
		textarea.id = 'Description';
		this.dom.appendChild(textarea);
		this.dom.appendChild(element('strong', 'What’s the urgency of your issue?'));
		var radBtnHigh = element('input');
		radBtnHigh.value = 'High';
		radBtnHigh.type = 'radio';
		radBtnHigh.name = 'priority';
		radBtnHigh.onclick = onPriorityChange;

		var highText = document.createElement('span');
		highText.appendChild(document.createTextNode(options.AgendaFree && !options.FullSupport ? options.localization.optionHighPrioritySupportUnpurchased : options.localization.optionHighPrioritySupport));

		var lblHigh = document.createElement('label');
		lblHigh.appendChild(radBtnHigh);
		lblHigh.appendChild(highText);
		if (options.AgendaFree && !options.FullSupport)
		{
			radBtnHigh.setAttribute('disabled', 'disabled');
			lblHigh.style.color = 'gray';
		}

		var radBtnMed = element('input');
		radBtnMed.value = 'Medium - 1 day';
		radBtnMed.type = 'radio';
		radBtnMed.name = 'priority';
		radBtnMed.onclick = onPriorityChange;
		var lblMed = document.createElement('label');
		lblMed.appendChild(radBtnMed);
		lblMed.appendChild(document.createTextNode('Medium - 1 day response'));

		var radBtnLow = element('input');
		radBtnLow.value = 'Low - 1 week';
		radBtnLow.type = 'radio';
		radBtnLow.name = 'priority';
		radBtnLow.onclick = onPriorityChange;
		var lblLow = document.createElement('label');
		lblLow.appendChild(radBtnLow);
		lblLow.appendChild(document.createTextNode('Low - 1 week response'));

		var radBtnNo = element('input');
		radBtnNo.value = 'No response necessary';
		radBtnNo.type = 'radio';
		radBtnNo.name = 'priority';
		radBtnNo.onclick = onPriorityChange;
		var lblNo = document.createElement('label');
		lblNo.appendChild(radBtnNo);
		lblNo.appendChild(document.createTextNode('No response necessary'));

		this.dom.appendChild(document.createElement('br'));
		this.dom.appendChild(lblHigh);
		if (options.AgendaFree && !options.FullSupport)
		{
			var upgradeBtn = document.createElement('a');
			upgradeBtn.textContent = 'Upgrade to Full version';
			upgradeBtn.style.marginLeft = '10px';
			upgradeBtn.className = 'button button-short button-highlighted background-color-hover upgrade-request';
			upgradeBtn.setAttribute('href', 'https://www.icompasstech.com/pricing/');
			upgradeBtn.setAttribute('target', '_blank');
			upgradeBtn.setAttribute('data-type', 'AgendaFree_Full_Support');
			this.dom.appendChild(upgradeBtn);
		}
		this.dom.appendChild(document.createElement('br'));
		this.dom.appendChild(lblMed);
		this.dom.appendChild(document.createElement('br'));
		this.dom.appendChild(lblLow);
		this.dom.appendChild(document.createElement('br'));
		this.dom.appendChild(lblNo);
		this.dom.appendChild(document.createElement('br'));


		this.dom.appendChild(document.createElement('br'));
		label = document.createElement('label');
		label.innerHTML = options.describePanel.annotateLabel;
		this.dom.appendChild(label);
		return this;
	};

	var onPriorityChange = function ()
	{
		$('.feedback-btn').removeAttr('disabled');
		$('.feedback-lbl-priority').hide();
	};
	window.Feedback.Describe.prototype.end = function ()
	{
		window.Feedback.Describe.Description = $('#Description').val();
		window.Feedback.Describe.Priority = document.querySelector('input[name="priority"]:checked').value;
	};

	window.Feedback.Annotate = function (options)
	{
		this.options = options || {};
		this.options.highlightClass = this.options.highlightClass || 'feedback-highlighted';
	};

	window.Feedback.Annotate.prototype = new window.Feedback.Page();

	window.Feedback.Annotate.prototype.start = function (modal)
	{
		emptyElements(this.dom);

		var hLabel = document.createElement('label');
		hLabel.innerHTML = ' Select areas relevant to your feedback';

		modal.className += ' feedback-animate-toside';
		this.dom.appendChild(hLabel);
		$('#FeedbackModal').draggable({ handle: '.feedback-header', delay: 0 });

	};

	window.Feedback.Annotate.prototype.render = function ()
	{

		this.dom = document.createElement('div');
		return this;
	};

	window.Feedback.Annotate.prototype.end = function ()
	{
	};

	window.Feedback.Annotate.prototype.close = function ()
	{
	};

	window.Feedback.Review = function ()
	{
		var a = document.createElement('div');
		a.style.overflow = 'hidden';
		this.dom = a;
	};

	window.Feedback.Review.prototype = new window.Feedback.Page();

	window.Feedback.Review.prototype.render = function (modal, pages, options)
	{
		modal.removeAttribute('style');
		$(modal).removeClass('feedback-animate-toside').addClass('feedback-animate-review');
		emptyElements(this.dom);
		var item, firstColumn;

		firstColumn = document.createElement('div');
		firstColumn.id = 'firstColumn';
		firstColumn.className = 'feedback-columns';

		var label = document.createElement('label');
		label.innerHTML = options.descriptonLabel;
		label.style.fontWeight = 'bold';
		firstColumn.appendChild(label);
		var textarea = document.createElement('textarea');
		textarea.style.width = '90%';
		textarea.value = window.Feedback.Describe.Description;
		firstColumn.appendChild(textarea);

		var accordion = document.createElement('div');
		accordion.id = 'accordionInfo';
		var h5 = document.createElement('h5');
		h5.innerHTML = options.reviewPanel.browserInfoLabel;
		var p1 = document.createElement('p');
		p1.id = 'browserInfo';

		p1.innerHTML = options.reviewPanel.browserData;
		accordion.appendChild(h5);
		accordion.appendChild(p1);

		h5 = document.createElement('h5');
		h5.innerHTML = options.reviewPanel.userInfoLabel;
		p1 = document.createElement('p');
		p1.id = 'userInfo';
		p1.innerHTML = options.reviewPanel.userData;
		accordion.appendChild(h5);
		accordion.appendChild(p1);

		h5 = document.createElement('h5');
		h5.innerHTML = options.reviewPanel.pageInfoLabel;
		p1 = document.createElement('p');
		p1.id = 'pageInfo';
		p1.innerHTML = options.reviewPanel.pageData;
		accordion.appendChild(h5);
		accordion.appendChild(p1);

		firstColumn.appendChild(accordion);

		var secondColumn = document.createElement('div');
		secondColumn.id = 'secondColumn';
		secondColumn.className = 'feedback-columns';
		item = document.createElement('label');
		item.innerHTML = options.screenshotLabel;
		secondColumn.appendChild(item);



		this.dom.appendChild(firstColumn);
		this.dom.appendChild(secondColumn);

		secondColumn.appendChild(document.createElement('br'));

		var image = document.createElement('img');
		image.className = 'hidden';
		secondColumn.appendChild(image);

		var spinner = document.createElement('span');
		spinner.innerHTML = '<span class="fa fa-spinner fa-spin"></span>';
		secondColumn.appendChild(spinner);

		var creatingImage = document.createElement('label');
		creatingImage.innerHTML = '&nbsp;&nbsp;' + options.reviewPanel.creatingImageLabel;
		secondColumn.appendChild(creatingImage);


		var imageData;
		setTimeout(function ()
		{
			window.html2canvas(document.body, {
				onrendered: function (canvas)
				{
					secondColumn.removeChild(spinner);
					secondColumn.removeChild(creatingImage);

					imageData = canvas.toDataURL();
					options.reviewPanel.imageData = imageData;
					image.className = '';
					image.src = imageData;
					image.style.width = '100%';
					image.style.height = '100%';
				}
			});
		}, 1300);

		return this;

	};

	window.Feedback.ThankYou = function ()
	{
		this.dom = document.createElement('div');
	};

	window.Feedback.ThankYou.prototype = new window.Feedback.Page();

	window.Feedback.ThankYou.prototype.render = function (options)
	{
		emptyElements(this.dom);
		var label = document.createElement('label');
		label.innerHTML = options.thankYouPanel.descriptionLabel;
		this.dom.appendChild(label);
		return this;
	};
	var annotate = {};

	function isCanvasSupported()
	{
		var elem = document.createElement('canvas');
		return !!(elem.getContext && elem.getContext('2d'));
	}

	function distance(element)
	{
		var x = (element.position().left + element.width()) - element.position().left;
		var y = (element.position().top + element.height()) - element.position().top;

		return Math.sqrt(x * x + y * y);
	}

	var css = {
		// CSS for the overlay and rectangles container
		base: {
			"position": 'absolute',
			"top": 0,
			"left": 0,
			"margin": 0,
			"z-index": 4900
		},

		// CSS for the rectangles container
		markers: {
			"z-index": 5000,
			"background-color": 'rgba(0,0,0,0)',
			"color": 'gray',
			"cursor": 'crosshair'
		},

		// CSS for the rectangles drawn
		rectangle: {
			"position": 'absolute',
			"font-size": '14px',
			"font-weight": 'bold',
			"z-index": 5500,
			"border": '2px solid #000'
		},

		// CSS to make everything unselectable
		unselectable: {
			"-moz-user-select": '-moz-none',
			"-khtml-user-select": 'none',
			"-webkit-user-select": 'none',
			"user-select": 'none'
		}
	};
	annotate.defaults = {

		useCanvas: isCanvasSupported(),

		minimalDistance: 10,

		color: 'rgba(255,255,255,0)',

		container: $(document),

		uploadName: 'screenshot',

		uploadMIME: 'image/png',

		onRectangleStart: function () { },

		onRectangleEnd: function (rectangle)
		{
			rectangle.text('Click me to remove');
			rectangle.mouseover(function ()
			{
				rectangle.text('Click me to remove');
			});

			rectangle.mouseout(function ()
			{
				rectangle.text('');
			});
		},

		onPreRender: function ()
		{
			alert('Feedback will now create a screen shot of the web elements ' +
				'ONLY. The overlay and feedback window will hide for a second ' +
				'and will then show again. Rendering can take a few seconds.');
		},

		onPostRender: function () { },

		onShow: function () { },

		onHide: function () { }
	};
	annotate.init = function (element, options)
	{
		annotate.options = $.extend(annotate.defaults, options);
		annotate.overlay = $('<canvas />').css(css.base).css(css.unselectable).appendTo(element);
		annotate.markers = $('<div />').css(css.base).css(css.markers).css(css.unselectable).appendTo(element);
		annotate.element = element;

		var rectangle = null;

		// Attach the resize hook to the window
		$(window).resize(function ()
		{
			annotate.resize();
			annotate.paint();
		});

		annotate.markers.mousedown(function (e)
		{
			rectangle = $('<div />').css({
				"left": e.pageX,
				"top": e.pageY
			}).css($.extend(
				css.rectangle,
				css.unselectable,
				{ "background-color": annotate.options.color }
			));


			var rectangleLeft = e.pageX;
			var rectangleTop = e.pageY;

			// Execute callback
			annotate.options.onRectangleStart(
				rectangle,
				rectangleLeft,
				rectangleTop
			);

			// Add it to the DOM
			rectangle.appendTo(annotate.markers);
			annotate.markers.mousemove(function (e)
			{
				rectangle.width(Math.abs(e.pageX - rectangleLeft));
				rectangle.height(Math.abs(e.pageY - rectangleTop));

				if (e.pageX < rectangleLeft)
				{
					rectangle.css('left', e.pageX);
				}

				if (e.pageY < rectangleTop)
				{
					rectangle.css('top', e.pageY);
				}
			});
		});

		annotate.markers.mouseup(function (e)
		{
			var self = rectangle;

			var remove = (function ()
			{
				self.remove();
				annotate.paint();
			});

			// Ignore small rectangles
			if (distance(self) < annotate.options.minimalDistance)
			{
				remove();
			} else
			{
				annotate.options.onRectangleEnd(self, e.pageX, e.pageY);
				self.mousedown(function () { return false; });
				self.click(remove);
			}

			annotate.markers.unbind('mousemove');
			annotate.paint();
		});

		// Initialize
		annotate.hide();
		annotate.resize();
		annotate.clear();
	};

	annotate.paint = function ()
	{
		// Draw overlay
		var context;
		if (annotate.options.useCanvas)
		{
			// Get context
			context = annotate.overlay[0].getContext('2d'); // Draw basic background
			context.clearRect(0, 0, annotate.overlay.width(), annotate.overlay.height());
			context.fillStyle = 'rgba(0, 0, 0, 0.5)';
			context.fillRect(0, 0, annotate.overlay.width(), annotate.overlay.height());
		}

		// Draw rectangles
		annotate.markers.find('div').each(function ()
		{
			var element = $(this);
			var borderWidth = parseInt(element.css('border-left-width'), 10);

			// Make cutout in canvas
			if (annotate.options.useCanvas)
			{
				context.clearRect(
					element.position().left,
					element.position().top,
					element.width() + borderWidth * 2,
					element.height() + borderWidth * 2
				);
			}
		});
	}; /**
	 * Resize the overlay and markers container.
	 * @param instance Feedback object instance
	 */
	annotate.resize = function ()
	{
		// Resize overlay
		if (annotate.options.useCanvas)
		{
			annotate.overlay.prop('width', annotate.options.container.width());
			annotate.overlay.prop('height', annotate.options.container.height());
		}

		// Resize markers
		annotate.markers.width(annotate.options.container.width());
		annotate.markers.height(annotate.options.container.height());
	}; /**
	 * Clear all rectangles and redraw everything
	 * @param instance Feedback object instance
	 */
	annotate.clear = function ()
	{
		annotate.markers.html('');
		annotate.paint();
	}; /**
	 * Show the Feedback overlay and markers. Calls the onShow callback.
	 * @param instance Feedback object instance
	 */
	annotate.show = function ()
	{
		if (annotate.options.useCanvas) annotate.overlay.show();
		annotate.markers.show();

		annotate.options.onShow();
	}; /**
	 * Hide the Feedback overlay and markers. Calls the onHide callback.
	 * @param instance Feedback object instance
	 */
	annotate.hide = function ()
	{
		if (annotate.options.useCanvas) annotate.overlay.hide();
		annotate.markers.hide();

		annotate.options.onHide();
	}; /**
	 * Quick helper to hide or show the overlay and markers
	 * @param instance Feedback object instance
	 */
	annotate.toggle = function ()
	{
		if (annotate.markers.is(':visible'))
		{
			annotate.hide();
		} else
		{
			annotate.show();
		}
	};
})(window, document);
;
/**
 * HTMLFeedback
 *
 * Copyright (c) 2012 Bas Stottelaar
 * See the file LICENSE for copying permission.
 *
 * jQuery based plugin to mark areas of your website that needs attention.
 * With the help of HTML2Canvas, we can create a screenshot (including the marked
 * areas) and upload it to the server. It currently is compatible with browsers 
 * supporting the canvas element. You can disable the canvas element as an overlay
 * and use FlashCanvas to render the screen.
 *
 * @author Bas Stottelaar <http://github.com/basilfx>
 * @version 1.0
 * @date 2012-02-18 (last update: 2012-12-30)
 * @license MIT
 */
(function ($)
{
	/**
		 * @var object Reference to the BlobBuilder, if the browser supports
		 * it. If not, this variable will be undefined.
		 */
	var blobBuilder = window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || undefined;

	/**
	 * @var object Reference to the FormData, if the browser supports it.
	 * If not, this variable will be undefined.
	 */
	var formData = window.FormData || undefined;

	/**
	 * @var boolean True when the webpage is shown on a touch compatible device.
	 */
	var isTouchDevice = 'ontouchstart' in document.documentElement;

	/**
	 * Convert a data URI to a blob.
	 * @see http://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata
	 * @return Blob Object containing the dataURI.
	 */
	function dataUrItoBlob(dataUri)
	{
		var byteString = atob(dataUri.split(',')[1]);
		var mimeString = dataUri.split(',')[0].split(':')[1].split(';')[0];

		var ab = new ArrayBuffer(byteString.length);
		var ia = new Uint8Array(ab);

		for (var i = 0; i < byteString.length; i++)
		{
			ia[i] = byteString.charCodeAt(i);
		}

		var bb = new blobBuilder();
		bb.append(ab);
		return bb.getBlob(mimeString);
	}

	/**
	 * Translate a touch event into a mouse event. Handles only
	 * single touches.
	 * @param event Event object containing the touch.
	 */
	function touchToMouseEvent(event)
	{
		// Only single touches
		if (event.originalEvent.touches.length > 1) return;

		// Set data
		var touch = event.originalEvent.changedTouches[0];
		var newEvent = document.createEvent('MouseEvents');
		var type;
		var simulateClick;

		// Determine type
		switch (event.type)
		{
			case 'touchstart':
				type = 'mousedown';
				break;
			case 'touchmove':
				type = 'mousemove';
				break;
			case 'touchend':
				type = 'mouseup';
				break;
			default:
				return;
		}

		// Handle click events
		if (event.type === 'touchstart')
		{
			event.target.startX = touch.clientX;
			event.target.startY = touch.clientY;
		} else if (event.type === 'touchend')
		{
			simulateClick = Math.abs(event.target.startX - touch.clientX) < 10 ||
							Math.abs(event.target.startY - touch.clientY) < 10;

			if (simulateClick) type = 'click';
		}

		// Initialize event
		newEvent.initMouseEvent(
			type, true, true, window, 1,
			touch.screenX, touch.screenY,
			touch.clientX, touch.clientY, false,
			false, false, false, 0, null
		);

		// Done
		event.target.dispatchEvent(newEvent);
		event.preventDefault();
	}

	/**
	 * Detect support for the canvas element.
	 * @return true if canvas element is supported
	 */
	function isCanvasSupported()
	{
		var elem = document.createElement('canvas');
		return !!(elem.getContext && elem.getContext('2d'));
	}

	/**
	 * Calculate the Eucledian distance from elements boundings
	 * @param element jQuery element
	 * @return double Pythagoras distance
	 */
	function distance(element)
	{
		var x = (element.position().left + element.width()) - element.position().left;
		var y = (element.position().top + element.height()) - element.position().top;

		return Math.sqrt(x * x + y * y);
	}

	/**
	 * @var object CSS for overlay and markers
	 */
	var css = {
		// CSS for the overlay and rectangles container
		base: {
			"position": 'absolute',
			"top": 0,
			"left": 0,
			"margin": 0,
			"z-index": 4900
		},

		// CSS for the rectangles container
		markers: {
			"z-index": 5000,
			"background-color": 'rgba(0,0,0,0)',
			"cursor": 'crosshair',
			"color": 'black'
		},

		// CSS for the rectangles drawn
		rectangle: {
			"position": 'absolute',
			"font-size": '14px',
			"font-weight": 'bold',
			"z-index": 5500,
			"border": '2px solid #000'
		},

		// CSS to make everything unselectable
		unselectable: {
			"-moz-user-select": '-moz-none',
			"-khtml-user-select": 'none',
			"-webkit-user-select": 'none',
			"user-select": 'none'
		}
	}; /**
	 * @var object The 'almighty' HTMLFeedback object
	 */
	var htmlFeedback = {}; /**
	 * @var object List of all HTMLFeedback instances
	 */
	htmlFeedback.instances = {};

	/**
	 * @var object Default plugin options
	 */
	htmlFeedback.defaults = {
		/**
	 * @var boolean If true, upload the data as URI instead as a multipart
	 * file. Default is false if browser has support for BlobBuilder.
	 */
		uploadAsURI: (blobBuilder ? false : true),

		/**
		 * @var boolean If true, use the canvas element as overlay for
		 * the screen. Default is true if the browser has support for the
		 * canvas element.
		 */
		useCanvas: isCanvasSupported(),

		/**
		 * @var int Minimal distance for a drawn square. Small nummer
		 * allows small squares. Please note: on touch devices the number
		 * will be at least 10px.
		 */
		minimalDistance: 10,

		/**
		 * @var object Rectangle color (in RGBA for opacity)
		 */
		color: 'rgba(255,255,255,0)',

		/**
		 * @var element Reference to a container object where the canvas
		 * and markers will be drawn over. Defaults to document.
		 */
		container: $(document),

		/**
		 * @var string Name of the element for file uploading.
		 */
		uploadName: 'screenshot',

		/**
		 * @var string Mime type of the file
		 */
		uploadMIME: 'image/png',

		/**
		 * @var callback Before a rectangle has been drawn
		 */
		onRectangleStart: function () { },

		/**
		 * @var callback After a rectangle has been drawn
		 */
		onRectangleEnd: function (rectangle)
		{
			rectangle.text('Click me to remove');
			rectangle.mouseover(function ()
			{
				rectangle.text('Click me to remove');
			});

			rectangle.mouseout(function ()
			{
				rectangle.text('');
			});
		},

		/**
		 * @var callback Before redering has started
		 */
		onPreRender: function ()
		{
			alert('HTMLFeedback will now create a screenshot of the web elements ' +
					'ONLY. The overlay and feedback window will hide for a second ' +
					'and will then show again. Rendering can take a few seconds.');
		},

		/**
		 * @var callback After rendering has completed
		 */
		onPostRender: function () { },

		/**
		 * @var callback Show event
		 */
		onShow: function () { },

		/**
		 * @var callback Hide event
		 */
		onHide: function () { }
	}; /**
	 * (Re)draw the canvas element and the markers.
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.paint = function (instance)
	{
		// Draw overlay
		var context;
		if (instance.options.useCanvas)
		{
			// Get context
			context = instance.overlay[0].getContext('2d'); // Draw basic background
			context.clearRect(0, 0, instance.overlay.width(), instance.overlay.height());
			context.fillStyle = 'rgba(0, 0, 0, 0.5)';
			context.fillRect(0, 0, instance.overlay.width(), instance.overlay.height());
		}

		// Draw rectangles
		instance.markers.find('div').each(function ()
		{
			var element = $(this);
			var borderWidth = parseInt(element.css('border-left-width'), 10);

			// Make cutout in canvas
			if (instance.options.useCanvas)
			{
				context.clearRect(
					element.position().left,
					element.position().top,
					element.width() + borderWidth * 2,
					element.height() + borderWidth * 2
				);
			}
		});
	}; /**
	 * Resize the overlay and markers container.
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.resize = function (instance)
	{
		// Resize overlay
		if (instance.options.useCanvas)
		{
			instance.overlay.prop('width', instance.options.container.width());
			instance.overlay.prop('height', instance.options.container.height());
		}

		// Resize markers
		instance.markers.width(instance.options.container.width());
		instance.markers.height(instance.options.container.height());
	}; /**
	 * Clear all rectangles and redraw everything
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.clear = function (instance)
	{
		instance.markers.html('');
		htmlFeedback.paint(instance);
	}; /**
	 * Show the HTMLFeedback overlay and markers. Calls the onShow callback.
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.show = function (instance)
	{
		if (instance.options.useCanvas) instance.overlay.show();
		instance.markers.show();

		instance.options.onShow();
	}; /**
	 * Hide the HTMLFeedback overlay and markers. Calls the onHide callback.
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.hide = function (instance)
	{
		if (instance.options.useCanvas) instance.overlay.hide();
		instance.markers.hide();

		instance.options.onHide();
	}; /**
	 * Quick helper to hide or show the overlay and markers
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.toggle = function (instance)
	{
		if (instance.markers.is(':visible'))
		{
			htmlFeedback.hide(instance);
		} else
		{
			htmlFeedback.show(instance);
		}
	}; /**
	 * Render the screenshot and call the onPostRender callback with the
	 * rendered canvas element as first parameter
	 *
	 * @param instance HTMLFeedback object instance
	 */
	htmlFeedback.render = function (instance)
	{

		instance.options.onPreRender();

		html2canvas(instance.element, {
			onrendered: function (canvas)
			{
				instance.options.onPostRender(canvas);
				// Show overlay again
				if (instance.options.useCanvas) instance.overlay.show();
			}
		});
	}; /**
	 * Create screenshot and upload it via AJAX. The extra parameter is passed
	 * to the jQuery.ajax method.
	 *
	 * @param instance HTMLFeedback object instance
	 * @param extra jQuery AJAX parameters
	 * @see http://api.jquery.com/jQuery.ajax/
	 */
	htmlFeedback.upload = function (instance, extra)
	{
		var imageData = null;
		var imageMime = instance.options.uploadMime;
		var uploadName = instance.options.uploadName;

		if (instance.options.useCanvas) instance.overlay.hide();
		instance.options.onPreRender();

		// Upload via XHR2
		html2canvas(instance.element, {
			onrendered: function (canvas)
			{
				instance.options.onPostRender(canvas); // Create the data
				if (instance.options.uploadAsURI)
				{ // As 'raw' string
					imageData = canvas.toDataURL(imageMime);
				} else
				{
					if (canvas.toBlob ? true : false)
					{ // Native
						canvas.toBlob(function (blob)
						{
							imageData = blob;
						}, imageMime);
					} else
					{ // Via dataURI -> Blob
						imageData = dataUrItoBlob(canvas.toDataURL(imageMime));
					}
				}

				if (formData)
				{ // Prefer upload via FormData object
					var form = new formData();
					form.append(uploadName, imageData);
					$.each(extra.data || {}, function (key, value)
					{
						form.append(key, value);
					});

					extra.data = form;
				} else
				{ // Or the old-fashioned way
					extra.data = extra.data || {};
					extra.data[uploadName] = imageData;
				}

				// And upload via ajax
				$.ajax($.extend({
					cache: false,
					contentType: false,
					processData: false,
					type: 'POST'
				}, extra));

				// Show overlay again
				if (instance.options.useCanvas) instance.overlay.show();
			}
		});
	}; /**
	 * Initialize a new HTMLFeedback instance.
	 * @param element jQuery object to bind to
	 * @param option Plugin options.
	 * @see HTMLFeedback.defaults
	 */
	htmlFeedback.init = function (element, options)
	{
		var options = $.extend(htmlFeedback.defaults, options);

		// Create required elements and add them to the element
		var overlay = options.useCanvas ? $('<canvas />').css(css.base).css(css.unselectable).appendTo(element) : null;
		var markers = $('<div />').css(css.base).css(css.markers).css(css.unselectable).appendTo(element);

		// Create an instance
		var instance = htmlFeedback.instances[element] = {
			overlay: overlay,
			markers: markers,
			options: options,
			element: element
		};

		var rectangle = null;

		// Attach the resize hook to the window
		$(window).resize(function ()
		{
			htmlFeedback.resize(instance);
			htmlFeedback.paint(instance);
		});

		markers.mousedown(function (e)
		{
			rectangle = $('<div />').css({
				"left": e.pageX,
				"top": e.pageY
			}).css($.extend(
				css.rectangle,
				css.unselectable,
				{ "background-color": instance.options.color }
			));
			//alert(instance.options.color);

			var rectangleLeft = e.pageX;
			var rectangleTop = e.pageY;

			// Execute callback
			instance.options.onRectangleStart(
				rectangle,
				rectangleLeft,
				rectangleTop
			);

			// Add it to the DOM
			rectangle.appendTo(markers);
			markers.mousemove(function (e)
			{
				rectangle.width(Math.abs(e.pageX - rectangleLeft));
				rectangle.height(Math.abs(e.pageY - rectangleTop));

				if (e.pageX < rectangleLeft)
				{
					rectangle.css('left', e.pageX);
				}

				if (e.pageY < rectangleTop)
				{
					rectangle.css('top', e.pageY);
				}
			});
		});

		markers.mouseup(function (e)
		{
			var self = rectangle;

			var remove = (function ()
			{
				self.remove();
				htmlFeedback.paint(instance);
			});

			// Ignore small rectangles
			if (distance(self) < options.minimalDistance)
			{
				remove();
			} else
			{
				instance.options.onRectangleEnd(self, e.pageX, e.pageY);
				self.mousedown(function () { return false; });
				self.click(remove);
			}

			markers.unbind('mousemove');
			htmlFeedback.paint(instance);
		});

		// Map touch events
		if (isTouchDevice)
		{
			instance.markers.bind('touchstart', touchToMouseEvent);
			instance.markers.bind('touchmove', touchToMouseEvent);
			instance.markers.bind('touchend', touchToMouseEvent);
			instance.markers.bind('touchcancel', touchToMouseEvent);
		}

		// Initialize
		htmlFeedback.hide(instance);
		htmlFeedback.resize(instance);
		htmlFeedback.clear(instance);
	};

	/**
	 * Bind the plugin to the jQuery prototype object.
	 *
	 * Once a instance has been initialized, you can execute commands on the
	 * instance. Instead of passing options, you can pass a string. For example:
	 *
	 *   $("body").htmlfeedback("upload", ajaxRequest);
	 *
	 * Supported actions:
	 *
	 *   show       --      Show the overlay and markers.
	 *   hide       --      Hide the overlay and markers.
	 *   toggle     --      Hide or show the overlay and the markers.
	 *   render     --      Create a screenshot and call the onPostRender callback
	 *                      with a reference to the newly created canvas.
	 *   upload     --      Upload a screenshot. Second parameter is a normal
	 *                      AJAX request object.
	 *   reset      --      Reset HTMLFeedback. Clears all markers.
	 *   color      --      Set the marker color.
	 */
	$.fn.htmlfeedback = function (input, extra)
	{
		var type = typeof input;
		var self = $(this);

		if (arguments.length === 0 || type === 'object')
		{
			htmlFeedback.init(self, input);
		} else if (type === 'string')
		{
			var instance = htmlFeedback.instances[self];

			switch (input.toLowerCase())
			{
				case 'show':
					htmlFeedback.show(instance);
					break;
				case 'hide':
					htmlFeedback.hide(instance);
					break;
				case 'toggle':
					htmlFeedback.toggle(instance);
					break;
				case 'render':
					htmlFeedback.render(instance, extra);
					break;
				case 'upload':
					htmlFeedback.upload(instance, extra);
					break;
				case 'reset':
					htmlFeedback.hide(instance);
					htmlFeedback.resize(instance);
					htmlFeedback.clear(instance);
					break;
				case 'color':
					instance.options.color = extra;
					break;
			}

			return self;
		}
		return null;
	};
})(jQuery);
;
/*
	html2canvas 0.4.1 <http://html2canvas.hertzen.com>
	Copyright (c) 2013 Niklas von Hertzen

	Released under MIT License
*/

(function (window, document, undefined)
{

	'use strict';

	var html2Canvas = {};
	var previousElement;
	var computedCss;

	html2Canvas.Util = {};

	html2Canvas.Util.log = function (a)
	{
		if (html2Canvas.logging && window.console && window.console.log)
		{
			window.console.log(a);
		}
	};

	html2Canvas.Util.trimText = (function (isNative)
	{
		return function (input)
		{
			return isNative ? isNative.apply(input) : ((input || '') + '').replace(/^\s+|\s+$/g, '');
		};
	})(String.prototype.trim);

	html2Canvas.Util.asFloat = function (v)
	{
		return parseFloat(v);
	};

	(function ()
	{
		// TODO: support all possible length values
		var textShadowProperty = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
		var textShadowValues = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
		html2Canvas.Util.parseTextShadows = function (value)
		{
			if (!value || value === 'none')
			{
				return [];
			}

			// find multiple shadow declarations
			var shadows = value.match(textShadowProperty),
				results = [];
			for (var i = 0; shadows && (i < shadows.length) ; i++)
			{
				var s = shadows[i].match(textShadowValues);
				results.push({
					color: s[0],
					offsetX: s[1] ? s[1].replace('px', '') : 0,
					offsetY: s[2] ? s[2].replace('px', '') : 0,
					blur: s[3] ? s[3].replace('px', '') : 0
				});
			}
			return results;
		};
	})();


	html2Canvas.Util.parseBackgroundImage = function (value)
	{
		var whitespace = ' \r\n\t';
		var method;
		var definition;
		var prefix;
		var prefixI;
		var block;
		var results = [];
		var c;
		var mode = 0;
		var numParen = 0;
		var quote = null;
		var args;

		var appendResult = function ()
		{
			if (method)
			{
				if (definition.substr(0, 1) === '"')
				{
					definition = definition.substr(1, definition.length - 2);
				}
				if (definition)
				{
					args.push(definition);
				}
				if (method.substr(0, 1) === '-' &&
						(prefixI = method.indexOf('-', 1) + 1) > 0)
				{
					prefix = method.substr(0, prefixI);
					method = method.substr(prefixI);
				}
				results.push({
					prefix: prefix,
					method: method.toLowerCase(),
					value: block,
					args: args
				});
			}
			args = []; //for some odd reason, setting .length = 0 didn't work in safari
			method =
				prefix =
				definition =
				block = '';
		};

		appendResult();
		for (var i = 0, ii = value.length; i < ii; i++)
		{
			c = value[i];
			if (mode === 0 && whitespace.indexOf(c) > -1)
			{
				continue;
			}
			switch (c)
			{
				case '"':
					if (!quote)
					{
						quote = c;
					}
					else if (quote === c)
					{
						quote = null;
					}
					break;

				case '(':
					if (quote) { break; }
					else if (mode === 0)
					{
						mode = 1;
						block += c;
						continue;
					} else
					{
						numParen++;
					}
					break;

				case ')':
					if (quote) { break; }
					else if (mode === 1)
					{
						if (numParen === 0)
						{
							mode = 0;
							block += c;
							appendResult();
							continue;
						} else
						{
							numParen--;
						}
					}
					break;

				case ',':
					if (quote) { break; }
					else if (mode === 0)
					{
						appendResult();
						continue;
					}
					else if (mode === 1)
					{
						if (numParen === 0 && !method.match(/^url$/i))
						{
							args.push(definition);
							definition = '';
							block += c;
							continue;
						}
					}
					break;
			}

			block += c;
			if (mode === 0) { method += c; }
			else { definition += c; }
		}
		appendResult();

		return results;
	};

	html2Canvas.Util.Bounds = function (element)
	{
		var clientRect, bounds = {};

		if (element.getBoundingClientRect)
		{
			clientRect = element.getBoundingClientRect();

			// TODO add scroll position to bounds, so no scrolling of window necessary
			bounds.top = clientRect.top;
			bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height);
			bounds.left = clientRect.left;

			bounds.width = element.offsetWidth;
			bounds.height = element.offsetHeight;
		}

		return bounds;
	};

	// TODO ideally, we'd want everything to go through this function instead of Util.Bounds,
	// but would require further work to calculate the correct positions for elements with offsetParents
	html2Canvas.Util.OffsetBounds = function (element)
	{
		var parent = element.offsetParent ? html2Canvas.Util.OffsetBounds(element.offsetParent) : { top: 0, left: 0 };

		return {
			top: element.offsetTop + parent.top,
			bottom: element.offsetTop + element.offsetHeight + parent.top,
			left: element.offsetLeft + parent.left,
			width: element.offsetWidth,
			height: element.offsetHeight
		};
	};

	function toPx(element, attribute, value)
	{
		var rsLeft = element.runtimeStyle && element.runtimeStyle[attribute];
		var left;
		var style = element.style;

		// Check if we are not dealing with pixels, (Opera has issues with this)
		// Ported from jQuery css.js
		// From the awesome hack by Dean Edwards
		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

		// If we're not dealing with a regular pixel number
		// but a number that has a weird ending, we need to convert it to pixels

		if (!/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test(value) && /^-?\d/.test(value))
		{
			// Remember the original values
			left = style.left;

			// Put in the new values to get a computed value out
			if (rsLeft)
			{
				element.runtimeStyle.left = element.currentStyle.left;
			}
			style.left = attribute === 'fontSize' ? '1em' : (value || 0);
			value = style.pixelLeft + 'px';

			// Revert the changed values
			style.left = left;
			if (rsLeft)
			{
				element.runtimeStyle.left = rsLeft;
			}
		}

		if (!/^(thin|medium|thick)$/i.test(value))
		{
			return Math.round(parseFloat(value)) + 'px';
		}

		return value;
	}

	function asInt(val)
	{
		return parseInt(val, 10);
	}

	function parseBackgroundSizePosition(value, element, attribute, index)
	{
		value = (value || '').split(',');
		value = value[index || 0] || value[0] || 'auto';
		value = html2Canvas.Util.trimText(value).split(' ');

		if (attribute === 'backgroundSize' && (!value[0] || value[0].match(/cover|contain|auto/)))
		{
			//these values will be handled in the parent function
		} else
		{
			value[0] = (value[0].indexOf('%') === -1) ? toPx(element, attribute + 'X', value[0]) : value[0];
			if (value[1] === undefined)
			{
				if (attribute === 'backgroundSize')
				{
					value[1] = 'auto';
					return value;
				} else
				{
					// IE 9 doesn't return double digit always
					value[1] = value[0];
				}
			}
			value[1] = (value[1].indexOf('%') === -1) ? toPx(element, attribute + 'Y', value[1]) : value[1];
		}
		return value;
	}

	html2Canvas.Util.getCSS = function (element, attribute, index)
	{
		if (previousElement !== element)
		{
			computedCss = document.defaultView.getComputedStyle(element, null);
		}

		var value = computedCss[attribute];

		if (/^background(Size|Position)$/.test(attribute))
		{
			return parseBackgroundSizePosition(value, element, attribute, index);
		} else if (/border(Top|Bottom)(Left|Right)Radius/.test(attribute))
		{
			var arr = value.split(' ');
			if (arr.length <= 1)
			{
				arr[1] = arr[0];
			}
			return arr.map(asInt);
		}

		return value;
	};

	html2Canvas.Util.resizeBounds = function (currentWidth, currentHeight, targetWidth, targetHeight, stretchMode)
	{
		var targetRatio = targetWidth / targetHeight;
		var currentRatio = currentWidth / currentHeight;
		var outputWidth;
		var outputHeight;

		if (!stretchMode || stretchMode === 'auto')
		{
			outputWidth = targetWidth;
			outputHeight = targetHeight;
		} else if (targetRatio < currentRatio ^ stretchMode === 'contain')
		{
			outputHeight = targetHeight;
			outputWidth = targetHeight * currentRatio;
		} else
		{
			outputWidth = targetWidth;
			outputHeight = targetWidth / currentRatio;
		}

		return {
			width: outputWidth,
			height: outputHeight
		};
	};

	function backgroundBoundsFactory(prop, el, bounds, image, imageIndex, backgroundSize)
	{
		var bgposition = html2Canvas.Util.getCSS(el, prop, imageIndex);
		var topPos;
		var left;
		var percentage;
		var val;

		if (bgposition.length === 1)
		{
			val = bgposition[0];

			bgposition = [];

			bgposition[0] = val;
			bgposition[1] = val;
		}

		if (bgposition[0].toString().indexOf('%') !== -1)
		{
			percentage = (parseFloat(bgposition[0]) / 100);
			left = bounds.width * percentage;
			if (prop !== 'backgroundSize')
			{
				left -= (backgroundSize || image).width * percentage;
			}
		} else
		{
			if (prop === 'backgroundSize')
			{
				if (bgposition[0] === 'auto')
				{
					left = image.width;
				} else
				{
					if (/contain|cover/.test(bgposition[0]))
					{
						var resized = html2Canvas.Util.resizeBounds(image.width, image.height, bounds.width, bounds.height, bgposition[0]);
						left = resized.width;
					} else
					{
						left = parseInt(bgposition[0], 10);
					}
				}
			} else
			{
				left = parseInt(bgposition[0], 10);
			}
		}


		if (bgposition[1] === 'auto')
		{
			topPos = left / image.width * image.height;
		} else if (bgposition[1].toString().indexOf('%') !== -1)
		{
			percentage = (parseFloat(bgposition[1]) / 100);
			topPos = bounds.height * percentage;
			if (prop !== 'backgroundSize')
			{
				topPos -= (backgroundSize || image).height * percentage;
			}

		} else
		{
			topPos = parseInt(bgposition[1], 10);
		}

		return [left, topPos];
	}

	html2Canvas.Util.BackgroundPosition = function (el, bounds, image, imageIndex, backgroundSize)
	{
		var result = backgroundBoundsFactory('backgroundPosition', el, bounds, image, imageIndex, backgroundSize);
		return { left: result[0], top: result[1] };
	};

	html2Canvas.Util.BackgroundSize = function (el, bounds, image, imageIndex)
	{
		var result = backgroundBoundsFactory('backgroundSize', el, bounds, image, imageIndex);
		return { width: result[0], height: result[1] };
	};

	html2Canvas.Util.Extend = function (options, defaults)
	{
		for (var key in options)
		{
			if (options.hasOwnProperty(key))
			{
				defaults[key] = options[key];
			}
		}
		return defaults;
	};


	/*
	 * Derived from jQuery.contents()
	 * Copyright 2010, John Resig
	 * Dual licensed under the MIT or GPL Version 2 licenses.
	 * http://jquery.org/license
	 */
	html2Canvas.Util.Children = function (elem)
	{
		var children;
		try
		{
			children = (elem.nodeName && elem.nodeName.toUpperCase() === 'IFRAME') ? elem.contentDocument || elem.contentWindow.document : (function (array)
			{
				var ret = [];
				if (array !== null)
				{
					(function (first, second)
					{
						var i = first.length,
						j = 0;

						if (typeof second.length === 'number')
						{
							for (var l = second.length; j < l; j++)
							{
								first[i++] = second[j];
							}
						} else
						{
							while (second[j] !== undefined)
							{
								first[i++] = second[j++];
							}
						}

						first.length = i;

						return first;
					})(ret, array);
				}
				return ret;
			})(elem.childNodes);

		} catch (ex)
		{
			html2Canvas.Util.log('html2canvas.Util.Children failed with exception: ' + ex.message);
			children = [];
		}
		return children;
	};

	html2Canvas.Util.isTransparent = function (backgroundColor)
	{
		return (backgroundColor === 'transparent' || backgroundColor === 'rgba(0, 0, 0, 0)');
	};
	html2Canvas.Util.Font = (function ()
	{

		var fontData = {};

		return function (font, fontSize, doc)
		{
			if (fontData[font + '-' + fontSize] !== undefined)
			{
				return fontData[font + '-' + fontSize];
			}

			var container = doc.createElement('div');
			var img = doc.createElement('img');
			var span = doc.createElement('span');
			var sampleText = 'Hidden Text';

			container.style.visibility = 'hidden';
			container.style.fontFamily = font;
			container.style.fontSize = fontSize;
			container.style.margin = 0;
			container.style.padding = 0;

			doc.body.appendChild(container);

			// http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif)
			img.src = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=';
			img.width = 1;
			img.height = 1;

			img.style.margin = 0;
			img.style.padding = 0;
			img.style.verticalAlign = 'baseline';

			span.style.fontFamily = font;
			span.style.fontSize = fontSize;
			span.style.margin = 0;
			span.style.padding = 0;

			span.appendChild(doc.createTextNode(sampleText));
			container.appendChild(span);
			container.appendChild(img);
			var baseline = (img.offsetTop - span.offsetTop) + 1;

			container.removeChild(span);
			container.appendChild(doc.createTextNode(sampleText));

			container.style.lineHeight = 'normal';
			img.style.verticalAlign = 'super';

			var middle = (img.offsetTop - container.offsetTop) + 1;
			var metricsObj = {
				baseline: baseline,
				lineWidth: 1,
				middle: middle
			};

			fontData[font + '-' + fontSize] = metricsObj;

			doc.body.removeChild(container);

			return metricsObj;
		};
	})();

	(function ()
	{
		var util = html2Canvas.Util,
			generate = {};

		html2Canvas.Generate = generate;

		var reGradients = [
		/^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
		/^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
		/^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)\-]+)\)$/,
		/^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/,
		/^(-webkit-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/,
		/^(-moz-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s?([a-z\-]*)([\w\d\.\s,%\(\)]+)\)$/,
		/^(-o-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/
		];

		/*
		 * TODO: Add IE10 vendor prefix (-ms) support
		 * TODO: Add W3C gradient (linear-gradient) support
		 * TODO: Add old Webkit -webkit-gradient(radial, ...) support
		 * TODO: Maybe some RegExp optimizations are possible ;o)
		 */
		generate.parseGradient = function (css, bounds)
		{
			var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3, tl, tr, br, bl;

			for (i = 0; i < len; i += 1)
			{
				m1 = css.match(reGradients[i]);
				if (m1)
				{
					break;
				}
			}

			if (m1)
			{
				switch (m1[1])
				{
					case '-webkit-linear-gradient':
					case '-o-linear-gradient':

						gradient = {
							type: 'linear',
							x0: null,
							y0: null,
							x1: null,
							y1: null,
							colorStops: []
						};

						// get coordinates
						m2 = m1[2].match(/\w+/g);
						if (m2)
						{
							m2Len = m2.length;
							for (i = 0; i < m2Len; i += 1)
							{
								switch (m2[i])
								{
									case 'top':
										gradient.y0 = 0;
										gradient.y1 = bounds.height;
										break;

									case 'right':
										gradient.x0 = bounds.width;
										gradient.x1 = 0;
										break;

									case 'bottom':
										gradient.y0 = bounds.height;
										gradient.y1 = 0;
										break;

									case 'left':
										gradient.x0 = 0;
										gradient.x1 = bounds.width;
										break;
								}
							}
						}
						if (gradient.x0 === null && gradient.x1 === null)
						{ // center
							gradient.x0 = gradient.x1 = bounds.width / 2;
						}
						if (gradient.y0 === null && gradient.y1 === null)
						{ // center
							gradient.y0 = gradient.y1 = bounds.height / 2;
						}

						// get colors and stops
						m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);
						if (m2)
						{
							m2Len = m2.length;
							step = 1 / Math.max(m2Len - 1, 1);
							for (i = 0; i < m2Len; i += 1)
							{
								m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);
								if (m3[2])
								{
									stop = parseFloat(m3[2]);
									if (m3[3] === '%')
									{
										stop /= 100;
									} else
									{ // px - stupid opera
										stop /= bounds.width;
									}
								} else
								{
									stop = i * step;
								}
								gradient.colorStops.push({
									color: m3[1],
									stop: stop
								});
							}
						}
						break;

					case '-webkit-gradient':

						gradient = {
							type: m1[2] === 'radial' ? 'circle' : m1[2], // TODO: Add radial gradient support for older mozilla definitions
							x0: 0,
							y0: 0,
							x1: 0,
							y1: 0,
							colorStops: []
						};

						// get coordinates
						m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/);
						if (m2)
						{
							gradient.x0 = (m2[1] * bounds.width) / 100;
							gradient.y0 = (m2[2] * bounds.height) / 100;
							gradient.x1 = (m2[3] * bounds.width) / 100;
							gradient.y1 = (m2[4] * bounds.height) / 100;
						}

						// get colors and stops
						m2 = m1[4].match(/((?:from|to|color-stop)\((?:[0-9\.]+,\s)?(?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)\))+/g);
						if (m2)
						{
							m2Len = m2.length;
							for (i = 0; i < m2Len; i += 1)
							{
								m3 = m2[i].match(/(from|to|color-stop)\(([0-9\.]+)?(?:,\s)?((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\)/);
								stop = parseFloat(m3[2]);
								if (m3[1] === 'from')
								{
									stop = 0.0;
								}
								if (m3[1] === 'to')
								{
									stop = 1.0;
								}
								gradient.colorStops.push({
									color: m3[3],
									stop: stop
								});
							}
						}
						break;

					case '-moz-linear-gradient':

						gradient = {
							type: 'linear',
							x0: 0,
							y0: 0,
							x1: 0,
							y1: 0,
							colorStops: []
						};

						// get coordinates
						m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);

						// m2[1] == 0%   -> left
						// m2[1] == 50%  -> center
						// m2[1] == 100% -> right

						// m2[2] == 0%   -> top
						// m2[2] == 50%  -> center
						// m2[2] == 100% -> bottom

						if (m2)
						{
							gradient.x0 = (m2[1] * bounds.width) / 100;
							gradient.y0 = (m2[2] * bounds.height) / 100;
							gradient.x1 = bounds.width - gradient.x0;
							gradient.y1 = bounds.height - gradient.y0;
						}

						// get colors and stops
						m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}%)?)+/g);
						if (m2)
						{
							m2Len = m2.length;
							step = 1 / Math.max(m2Len - 1, 1);
							for (i = 0; i < m2Len; i += 1)
							{
								m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/);
								if (m3[2])
								{
									stop = parseFloat(m3[2]);
									if (m3[3])
									{ // percentage
										stop /= 100;
									}
								} else
								{
									stop = i * step;
								}
								gradient.colorStops.push({
									color: m3[1],
									stop: stop
								});
							}
						}
						break;

					case '-webkit-radial-gradient':
					case '-moz-radial-gradient':
					case '-o-radial-gradient':

						gradient = {
							type: 'circle',
							x0: 0,
							y0: 0,
							x1: bounds.width,
							y1: bounds.height,
							cx: 0,
							cy: 0,
							rx: 0,
							ry: 0,
							colorStops: []
						};

						// center
						m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
						if (m2)
						{
							gradient.cx = (m2[1] * bounds.width) / 100;
							gradient.cy = (m2[2] * bounds.height) / 100;
						}

						// size
						m2 = m1[3].match(/\w+/);
						m3 = m1[4].match(/[a-z\-]*/);
						if (m2 && m3)
						{
							switch (m3[0])
							{
								case 'farthest-corner':
								case 'cover': // is equivalent to farthest-corner
								case '': // mozilla removes "cover" from definition :(
									tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
									tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
									br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
									bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
									gradient.rx = gradient.ry = Math.max(tl, tr, br, bl);
									break;
								case 'closest-corner':
									tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2));
									tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
									br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2));
									bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2));
									gradient.rx = gradient.ry = Math.min(tl, tr, br, bl);
									break;
								case 'farthest-side':
									if (m2[0] === 'circle')
									{
										gradient.rx = gradient.ry = Math.max(
											gradient.cx,
											gradient.cy,
											gradient.x1 - gradient.cx,
											gradient.y1 - gradient.cy
											);
									} else
									{ // ellipse

										gradient.type = m2[0];

										gradient.rx = Math.max(
											gradient.cx,
											gradient.x1 - gradient.cx
											);
										gradient.ry = Math.max(
											gradient.cy,
											gradient.y1 - gradient.cy
											);
									}
									break;
								case 'closest-side':
								case 'contain': // is equivalent to closest-side
									if (m2[0] === 'circle')
									{
										gradient.rx = gradient.ry = Math.min(
											gradient.cx,
											gradient.cy,
											gradient.x1 - gradient.cx,
											gradient.y1 - gradient.cy
											);
									} else
									{ // ellipse

										gradient.type = m2[0];

										gradient.rx = Math.min(
											gradient.cx,
											gradient.x1 - gradient.cx
											);
										gradient.ry = Math.min(
											gradient.cy,
											gradient.y1 - gradient.cy
											);
									}
									break;

									// TODO: add support for "30px 40px" sizes (webkit only)
							}
						}

						// color stops
						m2 = m1[5].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);
						if (m2)
						{
							m2Len = m2.length;
							step = 1 / Math.max(m2Len - 1, 1);
							for (i = 0; i < m2Len; i += 1)
							{
								m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);
								if (m3[2])
								{
									stop = parseFloat(m3[2]);
									if (m3[3] === '%')
									{
										stop /= 100;
									} else
									{ // px - stupid opera
										stop /= bounds.width;
									}
								} else
								{
									stop = i * step;
								}
								gradient.colorStops.push({
									color: m3[1],
									stop: stop
								});
							}
						}
						break;
				}
			}

			return gradient;
		};

		function addScrollStops(grad)
		{
			return function (colorStop)
			{
				try
				{
					grad.addColorStop(colorStop.stop, colorStop.color);
				}
				catch (e)
				{
					util.log(['failed to add color stop: ', e, '; tried to add: ', colorStop]);
				}
			};
		}

		generate.Gradient = function (src, bounds)
		{
			if (bounds.width === 0 || bounds.height === 0)
			{
				return null;
			}

			var canvas = document.createElement('canvas'),
			ctx = canvas.getContext('2d'),
			gradient, grad;

			canvas.width = bounds.width;
			canvas.height = bounds.height;

			// TODO: add support for multi defined background gradients
			gradient = html2Canvas.Generate.parseGradient(src, bounds);

			if (gradient)
			{
				switch (gradient.type)
				{
					case 'linear':
						grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1);
						gradient.colorStops.forEach(addScrollStops(grad));
						ctx.fillStyle = grad;
						ctx.fillRect(0, 0, bounds.width, bounds.height);
						break;

					case 'circle':
						grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx);
						gradient.colorStops.forEach(addScrollStops(grad));
						ctx.fillStyle = grad;
						ctx.fillRect(0, 0, bounds.width, bounds.height);
						break;

					case 'ellipse':
						var canvasRadial = document.createElement('canvas'),
							ctxRadial = canvasRadial.getContext('2d'),
							ri = Math.max(gradient.rx, gradient.ry),
							di = ri * 2;

						canvasRadial.width = canvasRadial.height = di;

						grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri);
						gradient.colorStops.forEach(addScrollStops(grad));

						ctxRadial.fillStyle = grad;
						ctxRadial.fillRect(0, 0, di, di);

						ctx.fillStyle = gradient.colorStops[gradient.colorStops.length - 1].color;
						ctx.fillRect(0, 0, canvas.width, canvas.height);
						ctx.drawImage(canvasRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry);
						break;
				}
			}

			return canvas;
		};

		generate.ListAlpha = function (number)
		{
			var tmp = '',
			modulus;

			do
			{
				modulus = number % 26;
				tmp = String.fromCharCode((modulus) + 64) + tmp;
				number = number / 26;
			} while ((number * 26) > 26);

			return tmp;
		};

		generate.ListRoman = function (number)
		{
			var romanArray = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'],
			decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
			roman = '',
			v,
			len = romanArray.length;

			if (number <= 0 || number >= 4000)
			{
				return number;
			}

			for (v = 0; v < len; v += 1)
			{
				while (number >= decimal[v])
				{
					number -= decimal[v];
					roman += romanArray[v];
				}
			}

			return roman;
		};
	})();
	function h2CRenderContext(width, height)
	{
		var storage = [];
		return {
			storage: storage,
			width: width,
			height: height,
			clip: function ()
			{
				storage.push({
					type: 'function',
					name: 'clip',
					'arguments': arguments
				});
			},
			translate: function ()
			{
				storage.push({
					type: 'function',
					name: 'translate',
					'arguments': arguments
				});
			},
			fill: function ()
			{
				storage.push({
					type: 'function',
					name: 'fill',
					'arguments': arguments
				});
			},
			save: function ()
			{
				storage.push({
					type: 'function',
					name: 'save',
					'arguments': arguments
				});
			},
			restore: function ()
			{
				storage.push({
					type: 'function',
					name: 'restore',
					'arguments': arguments
				});
			},
			fillRect: function ()
			{
				storage.push({
					type: 'function',
					name: 'fillRect',
					'arguments': arguments
				});
			},
			createPattern: function ()
			{
				storage.push({
					type: 'function',
					name: 'createPattern',
					'arguments': arguments
				});
			},
			drawShape: function ()
			{

				var shape = [];

				storage.push({
					type: 'function',
					name: 'drawShape',
					'arguments': shape
				});

				return {
					moveTo: function ()
					{
						shape.push({
							name: 'moveTo',
							'arguments': arguments
						});
					},
					lineTo: function ()
					{
						shape.push({
							name: 'lineTo',
							'arguments': arguments
						});
					},
					arcTo: function ()
					{
						shape.push({
							name: 'arcTo',
							'arguments': arguments
						});
					},
					bezierCurveTo: function ()
					{
						shape.push({
							name: 'bezierCurveTo',
							'arguments': arguments
						});
					},
					quadraticCurveTo: function ()
					{
						shape.push({
							name: 'quadraticCurveTo',
							'arguments': arguments
						});
					}
				};

			},
			drawImage: function ()
			{
				storage.push({
					type: 'function',
					name: 'drawImage',
					'arguments': arguments
				});
			},
			fillText: function ()
			{
				storage.push({
					type: 'function',
					name: 'fillText',
					'arguments': arguments
				});
			},
			setVariable: function (variable, value)
			{
				storage.push({
					type: 'variable',
					name: variable,
					'arguments': value
				});
				return value;
			}
		};
	}

	function h2CzContext(zindex)
	{
		return {
			zindex: zindex,
			children: []
		};
	}

	html2Canvas.Parse = function (images, options)
	{
		window.scroll(0, 0);

		var element = ((options.elements === undefined) ? document.body : options.elements[0]), // select body by default
		numDraws = 0,
		doc = element.ownerDocument,
		util = html2Canvas.Util,
		support = util.Support(options, doc),
		ignoreElementsRegExp = new RegExp('(' + options.ignoreElements + ')'),
		body = doc.body,
		getCss = util.getCSS,
		pseudoHide = '___html2canvas___pseudoelement',
		hidePseudoElements = doc.createElement('style');

		hidePseudoElements.innerHTML = '.' + pseudoHide + '-before:before { content: "" !important; display: none !important; }' +
		'.' + pseudoHide + '-after:after { content: "" !important; display: none !important; }';

		body.appendChild(hidePseudoElements);

		images = images || {};

		function documentWidth()
		{
			return Math.max(
				Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
				Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
				Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
				);
		}

		function documentHeight()
		{
			return Math.max(
				Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
				Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
				Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
				);
		}

		function getCssInt(element, attribute)
		{
			var val = parseInt(getCss(element, attribute), 10);
			return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html
		}

		function renderRect(ctx, x, y, w, h, bgcolor)
		{
			if (bgcolor !== 'transparent')
			{
				ctx.setVariable('fillStyle', bgcolor);
				ctx.fillRect(x, y, w, h);
				numDraws += 1;
			}
		}

		function capitalize(m, p1, p2)
		{
			if (m.length > 0)
			{
				return p1 + p2.toUpperCase();
			}
			return '';
		}

		function textTransform(text, transform)
		{
			switch (transform)
			{
				case 'lowercase':
					return text.toLowerCase();
				case 'capitalize':
					return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize);
				case 'uppercase':
					return text.toUpperCase();
				default:
					return text;
			}
		}

		function noLetterSpacing(letterSpacing)
		{
			return (/^(normal|none|0px)$/.test(letterSpacing));
		}

		function drawText(currentText, x, y, ctx)
		{
			if (currentText !== null && util.trimText(currentText).length > 0)
			{
				ctx.fillText(currentText, x, y);
				numDraws += 1;
			}
		}

		function setTextVariables(ctx, el, textDecoration, color)
		{
			var bold = getCss(el, 'fontWeight');
			var family = getCss(el, 'fontFamily');
			var size = getCss(el, 'fontSize');
			var shadows = util.parseTextShadows(getCss(el, 'textShadow'));

			switch (parseInt(bold, 10))
			{
				case 401:
					bold = 'bold';
					break;
				case 400:
					bold = 'normal';
					break;
			}

			ctx.setVariable('fillStyle', color);
			ctx.setVariable('font', [getCss(el, 'fontStyle'), getCss(el, 'fontVariant'), bold, size, family].join(' '));
			ctx.setVariable('textAlign', 'left');

			if (shadows.length)
			{
				// TODO: support multiple text shadows
				// apply the first text shadow
				ctx.setVariable('shadowColor', shadows[0].color);
				ctx.setVariable('shadowOffsetX', shadows[0].offsetX);
				ctx.setVariable('shadowOffsetY', shadows[0].offsetY);
				ctx.setVariable('shadowBlur', shadows[0].blur);
			}

			if (textDecoration !== 'none')
			{
				return util.Font(family, size, doc);
			}
			return null;
		}

		function renderTextDecoration(ctx, textDecoration, bounds, metrics, color)
		{
			switch (textDecoration)
			{
				case 'underline':
					// Draws a line at the baseline of the font
					// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
					renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color);
					break;
				case 'overline':
					renderRect(ctx, bounds.left, Math.round(bounds.top), bounds.width, 1, color);
					break;
				case 'line-through':
					// TODO try and find exact position for line-through
					renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color);
					break;
			}
		}

		function textRangeBounds(text, textNode, textOffset)
		{
			var range = doc.createRange();
			range.setStart(textNode, textOffset);
			range.setEnd(textNode, textOffset + text.length);
			return range.getBoundingClientRect();
		}

		function textWrapperBounds(oldTextNode, transform)
		{
			var parent = oldTextNode.parentNode;
			var wrapElement = doc.createElement('wrapper');
			var backupText = oldTextNode.cloneNode(true);

			wrapElement.appendChild(oldTextNode.cloneNode(true));
			parent.replaceChild(wrapElement, oldTextNode);

			var bounds = transform ? util.OffsetBounds(wrapElement) : util.Bounds(wrapElement);
			parent.replaceChild(backupText, wrapElement);
			return bounds;
		}

		function getTextBounds(state, text, textDecoration, isLast, transform)
		{
			var bounds = null;
			if (support.rangeBounds && !transform)
			{
				if (textDecoration !== 'none' || util.trimText(text).length !== 0)
				{
					bounds = textRangeBounds(text, state.node, state.textOffset);
				}
				state.textOffset += text.length;
			} else if (state.node && typeof state.node.nodeValue === 'string')
			{
				var newTextNode = (isLast) ? state.node.splitText(text.length) : null;
				bounds = textWrapperBounds(state.node, transform);
				state.node = newTextNode;
			}
			return bounds;
		}

		function renderText(el, textNode, stack)
		{
			var ctx = stack.ctx;
			var color = getCss(el, 'color');
			var textDecoration = getCss(el, 'textDecoration');
			var textAlign = getCss(el, 'textAlign');
			var metrics;
			var textList;
			var state = {
				node: textNode,
				textOffset: 0
			};

			if (util.trimText(textNode.nodeValue).length > 0)
			{
				textNode.nodeValue = textTransform(textNode.nodeValue, getCss(el, 'textTransform'));
				textAlign = textAlign.replace(['-webkit-auto'], ['auto']);

				textList = (!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCss(el, 'letterSpacing'))) ?
				textNode.nodeValue.split(/(\b| )/)
				: textNode.nodeValue.split('');

				metrics = setTextVariables(ctx, el, textDecoration, color);

				if (options.chinese)
				{
					textList.forEach(function (word, index)
					{
						if (/.*[\u4E00-\u9FA5].*$/.test(word))
						{
							word = word.split('');
							word.unshift(index, 1);
							textList.splice.apply(textList, word);
						}
					});
				}

				textList.forEach(function (text, index)
				{
					var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1), stack.transform.matrix);
					if (bounds)
					{
						drawText(text, bounds.left, bounds.bottom, ctx);
						renderTextDecoration(ctx, textDecoration, bounds, metrics, color);
					}
				});
			}
		}

		function listPosition(element, val)
		{
			var boundElement = doc.createElement('boundelement');

			boundElement.style.display = 'inline';

			var originalType = element.style.listStyleType;
			element.style.listStyleType = 'none';

			boundElement.appendChild(doc.createTextNode(val));

			element.insertBefore(boundElement, element.firstChild);

			var bounds = util.Bounds(boundElement);
			element.removeChild(boundElement);
			element.style.listStyleType = originalType;
			return bounds;
		}

		function elementIndex(el)
		{
			var i = -1;
			var count = 1;
			var childs = el.parentNode.childNodes;

			if (el.parentNode)
			{
				while (childs[++i] !== el)
				{
					if (childs[i].nodeType === 1)
					{
						count++;
					}
				}
				return count;
			} else
			{
				return -1;
			}
		}

		function listItemText(element, type)
		{
			var currentIndex = elementIndex(element);
			var text = '';
			switch (type)
			{
				case 'decimal':
					text = currentIndex;
					break;
				case 'decimal-leading-zero':
					text = (currentIndex.toString().length === 1) ? '0' + currentIndex.toString() : currentIndex.toString();
					break;
				case 'upper-roman':
					text = html2Canvas.Generate.ListRoman(currentIndex);
					break;
				case 'lower-roman':
					text = html2Canvas.Generate.ListRoman(currentIndex).toLowerCase();
					break;
				case 'lower-alpha':
					text = html2Canvas.Generate.ListAlpha(currentIndex).toLowerCase();
					break;
				case 'upper-alpha':
					text = html2Canvas.Generate.ListAlpha(currentIndex);
					break;
			}

			return text + '. ';
		}

		function renderListItem(element, stack, elBounds)
		{
			var x;
			var ctx = stack.ctx;
			var type = getCss(element, 'listStyleType');
			var listBounds;

			if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type))
			{
				var text = listItemText(element, type);
				listBounds = listPosition(element, text);
				setTextVariables(ctx, element, 'none', getCss(element, 'color'));

				if (getCss(element, 'listStylePosition') === 'inside')
				{
					ctx.setVariable('textAlign', 'left');
					x = elBounds.left;
				} else
				{
					return;
				}

				drawText(text, x, listBounds.bottom, ctx);
			}
		}

		function loadImage(src)
		{
			var img = images[src];
			return (img && img.succeeded === true) ? img.img : false;
		}

		function clipBounds(src, dst)
		{
			var x = Math.max(src.left, dst.left);
			var y = Math.max(src.top, dst.top);
			var x2 = Math.min((src.left + src.width), (dst.left + dst.width));
			var y2 = Math.min((src.top + src.height), (dst.top + dst.height));

			return {
				left: x,
				top: y,
				width: x2 - x,
				height: y2 - y
			};
		}

		function setZ(element, stack, parentStack)
		{
			var newContext;
			var isPositioned = stack.cssPosition !== 'static';
			var zIndex = isPositioned ? getCss(element, 'zIndex') : 'auto';
			var opacity = getCss(element, 'opacity');
			var isFloated = getCss(element, 'cssFloat') !== 'none';

			// https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context
			// When a new stacking context should be created:
			// the root element (HTML),
			// positioned (absolutely or relatively) with a z-index value other than "auto",
			// elements with an opacity value less than 1. (See the specification for opacity),
			// on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is "auto" (See this post)

			stack.zIndex = newContext = h2CzContext(zIndex);
			newContext.isPositioned = isPositioned;
			newContext.isFloated = isFloated;
			newContext.opacity = opacity;
			newContext.ownStacking = (zIndex !== 'auto' || opacity < 1);

			if (parentStack)
			{
				parentStack.zIndex.children.push(stack);
			}
		}

		function drawImage(ctx)
		{
			ctx.drawImage.apply(ctx, Array.prototype.slice.call(arguments, 1));
			numDraws += 1;
		}

		function renderImage(ctx, element, image, bounds, borders)
		{
			var paddingLeft = getCssInt(element, 'paddingLeft');
			var paddingTop = getCssInt(element, 'paddingTop');
			var paddingRight = getCssInt(element, 'paddingRight');
			var paddingBottom = getCssInt(element, 'paddingBottom');

			drawImage(
				ctx,
				image,
				0, //sx
				0, //sy
				image.width, //sw
				image.height, //sh
				bounds.left + paddingLeft + borders[3].width, //dx
				bounds.top + paddingTop + borders[0].width, // dy
				bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
				bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
				);
		}

		function getBorderData(element)
		{
			return ['Top', 'Right', 'Bottom', 'Left'].map(function (side)
			{
				return {
					width: getCssInt(element, 'border' + side + 'Width'),
					color: getCss(element, 'border' + side + 'Color')
				};
			});
		}

		function getBorderRadiusData(element)
		{
			return ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'].map(function (side)
			{
				return getCss(element, 'border' + side + 'Radius');
			});
		}

		function bezierCurve(start, startControl, endControl, end)
		{

			var lerp = function (a, b, t)
			{
				return {
					x: a.x + (b.x - a.x) * t,
					y: a.y + (b.y - a.y) * t
				};
			};

			return {
				start: start,
				startControl: startControl,
				endControl: endControl,
				end: end,
				subdivide: function (t)
				{
					var ab = lerp(start, startControl, t);
					var bc = lerp(startControl, endControl, t);
					var cd = lerp(endControl, end, t);
					var abbc = lerp(ab, bc, t);
					var bccd = lerp(bc, cd, t);
					var dest = lerp(abbc, bccd, t);
					return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
				},
				curveTo: function (borderArgs)
				{
					borderArgs.push(['bezierCurve', startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
				},
				curveToReversed: function (borderArgs)
				{
					borderArgs.push(['bezierCurve', endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
				}
			};
		}

		var getCurvePoints = (function (kappa)
		{

			return function (x, y, r1, r2)
			{
				var ox = (r1) * kappa; // control point offset horizontal
				var oy = (r2) * kappa; // control point offset vertical
				var xm = x + r1; // x-middle
				var ym = y + r2; // y-middle
				return {
					topLeft: bezierCurve({
						x: x,
						y: ym
					}, {
						x: x,
						y: ym - oy
					}, {
						x: xm - ox,
						y: y
					}, {
						x: xm,
						y: y
					}),
					topRight: bezierCurve({
						x: x,
						y: y
					}, {
						x: x + ox,
						y: y
					}, {
						x: xm,
						y: ym - oy
					}, {
						x: xm,
						y: ym
					}),
					bottomRight: bezierCurve({
						x: xm,
						y: y
					}, {
						x: xm,
						y: y + oy
					}, {
						x: x + ox,
						y: ym
					}, {
						x: x,
						y: ym
					}),
					bottomLeft: bezierCurve({
						x: xm,
						y: ym
					}, {
						x: xm - ox,
						y: ym
					}, {
						x: x,
						y: y + oy
					}, {
						x: x,
						y: y
					})
				};
			};
		})(4 * ((Math.sqrt(2) - 1) / 3));

		function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y)
		{
			if (radius1[0] > 0 || radius1[1] > 0)
			{
				borderArgs.push(['line', corner1[0].start.x, corner1[0].start.y]);
				corner1[0].curveTo(borderArgs);
				corner1[1].curveTo(borderArgs);
			} else
			{
				borderArgs.push(['line', x, y]);
			}

			if (radius2[0] > 0 || radius2[1] > 0)
			{
				borderArgs.push(['line', corner2[0].start.x, corner2[0].start.y]);
			}
		}

		function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2)
		{
			var borderArgs = [];

			if (radius1[0] > 0 || radius1[1] > 0)
			{
				borderArgs.push(['line', outer1[1].start.x, outer1[1].start.y]);
				outer1[1].curveTo(borderArgs);
			} else
			{
				borderArgs.push(['line', borderData.c1[0], borderData.c1[1]]);
			}

			if (radius2[0] > 0 || radius2[1] > 0)
			{
				borderArgs.push(['line', outer2[0].start.x, outer2[0].start.y]);
				outer2[0].curveTo(borderArgs);
				borderArgs.push(['line', inner2[0].end.x, inner2[0].end.y]);
				inner2[0].curveToReversed(borderArgs);
			} else
			{
				borderArgs.push(['line', borderData.c2[0], borderData.c2[1]]);
				borderArgs.push(['line', borderData.c3[0], borderData.c3[1]]);
			}

			if (radius1[0] > 0 || radius1[1] > 0)
			{
				borderArgs.push(['line', inner1[1].end.x, inner1[1].end.y]);
				inner1[1].curveToReversed(borderArgs);
			} else
			{
				borderArgs.push(['line', borderData.c4[0], borderData.c4[1]]);
			}

			return borderArgs;
		}

		function calculateCurvePoints(bounds, borderRadius, borders)
		{

			var x = bounds.left,
			y = bounds.top,
			width = bounds.width,
			height = bounds.height,

			tlh = borderRadius[0][0],
			tlv = borderRadius[0][1],
			trh = borderRadius[1][0],
			trv = borderRadius[1][1],
			brh = borderRadius[2][0],
			brv = borderRadius[2][1],
			blh = borderRadius[3][0],
			blv = borderRadius[3][1],

			topWidth = width - trh,
			rightHeight = height - brv,
			bottomWidth = width - brh,
			leftHeight = height - blv;

			return {
				topLeftOuter: getCurvePoints(
					x,
					y,
					tlh,
					tlv
					).topLeft.subdivide(0.5),

				topLeftInner: getCurvePoints(
					x + borders[3].width,
					y + borders[0].width,
					Math.max(0, tlh - borders[3].width),
					Math.max(0, tlv - borders[0].width)
					).topLeft.subdivide(0.5),

				topRightOuter: getCurvePoints(
					x + topWidth,
					y,
					trh,
					trv
					).topRight.subdivide(0.5),

				topRightInner: getCurvePoints(
					x + Math.min(topWidth, width + borders[3].width),
					y + borders[0].width,
					(topWidth > width + borders[3].width) ? 0 : trh - borders[3].width,
					trv - borders[0].width
					).topRight.subdivide(0.5),

				bottomRightOuter: getCurvePoints(
					x + bottomWidth,
					y + rightHeight,
					brh,
					brv
					).bottomRight.subdivide(0.5),

				bottomRightInner: getCurvePoints(
					x + Math.min(bottomWidth, width + borders[3].width),
					y + Math.min(rightHeight, height + borders[0].width),
					Math.max(0, brh - borders[1].width),
					Math.max(0, brv - borders[2].width)
					).bottomRight.subdivide(0.5),

				bottomLeftOuter: getCurvePoints(
					x,
					y + leftHeight,
					blh,
					blv
					).bottomLeft.subdivide(0.5),

				bottomLeftInner: getCurvePoints(
					x + borders[3].width,
					y + leftHeight,
					Math.max(0, blh - borders[3].width),
					Math.max(0, blv - borders[2].width)
					).bottomLeft.subdivide(0.5)
			};
		}

		function getBorderClip(element, borderPoints, borders, radius, bounds)
		{
			var backgroundClip = getCss(element, 'backgroundClip'),
			borderArgs = [];

			switch (backgroundClip)
			{
				case 'content-box':
				case 'padding-box':
					parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);
					parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);
					parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);
					parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);
					break;

				default:
					parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);
					parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);
					parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);
					parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);
					break;
			}

			return borderArgs;
		}

		function parseBorders(element, bounds, borders)
		{
			var x = bounds.left,
			y = bounds.top,
			width = bounds.width,
			height = bounds.height,
			borderSide,
			bx,
			by,
			bw,
			bh,
			borderArgs,
			// http://www.w3.org/TR/css3-background/#the-border-radius
			borderRadius = getBorderRadiusData(element),
			borderPoints = calculateCurvePoints(bounds, borderRadius, borders),
			borderData = {
				clip: getBorderClip(element, borderPoints, borders, borderRadius, bounds),
				borders: []
			};

			for (borderSide = 0; borderSide < 4; borderSide++)
			{

				if (borders[borderSide].width > 0)
				{
					bx = x;
					by = y;
					bw = width;
					bh = height - (borders[2].width);

					switch (borderSide)
					{
						case 0:
							// top border
							bh = borders[0].width;

							borderArgs = drawSide({
								c1: [bx, by],
								c2: [bx + bw, by],
								c3: [bx + bw - borders[1].width, by + bh],
								c4: [bx + borders[3].width, by + bh]
							}, borderRadius[0], borderRadius[1],
							borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);
							break;
						case 1:
							// right border
							bx = x + width - (borders[1].width);
							bw = borders[1].width;

							borderArgs = drawSide({
								c1: [bx + bw, by],
								c2: [bx + bw, by + bh + borders[2].width],
								c3: [bx, by + bh],
								c4: [bx, by + borders[0].width]
							}, borderRadius[1], borderRadius[2],
							borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);
							break;
						case 2:
							// bottom border
							by = (by + height) - (borders[2].width);
							bh = borders[2].width;

							borderArgs = drawSide({
								c1: [bx + bw, by + bh],
								c2: [bx, by + bh],
								c3: [bx + borders[3].width, by],
								c4: [bx + bw - borders[3].width, by]
							}, borderRadius[2], borderRadius[3],
							borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);
							break;
						case 3:
							// left border
							bw = borders[3].width;

							borderArgs = drawSide({
								c1: [bx, by + bh + borders[2].width],
								c2: [bx, by],
								c3: [bx + bw, by + borders[0].width],
								c4: [bx + bw, by + bh]
							}, borderRadius[3], borderRadius[0],
							borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);
							break;
					}

					borderData.borders.push({
						args: borderArgs,
						color: borders[borderSide].color
					});

				}
			}

			return borderData;
		}

		function createShape(ctx, args)
		{
			var shape = ctx.drawShape();
			args.forEach(function (border, index)
			{
				shape[(index === 0) ? 'moveTo' : border[0] + 'To'].apply(null, border.slice(1));
			});
			return shape;
		}

		function renderBorders(ctx, borderArgs, color)
		{
			if (color !== 'transparent')
			{
				ctx.setVariable('fillStyle', color);
				createShape(ctx, borderArgs);
				ctx.fill();
				numDraws += 1;
			}
		}

		function renderFormValue(el, bounds, stack)
		{
			var valueWrap = doc.createElement('valuewrap');
			var cssPropertyArray = ['lineHeight', 'textAlign', 'fontFamily', 'color', 'fontSize', 'paddingLeft', 'paddingTop', 'width', 'height', 'border', 'borderLeftWidth', 'borderTopWidth'];

			cssPropertyArray.forEach(function (property)
			{
				try
				{
					valueWrap.style[property] = getCss(el, property);
				} catch (e)
				{
					// Older IE has issues with "border"
					util.log('html2canvas: Parse: Exception caught in renderFormValue: ' + e.message);
				}
			});

			valueWrap.style.borderColor = 'black';
			valueWrap.style.borderStyle = 'solid';
			valueWrap.style.display = 'block';
			valueWrap.style.position = 'absolute';

			if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName === 'SELECT')
			{
				valueWrap.style.lineHeight = getCss(el, 'height');
			}

			valueWrap.style.top = bounds.top + 'px';
			valueWrap.style.left = bounds.left + 'px';

			var textValue = (el.nodeName === 'SELECT') ? (el.options[el.selectedIndex] || 0).text : el.value;
			if (!textValue)
			{
				textValue = el.placeholder;
			}

			var textNode = doc.createTextNode(textValue);

			valueWrap.appendChild(textNode);
			body.appendChild(valueWrap);

			renderText(el, textNode, stack);
			body.removeChild(valueWrap);
		}

		function indexedProperty(property)
		{
			return (isNaN(window.parseInt(property, 10)));
		}

		function getPseudoElement(el, which)
		{
			var elStyle = window.getComputedStyle(el, which);
			if (!elStyle || !elStyle.content || elStyle.content === 'none' || elStyle.content === '-moz-alt-content' || elStyle.display === 'none')
			{
				return null;
			}
			var content = elStyle.content + '',
			first = content.substr(0, 1);
			//strips quotes
			if (first === content.substr(content.length - 1) && first.match(/'|"/))
			{
				content = content.substr(1, content.length - 2);
			}

			var isImage = content.substr(0, 3) === 'url',
			elps = document.createElement(isImage ? 'img' : 'span');

			elps.className = pseudoHide + '-before ' + pseudoHide + '-after';

			Object.keys(elStyle).filter(indexedProperty).forEach(function (prop)
			{
				// Prevent assigning of read only CSS Rules, ex. length, parentRule
				try
				{
					elps.style[prop] = elStyle[prop];
				} catch (e)
				{
					util.log(['Tried to assign readonly property ', prop, 'Error:', e]);
				}
			});

			if (isImage)
			{
				elps.src = util.parseBackgroundImage(content)[0].args[0];
			} else
			{
				elps.innerHTML = content;
			}
			return elps;
		}

		function isElementVisible(element)
		{
			return (getCss(element, 'display') !== 'none' && getCss(element, 'visibility') !== 'hidden' && !element.hasAttribute('data-html2canvas-ignore'));
		}

		function removePx(str)
		{
			return str.replace('px', '');
		}

		function getTransform(element)
		{
			var transform = getCss(element, 'transform') || getCss(element, '-webkit-transform') || getCss(element, '-moz-transform') || getCss(element, '-ms-transform') || getCss(element, '-o-transform');
			var transformOrigin = getCss(element, 'transform-origin') || getCss(element, '-webkit-transform-origin') || getCss(element, '-moz-transform-origin') || getCss(element, '-ms-transform-origin') || getCss(element, '-o-transform-origin') || '0px 0px';

			transformOrigin = transformOrigin.split(' ').map(removePx).map(util.asFloat);

			var matrix = null;
			if (transform && transform !== 'none')
			{
				var match = transform.match(transformRegExp);
				if (match)
				{
					switch (match[1])
					{
						case 'matrix':
							matrix = match[2].split(',').map(util.trimText).map(util.asFloat);
							break;
					}
				}
			}

			return {
				origin: transformOrigin,
				matrix: matrix
			};
		}

		function getBounds(element, transform)
		{
			var bounds = (transform.matrix) ? util.OffsetBounds(element) : util.Bounds(element);
			transform.origin[0] += bounds.left;
			transform.origin[1] += bounds.top;
			return bounds;
		}

		function setOpacity(ctx, element, parentStack)
		{
			return ctx.setVariable('globalAlpha', getCss(element, 'opacity') * ((parentStack) ? parentStack.opacity : 1));
		}

		function createStack(element, parentStack, bounds, transform)
		{
			var ctx = h2CRenderContext((!parentStack) ? documentWidth() : bounds.width, (!parentStack) ? documentHeight() : bounds.height);
			var stack = {
				ctx: ctx,
				opacity: setOpacity(ctx, element, parentStack),
				cssPosition: getCss(element, 'position'),
				borders: getBorderData(element),
				transform: transform,
				clip: (parentStack && parentStack.clip) ? util.Extend({}, parentStack.clip) : null
			};

			setZ(element, stack, parentStack);

			// TODO correct overflow for absolute content residing under a static position
			if (options.useOverflow === true && /(hidden|scroll|auto)/.test(getCss(element, 'overflow')) === true && /(BODY)/i.test(element.nodeName) === false)
			{
				stack.clip = (stack.clip) ? clipBounds(stack.clip, bounds) : bounds;
			}

			return stack;
		}

		function getBackgroundBounds(borders, bounds, clip)
		{
			var backgroundBounds = {
				left: bounds.left + borders[3].width,
				top: bounds.top + borders[0].width,
				width: bounds.width - (borders[1].width + borders[3].width),
				height: bounds.height - (borders[0].width + borders[2].width)
			};

			if (clip)
			{
				backgroundBounds = clipBounds(backgroundBounds, clip);
			}

			return backgroundBounds;
		}

		function renderBackgroundColor(ctx, backgroundBounds, bgcolor)
		{
			renderRect(
				ctx,
				backgroundBounds.left,
				backgroundBounds.top,
				backgroundBounds.width,
				backgroundBounds.height,
				bgcolor
			);
		}

		function resizeImage(image, bounds)
		{
			if (image.width === bounds.width && image.height === bounds.height)
			{
				return image;
			}

			var canvas = doc.createElement('canvas');
			canvas.width = bounds.width;
			canvas.height = bounds.height;
			var ctx = canvas.getContext('2d');
			drawImage(ctx, image, 0, 0, image.width, image.height, 0, 0, bounds.width, bounds.height);
			return canvas;
		}

		function renderBackgroundRepeat(ctx, image, backgroundPosition, bounds)
		{
			var offsetX = Math.round(bounds.left + backgroundPosition.left);
			var offsetY = Math.round(bounds.top + backgroundPosition.top);

			ctx.createPattern(image);
			ctx.translate(offsetX, offsetY);
			ctx.fill();
			ctx.translate(-offsetX, -offsetY);
		}

		function backgroundRepeatShape(ctx, image, backgroundPosition, bounds, left, top, width, height)
		{
			var args = [];
			args.push(['line', Math.round(left), Math.round(top)]);
			args.push(['line', Math.round(left + width), Math.round(top)]);
			args.push(['line', Math.round(left + width), Math.round(height + top)]);
			args.push(['line', Math.round(left), Math.round(height + top)]);
			createShape(ctx, args);
			ctx.save();
			ctx.clip();
			renderBackgroundRepeat(ctx, image, backgroundPosition, bounds);
			ctx.restore();
		}

		function renderBackgroundRepeating(el, bounds, ctx, image, imageIndex)
		{
			var backgroundSize = util.BackgroundSize(el, bounds, image, imageIndex);
			var backgroundPosition = util.BackgroundPosition(el, bounds, image, imageIndex, backgroundSize);
			var backgroundRepeat = getCss(el, 'backgroundRepeat').split(',').map(util.trimText);

			image = resizeImage(image, backgroundSize);

			backgroundRepeat = backgroundRepeat[imageIndex] || backgroundRepeat[0];

			switch (backgroundRepeat)
			{
				case 'repeat-x':
					backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
						bounds.left, bounds.top + backgroundPosition.top, 99999, image.height);
					break;

				case 'repeat-y':
					backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
						bounds.left + backgroundPosition.left, bounds.top, image.width, 99999);
					break;

				case 'no-repeat':
					backgroundRepeatShape(ctx, image, backgroundPosition, bounds,
						bounds.left + backgroundPosition.left, bounds.top + backgroundPosition.top, image.width, image.height);
					break;

				default:
					renderBackgroundRepeat(ctx, image, backgroundPosition, {
						top: bounds.top,
						left: bounds.left,
						width: image.width,
						height: image.height
					});
					break;
			}
		}

		function renderBackgroundImage(element, bounds, ctx)
		{
			var backgroundImage = getCss(element, 'backgroundImage');
			var backgroundImages = util.parseBackgroundImage(backgroundImage);
			var image;
			var imageIndex = backgroundImages.length;

			while (imageIndex--)
			{
				backgroundImage = backgroundImages[imageIndex];

				if (!backgroundImage.args || backgroundImage.args.length === 0)
				{
					continue;
				}

				var key = backgroundImage.method === 'url' ?
					backgroundImage.args[0] :
					backgroundImage.value;

				image = loadImage(key);

				// TODO add support for background-origin
				if (image)
				{
					renderBackgroundRepeating(element, bounds, ctx, image, imageIndex);
				} else
				{
					util.log('html2canvas: Error loading background:', backgroundImage);
				}
			}
		}

		function parseElement(element, stack, pseudoElement)
		{
			if (isElementVisible(element))
			{
				// ReSharper disable once FunctionsUsedBeforeDeclared
				stack = renderElement(element, stack, pseudoElement, false) || stack;
				if (!ignoreElementsRegExp.test(element.nodeName))
				{
					// ReSharper disable once FunctionsUsedBeforeDeclared
					parseChildren(element, stack, pseudoElement);
				}
			}
		}

		function injectPseudoElements(el, stack)
		{
			var before = getPseudoElement(el, ':before');
			var after = getPseudoElement(el, ':after');
			if (!before && !after)
			{
				return;
			}

			if (before)
			{
				el.className += ' ' + pseudoHide + '-before';
				el.parentNode.insertBefore(before, el);
				parseElement(before, stack, true);
				el.parentNode.removeChild(before);
				el.className = el.className.replace(pseudoHide + '-before', '').trim();
			}

			if (after)
			{
				el.className += ' ' + pseudoHide + '-after';
				el.appendChild(after);
				parseElement(after, stack, true);
				el.removeChild(after);
				el.className = el.className.replace(pseudoHide + '-after', '').trim();
			}

		}

		function renderElement(element, parentStack, pseudoElement, ignoreBackground)
		{
			var transform = getTransform(element, parentStack);
			var bounds = getBounds(element, transform);
			var image;
			var stack = createStack(element, parentStack, bounds, transform);
			var borders = stack.borders;
			var ctx = stack.ctx;
			var backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip);
			var borderData = parseBorders(element, bounds, borders);
			var backgroundColor = (ignoreElementsRegExp.test(element.nodeName)) ? '#efefef' : getCss(element, 'backgroundColor');

			createShape(ctx, borderData.clip);

			ctx.save();
			ctx.clip();

			if (backgroundBounds.height > 0 && backgroundBounds.width > 0 && !ignoreBackground)
			{
				renderBackgroundColor(ctx, bounds, backgroundColor);
				renderBackgroundImage(element, backgroundBounds, ctx);
			} else if (ignoreBackground)
			{
				stack.backgroundColor = backgroundColor;
			}

			ctx.restore();

			borderData.borders.forEach(function (border)
			{
				renderBorders(ctx, border.args, border.color);
			});

			if (!pseudoElement)
			{
				injectPseudoElements(element, stack);
			}

			switch (element.nodeName)
			{
				case 'IMG':
					if ((image = loadImage(element.getAttribute('src'))))
					{
						renderImage(ctx, element, image, bounds, borders);
					} else
					{
						util.log('html2canvas: Error loading <img>:' + element.getAttribute('src'));
					}
					break;
				case 'INPUT':
					// TODO add all relevant type's, i.e. HTML5 new stuff
					// todo add support for placeholder attribute for browsers which support it
					if (/^(text|url|email|submit|button|reset)$/.test(element.type) && (element.value || element.placeholder || '').length > 0)
					{
						renderFormValue(element, bounds, stack);
					}
					break;
				case 'TEXTAREA':
					if ((element.value || element.placeholder || '').length > 0)
					{
						renderFormValue(element, bounds, stack);
					}
					break;
				case 'SELECT':
					if ((element.options || element.placeholder || '').length > 0)
					{
						renderFormValue(element, bounds, stack);
					}
					break;
				case 'LI':
					renderListItem(element, stack, backgroundBounds);
					break;
				case 'CANVAS':
					renderImage(ctx, element, element, bounds, borders);
					break;
			}

			return stack;
		}

		var transformRegExp = /(matrix)\((.+)\)/;

		function parseChildren(element, stack, pseudoElement)
		{
			util.Children(element).forEach(function (node)
			{
				if (node.nodeType === node.ELEMENT_NODE)
				{
					parseElement(node, stack, pseudoElement);
				} else if (node.nodeType === node.TEXT_NODE)
				{
					renderText(element, node, stack);
				}
			});
		}

		function init()
		{
			var background = getCss(document.documentElement, 'backgroundColor'),
				transparentBackground = (util.isTransparent(background) && element === document.body),
				stack = renderElement(element, null, false, transparentBackground);
			parseChildren(element, stack);

			if (transparentBackground)
			{
				background = stack.backgroundColor;
			}

			body.removeChild(hidePseudoElements);
			return {
				backgroundColor: background,
				stack: stack
			};
		}

		return init();
	};
	html2Canvas.Preload = function (options)
	{
		var images = {
			numLoaded: 0, // also failed are counted here
			numFailed: 0,
			numTotal: 0,
			cleanupDone: false
		};
		var util = html2Canvas.Util;
		var i;
		var count = 0;
		var element = options.elements[0] || document.body;
		var doc = element.ownerDocument;
		var domImages = element.getElementsByTagName('img'); // Fetch images of the present element only
		var imgLen = domImages.length;
		var link = doc.createElement('a');
		var supportCors = (function (img)
		{
			return (img.crossOrigin !== undefined);
		})(new Image());
		var timeoutTimer;

		link.href = window.location.href;
		var pageOrigin = link.protocol + link.host;

		function isSameOrigin(url)
		{
			link.href = url;
			link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/
			var origin = link.protocol + link.host;
			return (origin === pageOrigin);
		}

		function start()
		{
			util.log('html2canvas: start: images: ' + images.numLoaded + ' / ' + images.numTotal + ' (failed: ' + images.numFailed + ')');
			if (!images.firstRun && images.numLoaded >= images.numTotal)
			{
				util.log('Finished loading images: # ' + images.numTotal + ' (failed: ' + images.numFailed + ')');

				if (typeof options.complete === 'function')
				{
					options.complete(images);
				}

			}
		}

		// TODO modify proxy to serve images with CORS enabled, where available
		function setImageLoadHandlers(img, imageObj)
		{
			img.onload = function ()
			{
				if (imageObj.timer !== undefined)
				{
					// CORS succeeded
					window.clearTimeout(imageObj.timer);
				}

				images.numLoaded++;
				imageObj.succeeded = true;
				img.onerror = img.onload = null;
				start();
			};
			img.onerror = function ()
			{
				if (img.crossOrigin === 'anonymous')
				{
					// CORS failed
					window.clearTimeout(imageObj.timer);

					// let's try with proxy instead
					if (options.proxy)
					{
						var src = img.src;
						img = new Image();
						imageObj.img = img;
						img.src = src;

						// ReSharper disable once FunctionsUsedBeforeDeclared
						proxyGetImage(img.src, img, imageObj);
						return;
					}
				}

				images.numLoaded++;
				images.numFailed++;
				imageObj.succeeded = false;
				img.onerror = img.onload = null;
				start();
			};
		}

		function proxyGetImage(url, img, imageObj)
		{
			var scriptUrl = options.proxy;
			link.href = url;
			url = link.href; // work around for pages with base href="" set - WARNING: this may change the url

			var callbackName = 'html2canvas_' + (count++);
			imageObj.callbackname = callbackName;

			if (scriptUrl.indexOf('?') > -1)
			{
				scriptUrl += '&';
			} else
			{
				scriptUrl += '?';
			}
			scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callbackName;
			var script = doc.createElement('script');

			window[callbackName] = function (a)
			{
				if (a.substring(0, 6) === 'error:')
				{
					imageObj.succeeded = false;
					images.numLoaded++;
					images.numFailed++;
					start();
				} else
				{
					setImageLoadHandlers(img, imageObj);
					img.src = a;
				}
				window[callbackName] = undefined; // to work with IE<9  // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
				try
				{
					delete window[callbackName];  // for all browser that support this
				} catch (ex) { }
				script.parentNode.removeChild(script);
				script = null;
				delete imageObj.script;
				delete imageObj.callbackname;
			};

			script.setAttribute('type', 'text/javascript');
			script.setAttribute('src', scriptUrl);
			imageObj.script = script;
			window.document.body.appendChild(script);

		}

		function invalidBackgrounds(backgroundImage)
		{
			return (backgroundImage && backgroundImage.method && backgroundImage.args && backgroundImage.args.length > 0);
		}

		function loadGradientImage(backgroundImage, bounds)
		{
			var img = html2Canvas.Generate.Gradient(backgroundImage, bounds);

			if (img !== undefined)
			{
				images[backgroundImage] = {
					img: img,
					succeeded: true
				};
				images.numTotal++;
				images.numLoaded++;
				start();
			}
		}

		function loadBackgroundImages(backgroundImage, el)
		{
			var bounds;

			html2Canvas.Util.parseBackgroundImage(backgroundImage).filter(invalidBackgrounds).forEach(function (backgroundImage)
			{
				if (backgroundImage.method === 'url')
				{
					methods.loadImage(backgroundImage.args[0]);
				} else if (backgroundImage.method.match(/\-?gradient$/))
				{
					if (bounds === undefined)
					{
						bounds = html2Canvas.Util.Bounds(el);
					}
					loadGradientImage(backgroundImage.value, bounds);
				}
			});
		}

		function loadPseudoElement(element, type)
		{
			var style = window.getComputedStyle(element, type),
			content = style.content;
			if (content.substr(0, 3) === 'url')
			{
				methods.loadImage(html2Canvas.Util.parseBackgroundImage(content)[0].args[0]);
			}
			loadBackgroundImages(style.backgroundImage, element);
		}

		function loadPseudoElementImages(element)
		{
			loadPseudoElement(element, ':before');
			loadPseudoElement(element, ':after');
		}

		function getImages(el)
		{
			var elNodeType;

			// Firefox fails with permission denied on pages with iframes
			var e;
			try
			{
				util.Children(el).forEach(getImages);
			}
			catch (e) { }

			try
			{
				elNodeType = el.nodeType;
			} catch (ex)
			{
				elNodeType = false;
				util.log('html2canvas: failed to access some element\'s nodeType - Exception: ' + ex.message);
			}

			if (elNodeType === 1 || elNodeType === undefined)
			{
				loadPseudoElementImages(el);
				try
				{
					loadBackgroundImages(util.getCSS(el, 'backgroundImage'), el);
				} catch (e)
				{
					util.log('html2canvas: failed to get background-image - Exception: ' + e.message);
				}
				loadBackgroundImages(el);
			}
		}

		var methods = {
			loadImage: function (src)
			{
				var img, imageObj;
				if (src && images[src] === undefined)
				{
					img = new Image();
					if (src.match(/data:image\/.*;base64,/i))
					{
						img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
						imageObj = images[src] = {
							img: img
						};
						images.numTotal++;
						setImageLoadHandlers(img, imageObj);
					} else if (isSameOrigin(src) || options.allowTaint === true)
					{
						imageObj = images[src] = {
							img: img
						};
						images.numTotal++;
						setImageLoadHandlers(img, imageObj);
						img.src = src;
					} else if (supportCors && !options.allowTaint && options.useCORS)
					{
						// attempt to load with CORS

						img.crossOrigin = 'anonymous';
						imageObj = images[src] = {
							img: img
						};
						images.numTotal++;
						setImageLoadHandlers(img, imageObj);
						img.src = src;
					} else if (options.proxy)
					{
						imageObj = images[src] = {
							img: img
						};
						images.numTotal++;
						proxyGetImage(src, img, imageObj);
					}
				}

			},
			cleanupDOM: function (cause)
			{
				var img, src;
				if (!images.cleanupDone)
				{
					if (cause && typeof cause === 'string')
					{
						util.log('html2canvas: Cleanup because: ' + cause);
					} else
					{
						util.log('html2canvas: Cleanup after timeout: ' + options.timeout + ' ms.');
					}

					for (src in images)
					{
						if (images.hasOwnProperty(src))
						{
							img = images[src];
							if (img && typeof img === 'object' && img.callbackname && img.succeeded === undefined)
							{
								// cancel proxy image request
								window[img.callbackname] = undefined; // to work with IE<9  // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
								try
								{
									delete window[img.callbackname];  // for all browser that support this
								} catch (ex) { }
								if (img.script && img.script.parentNode)
								{
									img.script.setAttribute('src', 'about:blank');  // try to cancel running request
									img.script.parentNode.removeChild(img.script);
								}
								images.numLoaded++;
								images.numFailed++;
								util.log('html2canvas: Cleaned up failed img: \'' + src + '\' Steps: ' + images.numLoaded + ' / ' + images.numTotal);
							}
						}
					}

					// cancel any pending requests
					if (window.stop !== undefined)
					{
						window.stop();
					} else if (document.execCommand !== undefined)
					{
						document.execCommand('Stop', false);
					}
					if (document.close !== undefined)
					{
						document.close();
					}
					images.cleanupDone = true;
					if (!(cause && typeof cause === 'string'))
					{
						start();
					}
				}
			},

			renderingDone: function ()
			{
				if (timeoutTimer)
				{
					window.clearTimeout(timeoutTimer);
				}
			}
		};

		if (options.timeout > 0)
		{
			timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);
		}

		util.log('html2canvas: Preload starts: finding background-images');
		images.firstRun = true;

		getImages(element);

		util.log('html2canvas: Preload: Finding images');
		// load <img> images
		for (i = 0; i < imgLen; i += 1)
		{
			methods.loadImage(domImages[i].getAttribute('src'));
		}

		images.firstRun = false;
		util.log('html2canvas: Preload: Done.');
		if (images.numTotal === images.numLoaded)
		{
			start();
		}

		return methods;
	};

	html2Canvas.Renderer = function (parseQueue, options)
	{

		// http://www.w3.org/TR/CSS21/zindex.html
		function createRenderQueue(parseQueue)
		{
			var queue = [];

			var rootContext = (function buildStackingContext(rootNode)
			{
				var rootContext = {};
				function insert(context, node, specialParent)
				{
					var zi = (node.zIndex.zindex === 'auto') ? 0 : Number(node.zIndex.zindex),
						contextForChildren = context, // the stacking context for children
						isPositioned = node.zIndex.isPositioned,
						isFloated = node.zIndex.isFloated,
						stub = { node: node },
						childrenDest = specialParent; // where children without z-index should be pushed into

					if (node.zIndex.ownStacking)
					{
						// '!' comes before numbers in sorted array
						contextForChildren = stub.context = { '!': [{ node: node, children: [] }] };
						childrenDest = undefined;
					} else if (isPositioned || isFloated)
					{
						childrenDest = stub.children = [];
					}

					if (zi === 0 && specialParent)
					{
						specialParent.push(stub);
					} else
					{
						if (!context[zi]) { context[zi] = []; }
						context[zi].push(stub);
					}

					node.zIndex.children.forEach(function (childNode)
					{
						insert(contextForChildren, childNode, childrenDest);
					});
				}
				insert(rootContext, rootNode);
				return rootContext;
			})(parseQueue);

			function sortZ(context)
			{
				Object.keys(context).sort().forEach(function (zi)
				{
					var nonPositioned = [],
					floated = [],
					positioned = [],
					list = [];

					// positioned after static
					context[zi].forEach(function (v)
					{
						if (v.node.zIndex.isPositioned || v.node.zIndex.opacity < 1)
						{
							// http://www.w3.org/TR/css3-color/#transparency
							// non-positioned element with opactiy < 1 should be stacked as if it were a positioned element with �z-index: 0� and �opacity: 1�.
							positioned.push(v);
						} else if (v.node.zIndex.isFloated)
						{
							floated.push(v);
						} else
						{
							nonPositioned.push(v);
						}
					});

					(function walk(arr)
					{
						arr.forEach(function (v)
						{
							list.push(v);
							if (v.children) { walk(v.children); }
						});
					})(nonPositioned.concat(floated, positioned));

					list.forEach(function (v)
					{
						if (v.context)
						{
							sortZ(v.context);
						} else
						{
							queue.push(v.node);
						}
					});
				});
			}

			sortZ(rootContext);

			return queue;
		}

		function getRenderer(rendererName)
		{
			var renderer;

			if (typeof options.renderer === 'string' && html2Canvas.Renderer[rendererName] !== undefined)
			{
				renderer = html2Canvas.Renderer[rendererName](options);
			} else if (typeof rendererName === 'function')
			{
				renderer = rendererName(options);
			} else
			{
				throw new Error('Unknown renderer');
			}

			if (typeof renderer !== 'function')
			{
				throw new Error('Invalid renderer defined');
			}
			return renderer;
		}

		return getRenderer(options.renderer)(parseQueue, options, document, createRenderQueue(parseQueue.stack), html2Canvas);
	};

	html2Canvas.Util.Support = function (options, doc)
	{

		function supportSvgRendering()
		{
			var img = new Image(),
			canvas = doc.createElement('canvas'),
			ctx = (canvas.getContext === undefined) ? false : canvas.getContext('2d');
			if (ctx === false)
			{
				return false;
			}
			canvas.width = canvas.height = 10;
			img.src = [
			'data:image/svg+xml,',
			'<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'10\' height=\'10\'>',
			'<foreignObject width=\'10\' height=\'10\'>',
			'<div xmlns=\'http://www.w3.org/1999/xhtml\' style=\'width:10;height:10;\'>',
			'sup',
			'</div>',
			'</foreignObject>',
			'</svg>'
			].join('');
			try
			{
				ctx.drawImage(img, 0, 0);
				canvas.toDataURL();
			} catch (e)
			{
				return false;
			}
			html2Canvas.Util.log('html2canvas: Parse: SVG powered rendering available');
			return true;
		}

		// Test whether we can use ranges to measure bounding boxes
		// Opera doesn't provide valid bounds.height/bottom even though it supports the method.

		function supportRangeBounds()
		{
			var r, testElement, rangeBounds, rangeHeight, support = false;

			if (doc.createRange)
			{
				r = doc.createRange();
				if (r.getBoundingClientRect)
				{
					testElement = doc.createElement('boundtest');
					testElement.style.height = '123px';
					testElement.style.display = 'block';
					doc.body.appendChild(testElement);

					r.selectNode(testElement);
					rangeBounds = r.getBoundingClientRect();
					rangeHeight = rangeBounds.height;

					if (rangeHeight === 123)
					{
						support = true;
					}
					doc.body.removeChild(testElement);
				}
			}

			return support;
		}

		return {
			rangeBounds: supportRangeBounds(),
			svgRendering: options.svgRendering && supportSvgRendering()
		};
	};
	window.html2canvas = function (elements, opts)
	{
		elements = (elements.length) ? elements : [elements];
		var queue,
		canvas,
		options = {
			// general
			logging: false,
			elements: elements,
			background: '#fff',

			// preload options
			proxy: null,
			timeout: 0,    // no timeout
			useCORS: false, // try to load images as CORS (where available), before falling back to proxy
			allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true

			// parse options
			svgRendering: false, // use svg powered rendering where available (FF11+)
			ignoreElements: 'IFRAME|OBJECT|PARAM',
			useOverflow: true,
			letterRendering: false,
			chinese: false,

			// render options

			width: null,
			height: null,
			taintTest: true, // do a taint test with all images before applying to canvas
			renderer: 'Canvas'
		};

		options = html2Canvas.Util.Extend(opts, options);

		html2Canvas.logging = options.logging;
		options.complete = function (images)
		{

			if (typeof options.onpreloaded === 'function')
			{
				if (options.onpreloaded(images) === false)
				{
					return;
				}
			}
			queue = html2Canvas.Parse(images, options);

			if (typeof options.onparsed === 'function')
			{
				if (options.onparsed(queue) === false)
				{
					return;
				}
			}

			canvas = html2Canvas.Renderer(queue, options);

			if (typeof options.onrendered === 'function')
			{
				options.onrendered(canvas);
			}


		};

		// for pages without images, we still want this to be async, i.e. return methods before executing
		window.setTimeout(function ()
		{
			html2Canvas.Preload(options);
		}, 0);

		return {
			render: function (queue, opts)
			{
				return html2Canvas.Renderer(queue, html2Canvas.Util.Extend(opts, options));
			},
			parse: function (images, opts)
			{
				return html2Canvas.Parse(images, html2Canvas.Util.Extend(opts, options));
			},
			preload: function (opts)
			{
				return html2Canvas.Preload(html2Canvas.Util.Extend(opts, options));
			},
			log: html2Canvas.Util.log
		};
	};

	window.html2canvas.log = html2Canvas.Util.log; // for renderers
	window.html2canvas.Renderer = {
		Canvas: undefined // We are assuming this will be used
	};
	html2Canvas.Renderer.Canvas = function (options)
	{
		options = options || {};

		var doc = document,
		safeImages = [],
		testCanvas = document.createElement('canvas'),
		testctx = testCanvas.getContext('2d'),
		util = html2Canvas.Util,
		canvas = options.canvas || doc.createElement('canvas');

		function createShape(ctx, args)
		{
			ctx.beginPath();
			args.forEach(function (arg)
			{
				ctx[arg.name].apply(ctx, arg['arguments']);
			});
			ctx.closePath();
		}

		function safeImage(item)
		{
			if (safeImages.indexOf(item['arguments'][0].src) === -1)
			{
				testctx.drawImage(item['arguments'][0], 0, 0);
				try
				{
					testctx.getImageData(0, 0, 1, 1);
				} catch (e)
				{
					testCanvas = doc.createElement('canvas');
					testctx = testCanvas.getContext('2d');
					return false;
				}
				safeImages.push(item['arguments'][0].src);
			}
			return true;
		}

		function renderItem(ctx, item)
		{
			switch (item.type)
			{
				case 'variable':
					ctx[item.name] = item['arguments'];
					break;
				case 'function':
					switch (item.name)
					{
						case 'createPattern':
							if (item['arguments'][0].width > 0 && item['arguments'][0].height > 0)
							{
								try
								{
									ctx.fillStyle = ctx.createPattern(item['arguments'][0], 'repeat');
								}
								catch (e)
								{
									util.log('html2canvas: Renderer: Error creating pattern', e.message);
								}
							}
							break;
						case 'drawShape':
							createShape(ctx, item['arguments']);
							break;
						case 'drawImage':
							if (item['arguments'][8] > 0 && item['arguments'][7] > 0)
							{
								if (!options.taintTest || (options.taintTest && safeImage(item)))
								{
									ctx.drawImage.apply(ctx, item['arguments']);
								}
							}
							break;
						default:
							ctx[item.name].apply(ctx, item['arguments']);
					}
					break;
			}
		}

		return function (parsedData, options, document, queue, html2CanvasInstance)
		{
			var ctx = canvas.getContext('2d');
			var newCanvas;
			var bounds;
			var zStack = parsedData.stack;

			canvas.width = canvas.style.width = options.width || zStack.ctx.width;
			canvas.height = canvas.style.height = options.height || zStack.ctx.height;

			var fstyle = ctx.fillStyle;
			ctx.fillStyle = (util.isTransparent(zStack.backgroundColor) && options.background !== undefined) ? options.background : parsedData.backgroundColor;
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			ctx.fillStyle = fstyle;

			queue.forEach(function (storageContext)
			{
				// set common settings for canvas
				ctx.textBaseline = 'bottom';
				ctx.save();

				if (storageContext.transform.matrix)
				{
					ctx.translate(storageContext.transform.origin[0], storageContext.transform.origin[1]);
					ctx.transform.apply(ctx, storageContext.transform.matrix);
					ctx.translate(-storageContext.transform.origin[0], -storageContext.transform.origin[1]);
				}

				if (storageContext.clip)
				{
					ctx.beginPath();
					ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
					ctx.clip();
				}

				if (storageContext.ctx.storage)
				{
					storageContext.ctx.storage.forEach(function (item)
					{
						renderItem(ctx, item);
					});
				}

				ctx.restore();
			});

			util.log('html2canvas: Renderer: Canvas renderer done - returning canvas obj');

			if (options.elements.length === 1)
			{
				if (typeof options.elements[0] === 'object' && options.elements[0].nodeName !== 'BODY')
				{
					// crop image to the bounds of selected (single) element
					bounds = html2CanvasInstance.Util.Bounds(options.elements[0]);
					newCanvas = document.createElement('canvas');
					newCanvas.width = Math.ceil(bounds.width);
					newCanvas.height = Math.ceil(bounds.height);
					ctx = newCanvas.getContext('2d');

					ctx.drawImage(canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height);
					canvas = null;
					return newCanvas;
				}
			}

			return canvas;
		};
	};
})(window, document);
;
// Declare namespaces
var CivicWeb = CivicWeb || {};
CivicWeb.Integration = CivicWeb.Integration || {};

//Create classes
CivicWeb.Integration.VideoClass = function (args)
{
	var localization = args.localization;
	var referenceFieldLocalization = args.referenceFieldLocalization;

	var minutesBuild = args != null && args.minutesBuild != null ? args.minutesBuild : false;
	var agendaDocument = args != null && args.agendaDocument != null ? args.agendaDocument : false;
	var meetingId = args != null && args.meetingId != null ? args.meetingId : 0;
	var createEvent = args != null && localization.createEvent != null ? localization.createEvent : '';
	var viewEvent = args != null && localization.viewEvent != null ? localization.viewEvent : '';
	var audioOnly = args != null && args.audioOnly != null ? args.audioOnly : false;
	var earthChannel = args != null && args.earthChannel != null ? args.earthChannel : false;
	var youTubeLite = args != null && args.youTubeLite != null ? args.youTubeLite : false;
	var youTube = args != null && args.youTube != null ? args.youTube : false;
	var youTubeEventId = args != null && args.youTubeEventId != null ? args.youTubeEventId : '';
	var manageVideo = args != null && args.manageVideo != null ? args.manageVideo : false;
	var purchasedBoxcast = args != null && args.purchasedBoxcast != null ? args.purchasedBoxcast : false;
	var timestampEnabled = args != null && args.timestampEnabled != null ? args.timestampEnabled : false;
	var documentBody = null;
	var myVideoWindow = null;
	var setVideoTimeStampDataCallback = function (seconds) { };
	var itemId = 0;

	var isPhone = false;
	var isIOS = false;
	var liveTimestamping = false;
	var liveTimestampingFirstTimestamp = null;
	var syncModeEnabled = false;
	var historic = false;
	var firstTimeStamp = Number.MAX_SAFE_INTEGER;
	var startAtFirstTimestamp = false;

	var attachmentPane = null;
	var videoHeight = 300;
	var videoWidth = 400;
	var videoScale = 0.618;
	var maxVideoWidth = 505;
	var ratio4x3 = 0.75;
	var ratio16x9 = 0.5625;
	var minWidthChromeLoad4x3 = 400;
	var minWidthChromeLoad16x9 = 464;
	var earthChannelForcedMinHeight = 200;//we are waiting for them to remove this limit

	//these variables are for multi event meetings
	var currentVideo = 0;
	var videoRatio = [];
	var urlBase = [];
	var videoObjects = [];
	var videoElement = [];
	var youTubeEvents = [];
	var liveEventExists = false;
	var searchingForAdditionalEvents = null;
	var queryValues;
	var eventIds = [];
	var broadcastsChannels = {};
	var nextPageToken = "";

	const youtubeText = "YouTube - ";
	const boxcastText = "Boxcast - "

	this.addVideoButtonToPortal = function (meetingId, documentId, buttonClient)
	{
		$.ajax({
			url: '/api/videolink/' + meetingId.toString(),
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (data)
			{
				var linkFound = false;
				if (data && data.length > 0)
				{
					if (!youTube && data.indexOf('IsMediaEnabled') < 0)
					{
						//Granicus
						if (buttonClient.is('a'))
						{
							buttonClient.show().removeClass('hidden').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);;
						}
						else
						{
							buttonClient.show().removeClass('hidden').find('span').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);;
						}
						buttonClient.attr({ 'href': data });
						linkFound = true;
					}
					else
					{
						var result = JSON.parse(data);
						currentVideo = 0;
						urlBase = [];
						for (var i = 0; i < result.length; i++)
						{
							var d = result[i];

							var isMediaEnabled = d.IsMediaEnabled ? d.IsMediaEnabled : false;
							var publisherEventId = d.PublisherEventID ? d.PublisherEventID : 0;
							var eventStatus = d.EventStatus ? d.EventStatus : '';
							var youTubeEventId = d.YouTubeEventId ? d.YouTubeEventId : '';
							var showVideoLink = d.ShowVideoLink ? d.ShowVideoLink : false;
							historic = d.Historic ? d.Historic || historic : false;

							if ((youTube && showVideoLink && youTubeEventId.length > 0 && youTubeEventId != '0') || eventStatus.toLowerCase() == 'published' && isMediaEnabled && publisherEventId > 0)
							{
								if (buttonClient.is('a'))
								{
									buttonClient.show().removeClass('hidden').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);;
								}
								else
								{
									buttonClient.show().removeClass('hidden').find('span').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);;
								}

								if (historic)
								{
									var currentUrlBase = d.URLBase.replace('view.', 'viewer.') + '&eID=' + publisherEventId;
									urlBase.push(currentUrlBase);
									buttonClient.off('click', showVideo).on('click', showVideo);
								}
								else
								{
									buttonClient.off('click', showVideo);
									buttonClient.attr({ 'href': '/document/' + documentId + '?splitscreen=true&media=true' });
								}
								linkFound = true;
								break;
							}
						}
					}
				}

				if (!linkFound)
				{
					buttonClient.hide().addClass('hidden');
				}
			},
			error: function ()
			{
				buttonClient.hide().addClass('hidden');
			}
		});

	};

	this.showPdfQuickViewVideoLink = function (meetingId, documentId)
	{
		$.ajax({
			url: '/api/videolink/' + meetingId.toString(),
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (data)
			{
				var linkFound = false;
				if (data && data.length > 0)
				{
					if (!youTube && data.indexOf('IsMediaEnabled') < 0)
					{
						//Granicus
						$('#VideoLink > a > span').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);
						$('#VideoLink > a').attr({ 'href': data });
						linkFound = true;
					}
					else
					{
						var result = JSON.parse(data);
						currentVideo = 0;
						urlBase = [];
						for (var i = 0; i < result.length; i++)
						{
							var d = result[i];

							var isMediaEnabled = d.IsMediaEnabled ? d.IsMediaEnabled : false;
							var publisherEventId = d.PublisherEventID ? d.PublisherEventID : 0;
							var eventStatus = d.EventStatus ? d.EventStatus : '';
							var youTubeEventId = d.YouTubeEventId ? d.YouTubeEventId : '';
							var showVideoLink = d.ShowVideoLink ? d.ShowVideoLink : false;
							historic = d.Historic ? d.Historic || historic : false;

							if ((youTube && showVideoLink && youTubeEventId.length > 0 && youTubeEventId != '0') || eventStatus.toLowerCase() == 'published' && isMediaEnabled && publisherEventId > 0)
							{
								$('#VideoLink > a').attr({ 'href': '/document/' + documentId + '?splitscreen=true&media=true' });
								linkFound = true;
								break;
							}
						}
					}

					if (linkFound)
					{
						$('#VideoLink').removeClass('hidden');
					}
				}
			},
			error: function ()
			{
				buttonClient.hide();
			}
		});
	};

	this.addTimestampsAndVideoToMeetingDocument = function (id, body, splitscreen)
	{

		$.ajax({
			url: '/api/geteventwithindexpoints/' + id.toString(),
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (response)
			{
				if (response)
				{
					var result = JSON.parse(response);
					if (result.length > 0)
					{
						youTube = result[0].YouTube != null ? result[0].YouTube : false;
					}

					if (result && result.length > 0)
					{
						//Do these once on load, not per event
						body.find('a[id^=video-timestamp-]').remove();

						currentVideo = 0;
						videoRatio = [];
						urlBase = [];
						videoElement = [];
						youTubeEvents = [];
						var videoExists = false;
						var showVideoLink = true;
						var showTimeStamps = false;
						var liveTimestamping = false;

						var agendaIds = [];
						var minutesIds = [];
						var iconLight = audioOnly ? '/Global/Images/icon-audio-light-16x16.png' : '/Global/Images/icon-video-light-16x16.png';
						var iconDark = audioOnly ? '/Global/Images/icon-audio-dark-16x16.png' : '/Global/Images/icon-video-dark-16x16.png';

						documentBody = body;

						eventIds = [];
						for (var k = 0; k < result.length; k++)
						{
							var dat = result[k];
							var event = dat.Event != null ? dat.Event : null;
							var eventId = event != null && event.eventId != null ? event.eventId : '';
							if (eventIds.indexOf(eventId) == -1)
							{
								eventIds.push(eventId);
							}
						}

						for (var i = 0; i < result.length; i++)
						{
							var d = result[i];
							var isMediaEnabled = d.PublisherEvent ? d.PublisherEvent.IsMediaEnabled : false;
							var publisherEventId = d.PublisherEvent ? d.PublisherEvent.PublisherEventID : 0;
							var eventStatus = d.PublisherEvent ? d.PublisherEvent.EventStatus : '';

							var event = d.Event != null ? d.Event : null;
							var eventId = event != null && event.eventId != null ? event.eventId : '';
							//var eventTitle = event != null && event.eventTitle != null ? event.eventTitle : '';

							if (event && event.broadcastChannel && event.channelId)
							{
								event.eventId = event.channelId;
								eventId = event.channelId;
							}
							if (i == 0)
							{
								historic = d.Historic != null ? d.Historic : false;

								showVideoLink = d.ShowVideoLink != null ? d.ShowVideoLink : true;
								showTimeStamps = d.ShowTimeStamps != null ? d.ShowTimeStamps : false;
								startAtFirstTimestamp = d.StartAtFirstTimestamp != null ? d.StartAtFirstTimestamp : false;
								liveTimestamping = d.PublisherEvent != null ? d.PublisherEvent.MediaType.toLowerCase() == 'live' : false;
							}

							if ((youTube && showVideoLink && eventId.length > 0 && eventId != '0') || (eventStatus.toLowerCase() == 'published' && isMediaEnabled && publisherEventId > 0))
							{
								if (showTimeStamps)
								{
									var localIndexPoints = result[i].LocalIndexPoints ? result[i].LocalIndexPoints : null;
									if (localIndexPoints)
									{
										for (var j = 0; j < localIndexPoints.length; j++)
										{
											var minutesItemId = localIndexPoints[j].ItemId;
											var secondsStart = localIndexPoints[j].Value;
											var timeStampEvent = localIndexPoints[j].Event != null ? localIndexPoints[j].Event : '';
											var relationshipTypeId = localIndexPoints[j].RelationshipTypeId;
											var agendaItemId = localIndexPoints[j].RelatedItem;
											
											if (!isNaN(secondsStart) && (timeStampEvent == eventId || timeStampEvent == ''))
											{
												var timeString = convertSecondsToTimeString(secondsStart, false, minutesItemId, timeStampEvent);
												var timestampLink = $('<a />').attr({ 'title': timeString, 'time-stamp-event': eventId, 'time-stamp-video': i, 'time-stamp': secondsStart }).css({ 'position': 'absolute', 'right': '0', 'cursor': 'pointer', 'text-decoration': 'underline', 'z-index': '500' }).on('click', function () { gotoVideoTimeStamp(this); }).append($('<img />').css({ 'width': '20px', 'height': '20px' }).attr({ 'src': iconLight }).hover(function () { $(this).attr('src', iconDark); }, function () { $(this).attr('src', iconLight); }));

												if (minutesIds.indexOf(parseInt(minutesItemId)) < 0)
												{
													var minutesHeading = body.find('a[name=MinutesHeading' + minutesItemId + ']');
													if (minutesHeading.length > 0)
													{
														timestampLink.attr({ 'id': 'video-timestamp-' + minutesItemId, 'top': minutesHeading.top });
														minutesHeading.parent().after(timestampLink);
													}
													var minutesItem = body.find('a[name=MinutesItem' + minutesItemId + ']');
													if (minutesItem.length > 0)
													{
														timestampLink.attr({ 'id': 'video-timestamp-' + minutesItemId, 'top': minutesItem.top });
														minutesItem.parent().after(timestampLink);
													}
													var resolutionItem = body.find('a[name=Resolution' + minutesItemId + ']');
													if (resolutionItem.length > 0)
													{
														timestampLink.attr({ 'id': 'video-timestamp-' + minutesItemId, 'top': resolutionItem.top });
														resolutionItem.parent().after(timestampLink);
													}

													minutesIds.push(minutesItemId)
												}

												if (relationshipTypeId == 6 && agendaIds.indexOf(parseInt(agendaItemId)) < 0)
												{
													var agendaHeading = body.find('a[name=AgendaHeading' + agendaItemId + ']');
													if (agendaHeading.length > 0)
													{
														timestampLink.attr({ 'id': 'video-timestamp-' + agendaItemId, 'top': agendaHeading.top });
														agendaHeading.parent().after(timestampLink);
													}
													var agendaItem = body.find('a[name=AgendaItem' + agendaItemId + ']');
													if (agendaItem.length > 0)
													{
														timestampLink.attr({ 'id': 'video-timestamp-' + agendaItemId, 'top': agendaItem.top });
														agendaItem.parent().after(timestampLink);
													}

													agendaIds.push(agendaItemId);
												}

												if (firstTimeStamp > secondsStart)
												{
													firstTimeStamp = secondsStart;
												}
											}
										}
									}

									if (!liveTimestamping && d.IndexPoints != null)
									{
										for (var k = 0; k < d.IndexPoints.length; k++)
										{
											var externalId = d.IndexPoints[k].ExternalID;
											var secondsStart = d.IndexPoints[k].SecondsStart;
											var validTimestamp = !isNaN(secondsStart) && parseInt(secondsStart) > 0 || !isNaN(d.IndexPoints[k].SecondsEnd) && parseInt(d.IndexPoints[k].SecondsEnd) > 0;
											var title = d.IndexPoints[k].Title;
											if (validTimestamp && agendaIds.indexOf(parseInt(externalId)) < 0)
											{
												var timeString =  convertSecondsToTimeString(secondsStart);
												var timestampLink = $('<a />').attr({ 'title': timeString, 'time-stamp-video': i, 'time-stamp': secondsStart }).css({ 'position': 'absolute', 'right': '0', 'cursor': 'pointer', 'text-decoration': 'underline', 'z-index': '500' }).on('click', function () { gotoVideoTimeStamp(this); }).append($('<img />').css({ 'width': '20px', 'height': '20px' }).attr({ 'src': iconLight }).hover(function () { $(this).attr('src', iconDark); }, function () { $(this).attr('src', iconLight); }));

												var agendaHeading = body.find('a[name=AgendaHeading' + externalId + ']');
												if (agendaHeading.length > 0)
												{
													timestampLink.attr({ 'id': 'video-timestamp-' + externalId, 'top': agendaHeading.top });
													agendaHeading.parent().after(timestampLink);
												}
												var agendaItem = body.find('a[name=AgendaItem' + externalId + ']');
												if (agendaItem.length > 0)
												{
													timestampLink.attr({ 'id': 'video-timestamp-' + externalId, 'top': agendaItem.top });
													agendaItem.parent().after(timestampLink);
												}

												agendaIds.push(externalId);
											}

											if (firstTimeStamp > secondsStart)
											{
												firstTimeStamp = secondsStart;
											}
										}
									}

								}

								var currentVideoRatio = (d.PublisherEvent && (parseInt(d.PublisherEvent.EnabledItemMask) & 4096) > 0) ? ratio16x9 : ratio4x3;
								videoRatio.push(currentVideoRatio);
								youTubeEvents.push(event);

								setVideoWidthHeight(currentVideoRatio);

								if (youTube && eventId.length > 0)
								{
									videoElement.push('<div id="videoDiv" height="' + videoHeight + 'px" width="' + videoWidth + 'px" style=" margin-top:' + (splitscreen ? '0em;' : '2.5em;') + ' text-align: center; top: 0; width:100%; background-color: white; z-index: 600; "><div id="timeStampVideoDiv"></div><hr style="margin:0"/></div>');
								}
								else if (historic)
								{
									var currentUrlBase = d.PublisherEvent.URLBase.replace('view.', 'viewer.') + '&eID=' + publisherEventId;
									urlBase.push(currentUrlBase);
								}
								else
								{
									var currentUrlBase = (d.PublisherEvent ? d.PublisherEvent.URLBase.replace('http://view.earthchannel.com/PlayerController.aspx', '//viewer.earthchannel.com/PlayerMedia.aspx') : '') + '&amp;eID=' + publisherEventId + '&amp;mode=embed';
									urlBase.push(currentUrlBase);
									videoElement.push('<div id="videoDiv" style=" margin-top:' + (splitscreen ? '0em;' : '2.5em;') + ' text-align: center;"><iframe id="iframeONE" height="' + videoHeight + 'px" width="' + videoWidth + 'px" src="' + currentUrlBase + '" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe><hr style="margin:0"/></div>');
								}
								videoExists = true;
							}
						}

						youTubeEventId = youTubeEvents.length > 0 && youTubeEvents[0] != null && youTubeEvents[0].eventId != null ? youTubeEvents[0].eventId : '';

						if (youTube && youTubeEventId != '')
						{
							attachmentPane = $('#attachment-pane');
							if (attachmentPane.length == 0)
							{
								attachmentPane = window.parent.$('#attachment-pane');
							}

							if (attachmentPane.length > 0)
							{
								videoScale = 1;
								maxVideoWidth = 800;

								body.find('a[target="AgendaAttachment"]').on('click', function () { if (attachmentPane && (attachmentPane).find('#videoDiv').length > 0) { setTimeout(function () { moveVideoToAgendaFrame(true); }, 0); } });
							}
							else
							{
								attachmentPane = null;
							}
						}

						if (videoExists && showVideoLink)
						{
							//----------------------------------------------------
							//common to multi events
							(attachmentPane ? attachmentPane : documentBody).css({ 'margin': '0' });
							(attachmentPane ? attachmentPane : documentBody).css({ 'padding': '0' });

							$(window).on('resize', setVideoSize);

							$('#video-button').removeClass("hidden").find('span[class="toolbar-text"]').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);
							var closeSpltiscreenButton = $('ul.split-screen-toolbar').find('li#close-split-screen');
							if (closeSpltiscreenButton && closeSpltiscreenButton.length > 0 && typeof window.CivicWeb != 'undefined' && typeof window.CivicWeb.Documents != 'undefined' && typeof window.CivicWeb.Documents.SplitscreenPage != 'undefined')
							{
								window.CivicWeb.Documents.SplitscreenPage.setToolbarCollapsedState();
							}

							$('#video-button').off('click').on('click', showVideo);

							//auto play from meeeting list widget and portal video button
							if (window.location.href.indexOf('media=true') > 0 || window.location.href.indexOf('timestamp') > 0)
							{
								if (isPhone && splitscreen && ($(window).height() > $(window).width()))
								{
									//moveVideoToAgendaFrame(false);
								}
								else
								{
									if (window.location.href.indexOf('timestamp') > 0)
									{
										startAt = queryValues.timestamp;
									}
									showVideo();
								}
							}
						}
					}
					else
					{

					}
				}
			},
			error: function ()
			{
				//return '';
			}
		});
	};

	var setVideoWidthHeight = function (currentVideoRatio)
	{
		var bodyWidth = (attachmentPane ? attachmentPane : documentBody).width();
		videoWidth = (!isNaN(bodyWidth) ? parseFloat(bodyWidth) : minWidthChromeLoad4x3) * videoScale;

		if (videoWidth > maxVideoWidth)
		{
			videoWidth = maxVideoWidth;
		}

		if (videoWidth < minWidthChromeLoad4x3 && navigator.userAgent.indexOf('Chrome') != -1 && currentVideoRatio == ratio4x3 && !youTube)
		{
			//4:3
			videoWidth = minWidthChromeLoad4x3;
			(attachmentPane ? attachmentPane : documentBody).attr('width', minWidthChromeLoad4x3);
		}
		else if (videoWidth < minWidthChromeLoad16x9 && navigator.userAgent.indexOf('Chrome') != -1 && currentVideoRatio == ratio16x9 && !youTube)
		{
			//16:9
			videoWidth = minWidthChromeLoad16x9;
			(attachmentPane ? attachmentPane : documentBody).attr('width', minWidthChromeLoad16x9);
		}

		videoHeight = videoWidth * currentVideoRatio;
	};

	var switchEvents = function (currentEventId)
	{
		if (youTubeEvents != null)
		{
			for (var i = 0; i < youTubeEvents.length; i++)
			{
				if (youTubeEvents[i].eventId != null && youTubeEvents[i].eventId == currentEventId)
				{
					currentVideo = i;
					youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';
					window.myPlayer.loadVideoById(youTubeEventId, 0, "large");

					break;
				}
			}
		}
	};

	this.getEvents = function ()
	{
		return youTubeEvents;
	};

	this.getCurrentEvent = function ()
	{
		return youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo] != null ? youTubeEvents[currentVideo] : null;
	};

	this.getVideoTime = function (iframe, id, callback)
	{
		if (liveTimestamping)
		{
			if (liveTimestampingFirstTimestamp == null)
			{
				liveTimestampingFirstTimestamp = new Date();
				callback(id, 0, true, youTubeEventId);
			}
			else
			{
				var liveTimestampingTimestamp = new Date();
				var difference = Math.round((liveTimestampingTimestamp - liveTimestampingFirstTimestamp) / 1000);
				callback(id, difference, true, youTubeEventId);
			}
		}
		else
		{
			if (youTube && window.myPlayer != null)
			{
				callback(id, Math.round(window.myPlayer.getCurrentTime()), true, youTubeEventId);
			}
			else
			{
				itemId = id;
				setVideoTimeStampDataCallback = callback;
				if (iframe)
				{
					var a = $('<a>', { href: iframe.src })[0];
					var url = a.origin ? a.origin : (a.protocol + "//" + a.host.replace(":80", "").replace(":443", ""));
					var ifr = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView;
					ifr.postMessage("GETTIME", url);
				}
			}
		}

	};

	var gotoVideoTimeStamp = function (e)
	{
		var timeStampVideo = !isNaN($(e).attr('time-stamp-video')) ? parseInt($(e).attr('time-stamp-video')) : 0;
		var secs = !isNaN($(e).attr('time-stamp')) ? parseInt($(e).attr('time-stamp')) : 0;
		
		secs = secs < 0 ? '0' : secs.toString();

		if (isIOS)
		{
			showVideo();
			var iframe = (attachmentPane ? attachmentPane : documentBody).find('#timeStampVideoDiv')[0];
			if (iframe)
			{
				var uri = iframe.src;
				var re = new RegExp('([?|&])start=.*?(&|$)', 'i');
				var newUri;
				var separator = uri.indexOf('?') !== -1 ? '&' : '?';
				if (uri.match(re))
				{
					newUri = uri.replace(re, separator + 'start=' + secs + '$2');
				}
				else
				{
					newUri = uri + separator + 'start=' + secs;
				}
				iframe.src = newUri;
			}
		}
		else
		{
			if (youTube && youTubeEvents[currentVideo] != null && youTubeEvents[timeStampVideo] != null)
			{
				if (window.myPlayer != null)
				{
					if (timeStampVideo != currentVideo)
					{
						currentVideo = timeStampVideo;
						youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';

						window.myPlayer.loadVideoById(youTubeEventId, secs, "large");
					}
					else
					{
						window.myPlayer.seekTo(secs);
					}
				}
				else
				{
					hideVideo();
					currentVideo = timeStampVideo;
					youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';
					startAtFirstTimestamp = true;
					firstTimeStamp = secs;
					showVideo();
				}
			}
			else if (timeStampVideo != currentVideo)
			{
				hideVideo();
				currentVideo = timeStampVideo;
				showVideo();
				var iframe = (attachmentPane ? attachmentPane : documentBody).find('#iframeONE')[0];
				$(iframe).on('load', function ()
				{
					setTimeout(function ()
					{
						var a = $('<a>', { href: iframe.src })[0];
						var url = a.origin ? a.origin : (a.protocol + "//" + a.host.replace(":80", "").replace(":443", ""));
						var ifr = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView;
						ifr.postMessage("SETTIME:" + secs, url);
					}, 100);
				});
			}
			else
			{
				var iframe = (attachmentPane ? attachmentPane : documentBody).find('#iframeONE')[0];
				if (iframe) {
					var a = $('<a>', { href: iframe.src })[0];
					var url = a.origin ? a.origin : (a.protocol + "//" + a.host.replace(":80", "").replace(":443", ""));
					var ifr = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView;
					ifr.postMessage("SETTIME:" + secs, url);
				}
				else
				{
					hideVideo();
					showVideo();
					var iframe = (attachmentPane ? attachmentPane : documentBody).find('#iframeONE')[0];
					$(iframe).on('load', function ()
					{
						setTimeout(function ()
						{
							var a = $('<a>', { href: iframe.src })[0];
							var url = a.origin ? a.origin : (a.protocol + "//" + a.host.replace(":80", "").replace(":443", ""));
							var ifr = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView;
							ifr.postMessage("SETTIME:" + secs, url);
						}, 100);
					});
				}
			}
		}

		return false;
	};

	this.resizeVideo = function ()
	{
		setVideoSize();
	};

	var setVideoSize = function ()
	{
		if (documentBody)
		{
			var bodyWidth = (attachmentPane ? attachmentPane : documentBody).width();
			var videoWidth = (!isNaN(bodyWidth) ? parseFloat(bodyWidth) : minWidthChromeLoad4x3) * videoScale;
			if (videoWidth > maxVideoWidth)
			{
				videoWidth = maxVideoWidth;
			}
			var videoHeight = videoWidth * videoRatio[currentVideo];

			if (youTube && youTubeEventId.length > 0)
			{

				if (attachmentPane == null)
				{
					documentBody.css({ 'padding-top': videoHeight + 10 + 'px' });
				}

				(attachmentPane ? attachmentPane : documentBody).find('#timeStampVideoDiv').attr('width', videoWidth + 'px').attr('height', videoHeight + 'px');//.css({ 'width': '94%' });
				(attachmentPane ? attachmentPane : documentBody).find('#videoDiv').attr('width', videoWidth + 'px').attr('height', videoHeight + 'px');//.css({ 'width': '94%' });
			}
			else
			{
				(attachmentPane ? attachmentPane : documentBody).find('#iframeONE').attr('width', videoWidth).attr('height', videoHeight);
			}
		}
	};

	var setVideoWidthHeight = function (currentVideoRatio)
	{
		var bodyWidth = (attachmentPane ? attachmentPane : documentBody).width();
		videoWidth = (!isNaN(bodyWidth) ? parseFloat(bodyWidth) : minWidthChromeLoad4x3) * videoScale;

		if (videoWidth > maxVideoWidth)
		{
			videoWidth = maxVideoWidth;
		}

		if (videoWidth < minWidthChromeLoad4x3 && navigator.userAgent.indexOf('Chrome') != -1 && currentVideoRatio == ratio4x3 && !youTube)
		{
			//4:3
			videoWidth = minWidthChromeLoad4x3;
			(attachmentPane ? attachmentPane : documentBody).attr('width', minWidthChromeLoad4x3);
		}
		else if (videoWidth < minWidthChromeLoad16x9 && navigator.userAgent.indexOf('Chrome') != -1 && currentVideoRatio == ratio16x9 && !youTube)
		{
			//16:9
			videoWidth = minWidthChromeLoad16x9;
			(attachmentPane ? attachmentPane : documentBody).attr('width', minWidthChromeLoad16x9);
		}

		videoHeight = videoWidth * currentVideoRatio;
	};

	function sleep(ms)
	{
		return new Promise(function (resolve) { setTimeout(resolve, ms) });
	};

	var getTime = function (callback)
	{
		if (youTube && window.myPlayer != null)
		{
			callback(0, Math.round(window.myPlayer.getCurrentTime()), true);
		}
		else
		{
			callback(0, 0, true);
		}
	};

	var setTime = function (secs, i)
	{
		if (youTube && window.myPlayer != null)
		{
			if (window.myPlayer.seekTo)
			{
				window.myPlayer.seekTo(secs);
			}
			else
			{
				if (i < 20)
				{
					i++;
					sleep(100).then(function () { return setTime(secs, i); });
				}
			}
		}
	};

	this.moveVideoToAgendaFrame = function (moveBackToAttachmentFrame, i)
	{
		if (documentBody == null && i < 20)
		{
			i++;
			setTimeout(function () { CivicWeb.Integration.Video.moveVideoToAgendaFrame(moveBackToAttachmentFrame, i); }, 100);
		}
		else
		{
			moveVideoToAgendaFrame(moveBackToAttachmentFrame);
		}

	};

	var moveVideoToAgendaFrame = function (moveBackToAttachmentFrame)
	{
		//only if it's in the Attachment frame
		if (documentBody && documentBody.find('#videoDiv').length == 0)// && $('#video-button').find('span[class="toolbar-text"]').text() == localization.hideLabel)
		{
			getTime(
				function (id, secs, hyphen)
				{
					hideVideo();

					//if (moveBackToAttachmentFrame)
					//{
					videoScale = 0.618;
					maxVideoWidth = 505;
					//}

					if (attachmentPane != null)
					{
						attachmentPane.find('#attachment-container').removeClass('hidden');
						attachmentPane = null;
					}

					setVideoWidthHeight(videoRatio[currentVideo]);

					showVideo();
					setTimeout(function () { setTime(secs, 1); }, 100);

					if (moveBackToAttachmentFrame)
					{
						$('#video-button').off('click').on('click', moveVideoToAttachmentFrame).removeClass("hidden").find('span[class="toolbar-text"]').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel + ' in the attachment pane');;
					}
					else
					{
						$('#video-button').off('click').on('click', hideVideo).find('span[class="toolbar-text"]').text(localization.hideLabel).attr('title', localization.hideAudioVideoLabel);
					}

				}
			);
		} else
		{
			attachmentPane = null;
			$('#video-button').off('click').on('click', showVideo).find('span[class="toolbar-text"]').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);
		}
	};

	this.moveVideoToAttachmentFrame = function ()
	{
		moveVideoToAttachmentFrame();
	};

	var moveVideoToAttachmentFrame = function ()
	{
		if (documentBody && documentBody.find('#videoDiv').length > 0)
		{
			//only if it's in the Agenda frame
			getTime(
				function (id, secs, hyphen)
				{
					hideVideo();

					attachmentPane = $('#attachment-pane');
					if (attachmentPane.length == 0)
					{
						attachmentPane = window.parent.$('#attachment-pane');
					}

					if (attachmentPane.length > 0)
					{
						videoScale = 1;
						maxVideoWidth = 800;

						setTimeout(function ()
						{
							setVideoWidthHeight(videoRatio[currentVideo]);
							showVideo();
							setTimeout(function () { setTime(secs, 1); }, 100);
						}, 0);
					}
					else
					{
						attachmentPane = null;
					}
				}
			);

		}
	};

	var showVideo = function (e)
	{
		(attachmentPane ? attachmentPane : documentBody).find('#videoDiv').remove();
		if (videoElement.length > 0 && documentBody != null)
		{
			if (navigator.userAgent.indexOf('Chrome') != -1)
			{
				var iframeBodyInitialWidth = (attachmentPane ? attachmentPane : documentBody).width();
				var minWidthToLoadChrome = minWidthChromeLoad16x9;
				if (iframeBodyInitialWidth < (minWidthChromeLoad4x3) && videoRatio[currentVideo] == ratio4x3)
				{
					minWidthToLoadChrome = minWidthChromeLoad4x3;
				}
				else if (iframeBodyInitialWidth < (minWidthChromeLoad16x9) && videoRatio[currentVideo] == ratio16x9)
				{
					minWidthToLoadChrome = minWidthChromeLoad16x9;
				}
				if (iframeBodyInitialWidth < minWidthToLoadChrome)
				{
					$(document.getElementById('AgendaPane')).width(minWidthToLoadChrome + 25);
					if (!eventIsYouTubeVideo(youTubeEventId))
					{
						$('body').prepend(videoElement[currentVideo]);
						loadBoxCastVideo('videoDiv', youTubeEventId);
					}
					else if (youTube && youTubeEventId.length > 0)
					{
						$('body').prepend(videoElement[currentVideo]);
						loadYouTubeVideo('videoDiv');
					}
					else
					{
						(attachmentPane ? attachmentPane : documentBody).prepend(videoElement[currentVideo]);
					}

					iframeBodyInitialWidth = iframeBodyInitialWidth < (earthChannelForcedMinHeight / videoRatio[currentVideo]) ? (earthChannelForcedMinHeight / videoRatio[currentVideo]) : iframeBodyInitialWidth;
					//wait till loaded
					setTimeout(function () { $(document.getElementById('AgendaPane')).width(iframeBodyInitialWidth + 25); setVideoSize() }, 1000);

				}
				else
				{
					if (!eventIsYouTubeVideo(youTubeEventId))
					{
						$('body').prepend(videoElement[currentVideo]);
						loadBoxCastVideo('videoDiv', youTubeEventId);
					}
					else if (youTube && youTubeEventId.length > 0)
					{
						$('body').prepend(videoElement[currentVideo]);
						loadYouTubeVideo('videoDiv');
					}
					else
					{
						(attachmentPane ? attachmentPane : documentBody).prepend(videoElement[currentVideo]);
					}
				}
			}
			else
			{
				if (!eventIsYouTubeVideo(youTubeEventId))
				{
					$('body').prepend(videoElement[currentVideo]);
					loadBoxCastVideo('videoDiv', youTubeEventId);
				}
				else if (youTube && youTubeEventId.length > 0)
				{
					$('body').prepend(videoElement[currentVideo]);
					loadYouTubeVideo('videoDiv');
				}
				else
				{
					(attachmentPane ? attachmentPane : documentBody).prepend(videoElement[currentVideo]);
				}
			}

			$(documentBody.find('body')).css({ 'margin-right': '15px' });

			$('#video-button').off('click').on('click', hideVideo).find('span[class="toolbar-text"]').text(localization.hideLabel).attr('title', localization.hideAudioVideoLabel);

			if (!youTube)
			{
				resizeVideoDiv(e);
			}
		}
		else if (historic)
		{
			window.open(urlBase[currentVideo], '_blank', "toolbar=no,scrollbars=no,resizable=no,top=50,left=50,width=1000,height=770");
		}
		if (attachmentPane)
		{
			attachmentPane.find('#attachment-container').addClass('hidden');
		}
		if (window.parent && window.parent.$)
		{
			window.parent.$('#walkme-player').hide();
		}
		//when auto playing this isn't a button click and e is null!!!!!
		if (e != null)
		{
			e.preventDefault();
		}
		return false;
	};

	this.hideVideo = function (e)
	{
		hideVideo(e);
	}

	var hideVideo = function (e)
	{
		if (documentBody != null)
		{
			currentVideo = 0;
			youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';

			if (youTube)
			{
				myVideoWindow = null;
				$(document.getElementById('timeStampVideoDiv')).closest('.k-window').remove();
			}

			(attachmentPane ? attachmentPane : documentBody).find('#videoDiv').remove();
			documentBody.css({ 'margin-right': '0' });

			$('#video-button').off('click').on('click', showVideo).find('span[class="toolbar-text"]').text(localization.audioVideoLabel).attr('title', localization.showAudioVideoLabel);

			//this should return the scrollable agenda content area to be non-scrollable
			(attachmentPane ? attachmentPane : documentBody).css({ 'padding-top': '' });
			if (typeof CivicWeb != 'undefined' && typeof CivicWeb.Document != 'undefined' && typeof CivicWeb.Document.AgendaNotesPage != 'undefined' && CivicWeb.Document.AgendaNotesPage.getInstance() != null)
			{
				CivicWeb.Document.AgendaNotesPage.events.resizeAgendaDocument(e);
			}
		}

		if (attachmentPane)
		{
			attachmentPane.find('#attachment-container').removeClass('hidden');
		}

		if (e != null)
		{
			e.preventDefault();
		}
		return false;
	};

	var resizeVideoDiv = function (e)
	{
		//this is the sizing of the scrollable agenda area
		//HTML quick-view
		if (documentBody.length > 0)
		{
			if (attachmentPane)
			{
				attachmentPane.find('#videoDiv').css({ 'top': '0', 'background-color': 'white', 'z-index': '600', 'position': '', 'height': '99.83%' });
			}
			else
			{
				documentBody.css({ 'padding-top': videoHeight + 10 + 'px' });
				documentBody.find('#videoDiv').css({ 'position': 'fixed', 'top': '0', 'width': '100%', 'background-color': 'white', 'z-index': '600' });
			}
			if (agendaDocument && typeof CivicWeb != 'undefined' && typeof CivicWeb.Document != 'undefined' && typeof CivicWeb.Document.AgendaNotesPage != 'undefined' && CivicWeb.Document.AgendaNotesPage.getInstance() != null)
			{
				CivicWeb.Document.AgendaNotesPage.events.resizeAgendaDocument(e);
			}
		}
	}

	this.convertSecondsToTimeString = function (secs, hyphens, itemId)
	{
		return convertSecondsToTimeString(secs, hyphens, itemId);
	};

	var convertSecondsToTimeString = function (secs, hyphens, itemId, timeStampEvent)
	{
		var timestamp = '';
		var leading = hyphens ? '-' : '0';
		if (secs >= 3600)
		{
			var h = Math.floor(secs / 3600);
			var m = Math.floor(secs % 3600 / 60);
			var s = Math.floor(secs % 3600 % 60);
			timestamp = h < 10 ? (hyphens ? leading : '') + h + 'h' : h + 'h';
			timestamp += m < 10 ? '0' + m + 'm' : m + 'm';
			timestamp += s < 10 ? '0' + s + 's' : s + 's';

		}
		else if (secs >= 60)
		{
			var m = Math.floor(secs / 60);
			var s = (secs % 60);
			timestamp = (hyphens ? leading + leading : leading) + 'h';
			timestamp += m < 10 ? leading + m + 'm' : m + 'm';
			timestamp += s < 10 ? '0' + s + 's' : s + 's';

		}
		else
		{
			var s = (secs % 60);
			timestamp = (hyphens ? leading + leading : leading) + 'h' + leading + leading + 'm';
			timestamp += s < 10 ? leading + s + 's' : s + 's';

		}

		if (itemId != null && eventIds.length > 1)
		{
			var timeStampEventId = timeStampEvent != null ? timeStampEvent : (BuildForms !=  null ? BuildForms.GetItemValue(itemId, referenceFieldLocalization.videoTimeStampEventFieldReferenceName) : '');
			var index = eventIds.indexOf(timeStampEventId) + 1;
			if (index > 0)
			{
				timestamp = 'Part ' + index + ': ' + timestamp;
			}
		}

		return timestamp;
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//Minutes --------------------------------------------------------------------------
	var setUpMinutesToTimeStamp = function (meetingId)
	{
		$.ajax({
			url: '/api/geteventwithindexpoints/' + meetingId.toString(),
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (data)
			{
				if (data && data.length > 0)
				{
					urlBase = [];
					var result = JSON.parse(data);
					eventIds = [];

					for (var k = 0; k < result.length; k++)
					{
						var dat = result[k];
						var event = dat.Event != null ? dat.Event : null;
						var eventId = event != null && event.eventId != null ? event.eventId : '';
						if (eventIds.indexOf(eventId) == -1)
						{
							eventIds.push(eventId);
						}
					}

					for (var i = 0; i < result.length; i++)
					{
						var d = result[i];
						liveTimestamping = d.PublisherEvent ? d.PublisherEvent.MediaType.toLowerCase() == 'live' : false;
						var isMediaEnabled = d.PublisherEvent ? d.PublisherEvent.IsMediaEnabled : false;
						var publisherEventId = d.PublisherEvent ? d.PublisherEvent.PublisherEventID : 0;
						var event = d.Event != null ? d.Event : null;
						var eventId = event != null && event.eventId != null ? event.eventId : '';
						//var eventTitle = events != null && events.eventTitle != null ? events.eventTitle : '';

						if ((isMediaEnabled && publisherEventId > 0) || (eventId.length > 0 && eventId != '0'))
						{
							videoRatio.push((d.PublisherEvent && (parseInt(d.PublisherEvent.EnabledItemMask) & 4096) > 0) ? ratio16x9 : ratio4x3);

							if (event != null)
							{
								youTubeEvents.push(event);
							}

							var localIndexPoints = d.LocalIndexPoints ? d.LocalIndexPoints : null;
							if (localIndexPoints)
							{
								for (var j = 0; j < localIndexPoints.length; j++)
								{
									var itemId = localIndexPoints[j].ItemId;
									var secondsStart = localIndexPoints[j].Value;
									var timestampEvent = localIndexPoints[j].Event;

									if (secondsStart != null && !isNaN(secondsStart))
									{
										if (secondsStart < 0)
										{
											timeString = '<a href"#" style="color:red;" class="time-stamp-event-link" time-stamp-event="' + timestampEvent + '" time-stamp="' + secondsStart + '" onclick="CivicWeb.Integration.Video.gotoMinutesVideoTimeStamp(this)">' + '-' + CivicWeb.Integration.Video.convertSecondsToTimeString(Math.abs(secondsStart), false, itemId) + '</a>';
										}
										else
										{
											timeString = '<a href"#" class="time-stamp-event-link" time-stamp-event="' + timestampEvent + '" time-stamp="' + secondsStart + '" onclick="CivicWeb.Integration.Video.gotoMinutesVideoTimeStamp(this)">' + CivicWeb.Integration.Video.convertSecondsToTimeString(secondsStart, false, itemId) + '</a>';
										}

										var timestampField = $(document.getElementById(referenceFieldLocalization.videoTimeStampFieldReferenceName + '_' + itemId));
										if (timestampField.length > 0)
										{
											timestampField.html(timeString);
										}
									}
								}
							}
						
							//Set Min size so video auto plays
							if (!youTube && navigator.userAgent.indexOf('Chrome') != -1)
							{
								if (videoRatio[0] == ratio4x3)
								{
									//4:3
									videoWidth = minWidthChromeLoad4x3;
									videoHeight = videoWidth * videoRatio[currentVideo];
								}
								else if (videoRatio[0] == ratio16x9)
								{
									//16:9
									videoWidth = minWidthChromeLoad16x9;
									videoHeight = videoWidth * videoRatio[currentVideo];
								}
							} else
							{
								videoHeight = earthChannelForcedMinHeight;
								videoWidth = videoHeight / videoRatio[currentVideo];
							}

							urlBase.push((d.PublisherEvent ? d.PublisherEvent.URLBase.replace('http://view.earthchannel.com/PlayerController.aspx', '//viewer.earthchannel.com/PlayerMedia.aspx') : '') + '&amp;eID=' + publisherEventId + '&amp;mode=embed');

							if (liveTimestamping)
							{
								$('#timeStampVideoButton').removeClass('hidden').attr({ 'title': (audioOnly ? 'Play the live stream' : 'View the live stream') }).off('click').on('click', toggleTimeStampVideo).find('span').text((audioOnly ? 'Play Stream' : 'View Stream'));
							}
							else
							{
								$('#timeStampVideoButton').removeClass('hidden').off('click').on('click', toggleTimeStampVideo);

								if (manageVideo && timestampEnabled)
								{
									$('#timeStampSyncVideo').removeClass('hidden').off('click').on('click', toggleTimeStampSyncMode);
								}
							}
						}
					}
					youTubeEventId = youTubeEvents.length > 0 && youTubeEvents[0] != null && youTubeEvents[0].eventId != null ? youTubeEvents[0].eventId : '';
				}
				else
				{

				}
			},
			error: function ()
			{
				//return '';
			}
		});

	};

	this.gotoMinutesVideoTimeStamp = function (e)
	{
		gotoMinutesVideoTimeStamp(e);
	};

	var gotoMinutesVideoTimeStamp = function (e)
	{
		var secs = $(e).attr('time-stamp');
		secs = !isNaN(secs) ? parseInt(secs) : 0;
		secs = secs < 0 ? '0' : secs.toString();

		if (youTube && window.myPlayer != null)
		{
			var timeStampEvent = $(e).attr('time-stamp-event');
			if (timeStampEvent != null && timeStampEvent != youTubeEventId)
			{
				youTubeEventId = timeStampEvent;
				window.myPlayer.loadVideoById(timeStampEvent, secs, "large");
				updateEventDropDown();
			}
			else
			{
				window.myPlayer.seekTo(secs);
			}
		}
		else
		{
			var iframe = $('#timeStampVideoDiv').find('iframe')[0];
			if (iframe)
			{
				var a = $('<a>', { href: iframe.src })[0];
				var url = a.origin ? a.origin : (a.protocol + "//" + a.host.replace(":80", "").replace(":443", ""));
				var ifr = iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument.defaultView;
				ifr.postMessage("SETTIME:" + secs, url);
			}
		}
		return false;
	};

	this.toggleTimeStampSyncMode = function ()
	{
		toggleTimeStampSyncMode();
	};

	var toggleTimeStampSyncMode = function ()
	{
		var timeStampSyncVideo = $('#timeStampSyncVideo');
		if (!syncModeEnabled && confirm('Sync mode allows timestamps to be synced with the recorded ' + (audioOnly ? 'audio' : 'video') + '. Sync mode affects all timestamps related to the video.\nDo you want to continue?'))
		{
			timeStampSyncVideo.attr({ 'title': 'Disable Sync Mode' }).find('span').text('Disable Sync Mode');
			$('#subMenu').append('<b id="syncModeEnabledLabel" style="float: right; margin-right: 2em; padding-right: 3px; background-color: #296498; color: #fff;" >Sync Mode Enabled</b>');
			syncModeEnabled = true;

			if ($(document.getElementById('timeStampVideoDiv')).length == 0)
			{
				toggleTimeStampVideo();
			}
		}
		else
		{
			timeStampSyncVideo.attr({ 'title': 'Sync timestamps with recorded ' + (audioOnly ? 'audio' : 'video') }).find('span').text('Enable Sync Mode');
			$('#syncModeEnabledLabel').remove();
			syncModeEnabled = false;
		}

		if (ATMBuild.SelectedItem != null)
		{
			Build.AddVideoTimeStampButton(ATMBuild.SelectedItem);
		}
	};

	var toggleTimeStampVideo = function ()
	{
		if (CivicWeb.Common.loadKendoUi(toggleTimeStampVideo))
		{
			if (!myVideoWindow)
			{
				$('body').prepend('<div id="timeStampVideoDiv"/>');

				var kendoVideoWindow = $(document.getElementById('timeStampVideoDiv'))
				kendoVideoWindow.css({ 'margin': '0', 'padding': '0' }).kendoWindow({
					width: videoWidth + 'px',
					height: videoHeight + 'px',
					title: 'Timestamp ' + (audioOnly ? 'Audio' : 'Video'),
					modal: false,
					visible: true,
					resizable: false,
					actions: ['Close'],
					content: urlBase[currentVideo],
					close: closeKendoVideoWindow,
					position: { top: 0, left: 0 },
					id: "kendoVideoWindow"
				})

				setTimeout(function ()
				{
					var timeStampVideoDiv = $(document.getElementById('timeStampVideoDiv'));

					if (youTube)
					{
						timeStampVideoDiv.height(earthChannelForcedMinHeight);
						timeStampVideoDiv.width(earthChannelForcedMinHeight / videoRatio[currentVideo]);
					}
					else
					{
						timeStampVideoDiv.parent().height(earthChannelForcedMinHeight);
						timeStampVideoDiv.parent().width(earthChannelForcedMinHeight / videoRatio[currentVideo]);
					}
				}, 1000);


				myVideoWindow = $(document.getElementById('timeStampVideoDiv')).data("kendoWindow");
				$(document.getElementById('timeStampVideoDiv')).closest('.k-window').css({ 'position': 'fixed', 'top': '0', 'left': '0' });
				myVideoWindow.open();
				$('#timeStampVideoButton').attr({ 'title': (liveTimestamping ? (audioOnly ? 'Stop playing the stream' : 'Stop viewing the stream') : (audioOnly ? 'Stop playing the audio' : 'Stop viewing the video')) }).find('span').text((liveTimestamping ? 'Stop Stream' : (audioOnly ? 'Stop Audio' : 'Close video popup')));

				if (youTube && CivicWeb.Integration.Video.getCurrentEvent() != null)
				{
					loadYouTubeVideo('timeStampVideoDiv');

					updateEventDropDown();
				}
			}
			else
			{
				closeKendoVideoWindow();
				$('#timeStampVideoButton').attr({ 'title': (liveTimestamping ? (audioOnly ? 'Play the live stream' : 'View the live stream') : (audioOnly ? 'Play the recorded audio' : 'View the recorded video')) }).find('span').text(liveTimestamping ? (audioOnly ? 'Play Stream' : 'View Stream') : (audioOnly ? 'Play Audio' : 'View Video'));
			}
		}
	};

	var closeKendoVideoWindow = function ()
	{
		myVideoWindow = null;
		$(document.getElementById('timeStampVideoDiv')).closest('.k-window').remove();
		$('#timeStampVideoButton').attr({ 'title': (liveTimestamping ? (audioOnly ? 'Play the live stream' : 'View the live stream') : (audioOnly ? 'Play the recorded audio' : 'View the recorded video')) }).find('span').text(liveTimestamping ? (audioOnly ? 'Play Stream' : 'View Stream') : (audioOnly ? 'Play Audio' : 'View Video'));

		if (syncModeEnabled)
		{
			$('#timeStampSyncVideo').attr({ 'title': 'Sync timestamps with recorded ' + (audioOnly ? 'audio' : 'video') }).find('span').text('Enable Sync Mode');
			$('#syncModeEnabledLabel').remove();
			syncModeEnabled = false;
		}
	};

	var saveVideoEventSettings = function (events, startAtFirstTimestamp)
	{
		var obj = {};
		obj.MeetingId = meetingId;
		obj.Events = events;
		obj.StartAtFirstTimestamp = startAtFirstTimestamp;

		$.ajax({
			url: '/api/savevideoeventsettings',
			contentType: 'application/json',
			dataType: 'json',
			async: true,
			cache: false,
			type: 'POST',
			data: JSON.stringify(obj),
			success: function (response)
			{
				setTimeout(function ()
				{
					$('#videoevent-selector-container').slideUp();
	
					$('#earthChannelEventLink').remove();
					$('#showVideoLinkSpan').remove();
					$('#showTimeStampsSpan').remove();

					$('#timeStampVideoButton').addClass('hidden');
					$('#timeStampSyncVideo').addClass('hidden');

					$('.time-stamp-event-link').remove();

					if (manageVideo && meetingId != null && meetingId > 0)
					{
						setUpViewCreateEventLink(meetingId);
					}

					if (minutesBuild)
					{
						setUpMinutesToTimeStamp(meetingId);
					}
				}, 750);
			},
			error: function ()
			{
				//return '';
			}
		});
	};

	var toggleshowVideoLink = function (e)
	{
		var obj = {};
		obj.MeetingId = meetingId;

		var id = $(e).attr('id');
		var confirmMsg = '';
		var checkedShowVideo = false;
		var showTimestampsFlipped = false;
		if (id == 'showVideoLink')
		{
			obj.ShowVideoLink = e.checked;
			if (!e.checked)
			{
				$('#showTimeStamps').prop('checked', false);
				obj.ShowTimeStamps = false;
				showTimestampsFlipped = true;
			}
			else
			{
				obj.ShowTimeStamps = $('#showTimeStamps').prop('checked');
			}

			confirmMsg = (e.checked ? 'Show' : 'Hide') + ' the ' + (audioOnly ? 'audio' : 'video') + ' button on the published agenda and minutes?\nDo you want to continue?';
		}
		else if (id == 'showTimeStamps')
		{
			obj.ShowTimeStamps = e.checked;
			if (!$('#showVideoLink').prop('checked'))
			{
				checkedShowVideo = true;
			}
			$('#showVideoLink').prop('checked', true);
			obj.ShowVideoLink = true;
			confirmMsg = (e.checked ? 'Show' : 'Hide') + ' the timestamps on the published agenda and minutes?\nDo you want to continue?';
		}

		if (confirm(confirmMsg))
		{
			$.ajax({
				url: '/api/savevideoeventsettings',
				contentType: 'application/json',
				dataType: 'json',
				async: true,
				cache: false,
				type: 'POST',
				data: JSON.stringify(obj),
				success: function (response)
				{

				},
				error: function ()
				{
					//return '';
				}
			});
		}
		else
		{
			e.checked = !e.checked;
			if (id == 'showVideoLink' && showTimestampsFlipped)
			{
				$('#showTimeStamps').prop('checked', e.checked);
			}

			if (checkedShowVideo)
			{
				$('#showVideoLink').prop('checked', false);
			}
		}

	};

	this.getSyncMode = function ()
	{
		return syncModeEnabled;
	};

	this.isAudioOnly = function ()
	{
		return audioOnly;
	};

	this.isLive = function ()
	{
		return liveTimestamping;
	};

	var setUpViewCreateEventLink = function (id)
	{
		$.ajax({
			url: '/api/getevent/' + id.toString(),
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (result)
			{
				var data = JSON.parse(result);
				var displayShowVideoLinkCheckbox = data.DisplayShowVideoLinkCheckbox != null ? data.DisplayShowVideoLinkCheckbox : false;
				var showVideoLink = data.ShowVideoLink != null ? data.ShowVideoLink : false;
				var showTimeStamps = data.ShowTimeStamps != null ? data.ShowTimeStamps : false;
				var historic = data.Historic != null ? data.Historic : false;
				var validYouTubeCredentialExists = data.validYouTubeCredentialExists != null ? data.validYouTubeCredentialExists : false;
				var publicDocumentExists = data.publicDocumentExists != null ? data.publicDocumentExists : false;
				var meetingId = data.MeetingId != null ? data.MeetingId : 0;
				var meetingName = data.MeetingName != null ? data.MeetingName : '';
				var meetingDateInThePast = data.MeetingDateInThePast != null ? data.MeetingDateInThePast : false;
				var meetingStartTimeExists = data.MeetingStartTimeExists != null ? data.MeetingStartTimeExists : false;

				var eventId = data.eventId != null ? data.eventId : '';
				var events = data.Events != null ? data.Events : [];
				var startAtFirstTimestamp = data.StartAtFirstTimestamp != null ? data.StartAtFirstTimestamp : false;
				var boxcast = data.boxcast != null ? data.boxcast : false;
				var broadcasts = data.broadcasts != null ? data.broadcasts : [];
				var boxcasters = data.boxcasters != null ? data.boxcasters : [];
				var rtmpSources = data.rtmpSources != null ? data.rtmpSources : [];
				var youtubeAccounts = data.youtubeAccounts != null ? data.youtubeAccounts : [];

				var eventLink = $('<a/>');
				if (youTube && eventId != '-1')
				{
					eventLink.attr({ 'id': 'earthChannelEventLink', 'class': 'subMenuText', 'href': '' }).text('Video').off('click').on('click', function (e) { closeYouTubeVideoEventSelector(); openYouTubeVideoEventSelector(e, meetingName, events, meetingDateInThePast, meetingStartTimeExists, startAtFirstTimestamp, boxcast, broadcasts, boxcasters, youtubeAccounts, rtmpSources); e.preventDefault(); });
					eventLink.attr({ 'title': (youTubeLite ? 'Paste in the YouTube link to connect to this meeting instance' : (boxcast ? 'Select a broadcast or create a new broadcast to connect to this meeting' : 'Select the YouTube live stream or a recorded video to connect to this meeting instance.')) });
				}
				else
				{
					eventLink.attr({ 'id': 'earthChannelEventLink', 'class': 'subMenuText', 'href': ('/videologin/' + meetingId + '/' + (eventId == '-1' ? '0' : eventId)), 'target': '_blank' });
					if (eventId != '0' && eventId != '-1')
					{
						eventLink.text(viewEvent);
					}
					else
					{
						eventLink.text(createEvent);
					}
				}

				if (eventId == '-1')
				{
					if (!publicDocumentExists)
					{
						eventLink.text((youTube ? 'Video' : createEvent)).addClass('disableCreateEventLink').attr({ 'disabled': 'disabled', 'title': 'A public Agenda needs to be published before ' + (boxcast ? 'a broadcast can be connected' : (youTube ? 'a video can be connected' : 'an event can be created')) }).removeAttr('href target');
						if (youTube)
						{
							eventLink.off('click').on('click', function (e) { if ($(this).attr('disabled')) { return false; }; closeYouTubeVideoEventSelector(); openYouTubeVideoEventSelector(e, meetingName, [], meetingDateInThePast, meetingStartTimeExists, startAtFirstTimestamp, boxcast, broadcasts, boxcasters, youtubeAccounts); e.preventDefault(); });
						}
					}
					else if (youTube && !validYouTubeCredentialExists)
					{
						eventLink.text('Video').addClass('disableCreateEventLink').attr({ 'title': 'Valid YouTube credentials are needed before an event can be created. Add credentials under the admin area on the General Settings page.' }).removeAttr('href target');
					}
				}

				$('#subMenu').append(eventLink);

				if (eventId != '0' && eventId != '-1' && displayShowVideoLinkCheckbox)
				{
					var showVideoContainer = $('<span/>').attr({ 'id': 'showVideoLinkSpan', 'title': 'Show the ' + (audioOnly ? 'audio' : 'video') + ' button on the published agenda and minutes documents' });
					showVideoContainer.append($('<input/>').attr({ 'id': 'showVideoLink', 'type': 'checkbox', 'checked': showVideoLink }).css({ 'margin-left': '2em', 'vertical-align': 'middle' }).off('click').on('click', function () { toggleshowVideoLink(this); }));
					showVideoContainer.append($('<label/>').attr({ 'for': 'showVideoLink' }).css({ 'text-indent': '0px' }).text('Show ' + (audioOnly ? 'Audio' : 'Video') + ' Button'));
					$('#subMenu').append(showVideoContainer);

					if (!historic)
					{
						var showTimeStampsContainer = $('<span/>').attr({ 'id': 'showTimeStampsSpan', 'title': 'Show timestamps on the published agenda and minutes documents' });
						showTimeStampsContainer.append($('<input/>').attr({ 'id': 'showTimeStamps', 'type': 'checkbox', 'checked': showTimeStamps }).css({ 'margin-left': '2em', 'vertical-align': 'middle' }).off('click').on('click', function () { toggleshowVideoLink(this); }));
						showTimeStampsContainer.append($('<label/>').attr({ 'for': 'showTimeStamps' }).css({ 'text-indent': '0px' }).text('Show Timestamps'));
						$('#subMenu').append(showTimeStampsContainer);
					}
				}

				if (minutesBuild && meetingId > 0 && broadcasts.length > 0)
				{
					addBoxCastInCameraButton(broadcasts, meetingId);
				}
				else
				{
					$('#boxcaster-incamera-control').addClass('hidden');
				}
			},
			error: function ()
			{
				//return '';
			}
		});
	};

	/////////////////////////////////////////////////////////////////////////////////////
	//YouTube --------------------------------------------------------------------------

	var closeYouTubeVideoEventSelector = function ()
	{
		nextPageToken = "";
		$('#videoevent-selector-container').remove();
	};

	var showInCameraButton = function (meetingId, currentlyInCamera)
	{
		$('#boxcaster-incamera-control').removeClass('hidden');
		if (currentlyInCamera)
		{
			$('#OpenSession').removeClass('hidden').off('click').on('click', function (e) { setInCameraSession(e, meetingId, false); });
		}
		else
		{
			$('#ClosedSession').removeClass('hidden').off('click').on('click', function (e) { setInCameraSession(e, meetingId, true); });
		}
	}

	var addInCameraButton = function (broadcastDetails, meetingId)
	{
		if (broadcastDetails && broadcastDetails.length > 0)
		{
			var currentlyInCamera = false;
			var minimuMillisecondsToStart = Number.MAX_SAFE_INTEGER;
			var allBroadcastsEnded = true;

			for (var i = 0; i < broadcastDetails.length; i++)
			{
				var broadcastDetail = broadcastDetails[i];

				if ((broadcastDetail.metadata.mixer != null && broadcastDetail.metadata.mixer.muted) || (broadcastDetail.metadata.overlays != null && broadcastDetail.metadata.overlays.length > 0))
				{
					currentlyInCamera = true;
				}

				minimuMillisecondsToStart = broadcastDetail.millisecondsToStart < minimuMillisecondsToStart ? broadcastDetail.millisecondsToStart : minimuMillisecondsToStart;
				allBroadcastsEnded = allBroadcastsEnded && broadcastDetail.streamEnded;
			}

			if (!allBroadcastsEnded)
			{
				if (minimuMillisecondsToStart > 0)
				{
					setTimeout(function () { showInCameraButton(meetingId, currentlyInCamera); }, minimuMillisecondsToStart);
				}
				else
				{
					showInCameraButton(meetingId, currentlyInCamera);
				}
			}
		}
	}

	var addBoxCastInCameraButton = function (broadcasts, meetingId)
	{
		var obj = {};
		obj.Broadcasts = broadcasts;
		obj.meetingId = meetingId;

		$.ajax({
			url: '/api/broadcastdetails',
			contentType: 'application/json',
			dataType: 'json',
			async: true,
			cache: false,
			type: 'POST',
			data: JSON.stringify(obj),
			success: function (response)
			{
				addInCameraButton(response, meetingId);
			},
			error: function ()
			{
				addInCameraButton(false, meetingId);
			}
		});
	}

	var setInCameraSession = function (e, meetingId, incamera)
	{
		if (incamera)
		{
			$('#ClosedSession').attr('disabled', true);
			$('#loadingSpinnerClosed').removeClass('hidden');
		}
		else
		{	
			$('#OpenSession').attr('disabled', true);
			$('#loadingSpinnerOpen').removeClass('hidden');
		}

		var obj = {};
		obj.MeetingId = meetingId;
		obj.InCamera = incamera;

			$.ajax({
				url: '/api/toggleboxcastintermission',
				contentType: 'application/json',
				dataType: 'json',
				async: true,
				cache: false,
				type: 'POST',
				data: JSON.stringify(obj),
				success: function (response)
				{
					$('#loadingSpinnerOpen').addClass('hidden');
					$('#loadingSpinnerClosed').addClass('hidden');
					if (response.success && incamera)
					{
						$('#OpenSession').removeClass('hidden').off('click').on('click', function (e) { setInCameraSession(e, meetingId, false); });
						$('#ClosedSession').addClass('hidden').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, true); });
					}
					else if (response.success && !incamera)
					{
						$('#ClosedSession').removeClass('hidden').off('click').on('click', function (e) { setInCameraSession(e, meetingId, true); });
						$('#OpenSession').addClass('hidden').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, false); });
					}
					else
					{
						$('#ClosedSession').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, true); });
						$('#OpenSession').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, false); });
						alert("There was an error setting the broadcast to " + (incamera ? "intermission" : "public"));
					}
				},
				error: function ()
				{
					$('#loadingSpinnerOpen').addClass('hidden');
					$('#loadingSpinnerClosed').addClass('hidden');
					$('#ClosedSession').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, true); });;
					$('#OpenSession').attr('disabled', false).off('click').on('click', function (e) { setInCameraSession(e, meetingId, false); });;
					alert("There was an error setting the broadcast to " + (incamera ? "intermission" : "public"));
				}
			});


		e.preventDefault();
	}

	var openYouTubeVideoEventSelector = function (e, meetingName, events, meetingDateInThePast, meetingStartTimeExists, startAtFirstTimestamp, boxcast, broadcasts, boxcasters, youtubeAccounts, rtmpSources)
	{
		//window
		var videoSelectorWindow = $('<div/>').attr({ 'id': 'videoevent-selector-container' }).css({ 'z-index': '1000', 'top': '150px', 'width': '500px', 'position': 'absolute', 'left': '29%', 'background-color': '#E8E8E8' });
		//header
		//close window button
		var videoSelectorHeader = ($('<div/>').css({ 'margin': '0' }).addClass('visBorder'))
			.append(($('<div/>').css({ 'clear': 'both' }).addClass('visHeader visHeaderHover').text(boxcast ? 'BoxCast Broadcast Selector' : 'YouTube Video Selector'))
				.append($('<span/>').attr({ 'id': 'closeVideoSelector', 'title': 'Close' }).css({ 'border-width': '0', 'float': 'right' }).addClass('cw-icon-delete glyphbutton cursor-pointer').off('click').on('click', closeYouTubeVideoEventSelector)));

		videoSelectorWindow.append(videoSelectorHeader);

		//create event button
		videoSelector = $('<div/>').attr({ 'id': 'videoevent-selector' }).css({ 'margin': '0.8em' });
		videoSelector.append($('<hr/>').attr({ 'id': 'hr1' }).css({ 'margin': '1em' }));
		if (youTubeLite)
		{

			//select video
			var videoList = $('<div/>').text('Paste in YouTube link');
			videoList.append($('<br />'));
			//inpu
			videoList.append($('<input/>').attr({ 'id': 'videoEventId', 'type': 'text', 'placeholder': 'https://youtube.com/watch?v=xxxxxxxxxxx', 'title': 'Paste in YouTube link', 'data-meetingname': meetingName }).css({ 'margin-right': '5px', 'margin-bottom': '3px', 'width': '300px' }));
			videoList.append($('<button/>').attr({ 'id': 'loadMore', 'type': 'button', 'title': 'Load more' }).addClass('button background-color-hover').text('Load More').off('click').on('click', loadMoreVideos));
			videoList.append($('<button/>').attr({ 'id': 'addEventRow', 'type': 'button', 'title': 'Add' }).addClass('button background-color-hover').text('Add').off('click').on('click', addEventRowFromInput));
			videoSelector.append(videoList);
		}
		else 
		{
			var createVideoButton = $('<button/>').attr({ 'id': 'createYouTubeEvent', 'type': 'button', 'title': boxcast ? 'Create a broadcast for this meeting' : 'Create a live event for this meeting' }).addClass('button background-color-hover').text(boxcast ? 'Create New Broadcast' : 'Create New Event').off('click').on('click', function (e) { createYouTubeEvent(e, meetingName); });

			if (boxcast && ((boxcasters && boxcasters.length > 1) || rtmpSources.length > 0))
			{
				videoSelector.append($('<div/>').css('padding-bottom', '5px').append(createVideoButton));
			}
			else
			{
				videoSelector.append($('<div/>').css('text-align', 'center').append(createVideoButton));
			}


			//select video
			var videoList = $('<div/>').text(boxcast ? 'Select Broadcast' : 'Select Video / Current Live Stream');
			videoList.append($('<br />'));
			//combobox
			videoList.append($('<select/>').attr({ 'id': 'videoEventId', 'title': 'Start typing the date of the ' + (boxcast ? 'broadcast' : 'video') + ' then select from the drop down the ' + (boxcast ? 'broadcast' : 'video') + ' you would like associated with this meeting' }).css({ 'margin-right': '5px', 'margin-bottom': '3px', 'height': '25px', 'width': '325px' }).addClass("hidden"));
			videoList.append($('<button/>').attr({ 'id': 'loadMore', 'type': 'button', 'title': 'Load more', 'disabled': 'disabled' }).addClass('button background-color-hover').text('Load More').off('click').on('click', loadMoreVideos));
			videoList.append($('<button/>').attr({ 'id': 'addEventRow', 'type': 'button', 'title': 'Add', 'disabled': 'disabled' }).addClass('button background-color-hover').text('Add').off('click').on('click', (addEventRow)));
			videoList.append(($('<span/>').attr({ 'id': 'videoLoading' })).append($('<span/>').addClass('fa fa-spinner fa-spin')));
			videoSelector.append(videoList);
		}

		videoSelector.append($('<hr/>').attr({ 'id': 'hr2' }).css({ 'margin': '1em' }).addClass('hidden currentlySelectedVideos'));

		videoSelector.append($('<div/>').addClass('hidden currentlySelectedVideos').text('Currently Selected Video(s)'));
		var videoTable = $('<table/>').attr({ 'id': 'currentlySelectedVideosTable' }).addClass('hidden currentlySelectedVideos').css({ 'background-color': 'white', 'width': (boxcast ? '100%': '300px') });
		videoSelector.append(videoTable);

		if (boxcast)
		{
			var boxcasterId = ''
			var youtubeAccountId = '';
			var youtubeeventIds = [];
			if (broadcasts.length > 0)
			{
				for (var i = 0; i < broadcasts.length > 0; i++)
				{
					var broadcastId = broadcasts[i].broadcastId;
					var channelId = broadcasts[i].channelId;
					var youtubeId = broadcasts[i].youtubeId;
					var title = broadcasts[i].title;
					boxcasterId = broadcasts[i].boxcasterId;
					youtubeAccountId = broadcasts[i].youtubeAccountId;
					youtubeeventIds.push(youtubeId);

					videoTable = addBroadcastRowToTable(videoTable, broadcastId, channelId, youtubeId, title);
				}
			}

			//show youtube events not created using boxcaster
			if (events.length > 0)
			{
				for (var i = 0; i < events.length > 0; i++)
				{
					var youtubeId = events[i].eventId;
					var title = events[i].eventTitle;
					if (!youtubeeventIds.includes(youtubeId))
					{
						videoTable = addBroadcastRowToTable(videoTable, '', '', youtubeId, title);
					}	
				}
			}

			if ((boxcasters && boxcasters.length > 0) || (rtmpSources.length > 0))
			{
				var bx = $('<select/>').attr({ 'id': 'boxcastersId' }).css({ 'width': '325px', 'margin-right': '5px', 'height': '25px' });
				for (var i = 0; i < boxcasters.length > 0; i++)
				{
					var id = boxcasters[i].id;
					var name = boxcasters[i].name;	
					bx.append('<option value=' + id + (boxcasterId != '' && id == boxcasterId ? ' selected' : '') + '>' + name + '</option>');
				}
				for (var i = 0; i < rtmpSources.length > 0; i++) {
					var id = rtmpSources[i].id;
					var name = rtmpSources[i].name;
					bx.append('<option value=' + id + (boxcasterId != '' && id == boxcasterId ? ' selected' : '') + '>' + name + '</option>');
				}

				if ((boxcasters.length + rtmpSources.length) == 1)
				{
					bx.addClass('hidden');
					createVideoButton.before(bx);
				}
				else
				{
					createVideoButton.before($('<span/>').text('Source'));
					createVideoButton.before($('<br/>'));
					createVideoButton.before(bx);
				}
			}

			if (youtubeAccounts && youtubeAccounts.length > 0)
			{
				var ac = $('<select/>').attr({ 'id': 'youtubeAccounts' }).css({ 'width': '300px' }).addClass('hidden');
				for (var i = 0; i < youtubeAccounts.length > 0; i++)
				{
					var id = youtubeAccounts[i].id;
					var name = youtubeAccounts[i].name;	
					ac.append('<option value=' + id + (youtubeAccountId != '' && id == youtubeAccountId ? ' selected' : '') + '>' + name + '</option>');
				}
				videoSelectorWindow.append(ac);
			}
		}
		else
		{
			//videos list
			if (events.length > 0)
			{
				for (var i = 0; i < events.length > 0; i++)
				{
					var eventId = events[i].eventId;
					var eventTitle = events[i].eventTitle;

					videoTable = addEventRowToTable(videoTable, eventId, eventTitle);
				}
			}
		}

		//start at first time stamp
		//save button
		//remove button
		videoSelector.append($('<hr/>').attr({ 'id': 'hr3' }).css({ 'margin': '1em' }));

		var saveButton = $('<span/>').css({ 'padding-left': '15px' });
		saveButton.append($('<input/>').attr({ 'id': 'startAtFirstTimestamp', 'type': 'checkbox' }).prop('checked', startAtFirstTimestamp).off('click').on('click', function () { enableSaveButton(); }));
		saveButton.append($('<label/>').attr({ 'for': 'startAtFirstTimestamp' }).text('Start At First Timestamp?'));

		saveButton.append(($('<span/>').css({ 'padding-left': '20px' })).append($('<button/>').attr({ 'id': 'saveYouTubeEvents', 'type': 'button', 'disabled': 'disabled', 'title': 'Connect the selected ' + (boxcast ? 'broadcast(s)' : 'video(s)') + ' with this meeting' }).addClass('button button-wide background-color-hover').text('Save').off('click').on('click', saveYouTubeEvents)));
		//saveButton.append($('<input/>').attr({ 'id': 'removeYouTubeVideoEventId', 'type': 'button', 'value': 'Remove', 'title': 'Remove the connected video from this meeting' }).css({ 'margin-left': '2px' }).addClass('button background-color-hover').off('click').on('click', removeYouTubeVideoEventId));

		videoSelector.append($('<div/>').append(saveButton));


		videoSelectorWindow.append(videoSelector);
		$('body').prepend(videoSelectorWindow);

		$('#videoevent-selector-container').draggable({
			handle: 'div.visHeader',
			containment: 'body',
			scroll: false
		});
		if (boxcast)
		{
			localization.meetingDateInThePast = localization.meetingDateInThePast.replace("video", "broadcast").replace("live event", "broadcast");
			localization.meetingStartTimeDoesNotExists = localization.meetingStartTimeDoesNotExists.replace("live event", "broadcast");
			localization.meetingNameToLong = localization.meetingNameToLong.replace("live event", "broadcast");
		}
		if (!youTubeLite)
		{	
			var searchVideoMsg = $('<div id="searchLiveMsg" class="hidden">');
			searchVideoMsg.append(CivicWeb.Common.Notification.create('search-live-msg', CivicWeb.Common.Notification.types.warning, 'Searching for the YouTube live stream may take a few minutes.', false, false));
			$('#hr3').after(searchVideoMsg);

			if (boxcast && boxcasters.length == 0 && rtmpSources.length == 0)
			{
				$('#hr1').after(CivicWeb.Common.Notification.create('create-event-msg', CivicWeb.Common.Notification.types.warning, "Please validate the BoxCast credentials before creating a broadcast", false, false));
				$('#createYouTubeEvent').attr({ 'disabled': 'disabled' });
			}
			else if (meetingDateInThePast)
			{
				$('#hr1').after(CivicWeb.Common.Notification.create('create-event-msg', CivicWeb.Common.Notification.types.warning, localization.meetingDateInThePast, false, false));
				$('#createYouTubeEvent').attr({ 'disabled': 'disabled' });
			}
			else if (!meetingStartTimeExists)
			{
				var meetingStartTimeDoesNotExist = window.location.href.indexOf('MeetingDetail.aspx') > -1 ? localization.meetingStartTimeDoesNotExists + '.' : localization.meetingStartTimeDoesNotExists + ' from the <a href="/eaengine/MeetingDetail.aspx?id=' + meetingId + '">Overview Page.</a>';


				$('#hr1').after(CivicWeb.Common.Notification.create('create-event-msg', CivicWeb.Common.Notification.types.warning, meetingStartTimeDoesNotExist, false, false));
				$('#createYouTubeEvent').attr({ 'disabled': 'disabled', 'title': localization.meetingStartTimeDoesNotExists });
			}
			else if (meetingName.length > 100)
			{
				$('#hr1').after(CivicWeb.Common.Notification.create('create-event-msg', CivicWeb.Common.Notification.types.warning, localization.meetingNameToLong.replace("{0}", meetingName.length), false, false));
				$('#createYouTubeEvent').attr({ 'disabled': 'disabled' });
			}

			populateYouTubeVideoDropDown(true, boxcast);
		}

		if (events.length > 0 || broadcasts && broadcasts.length > 0)
		{
			$('.currentlySelectedVideos').removeClass('hidden');
		}

		e.preventDefault();
	};

	var addEventRowFromInput = function (e)
	{
		var youTubeLink = validateYouTubeUrl($('#videoEventId').val());
		if (youTubeLink.length > 0)
		{
			var eventId = youTubeLink;
			var eventTitle = $('#videoEventId').attr('data-meetingname');

			var videoTable = $('#currentlySelectedVideosTable');

			if (eventId != '0' && eventId.length > 0 && videoTable.find('a[eventId="' + eventId + '"]').length == 0 && videoTable.children().length < 9)
			{
				videoTable = addEventRowToTable(videoTable, eventId, eventTitle);
				nameVideoParts(videoTable);
				$('.currentlySelectedVideos').removeClass('hidden');
				$('#videoEventId').val('');
				enableSaveButton();
			}
			$('#invalid-youtube-msg').remove();
		}
		else
		{
			$('#hr1').after(CivicWeb.Common.Notification.create('invalid-youtube-msg', CivicWeb.Common.Notification.types.warning, "Please enter a valid YouTube broadcast link", false, false));
		}

		e.preventDefault();
	}

	function validateYouTubeUrl(url)
	{
		if (url != undefined || url != '')
		{
			var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/;
			var match = url.match(regExp);
			if (match && match[2].length == 11)
			{
				return match[2];
			}
			else
			{
				return '';
			}
		}
	}

	var removeEventRow = function (e)
	{
		$(this).closest('tr').remove();

		if ($('.selectedEvent').length > 0)
		{
			nameVideoParts($('#currentlySelectedVideosTable'));
			$('.currentlySelectedVideos').removeClass('hidden');
		}
		else
		{
			$('.currentlySelectedVideos').addClass('hidden');
		}

		enableSaveButton();

		e.preventDefault();
	};

	var addEventRow = function (e)
	{
		var eventId = $('#videoEventId option:selected').val();
		var eventTitle = $("#videoEventId option:selected").text();//.replace('**Live** ', '').replace(' (Video)', '').replace(' (Event)', '');

		var videoTable = $('#currentlySelectedVideosTable');

		if (eventId != '0' && eventId.length > 0 && videoTable.find('a[eventId="' + eventId + '"]').length == 0 && videoTable.children().length < 9)
		{
			const video = videoObjects.find((obj) => obj.value === eventId);

			if (purchasedBoxcast)
			{
				if (video.type === "boxcast")
				{
					eventTitle = video.label.replace(boxcastText);
					videoTable = addBroadcastRowToTable(videoTable, eventId, '', '', eventTitle);
				}
				else
				{
					eventTitle = video.label.replace(youtubeText);
					videoTable = addBroadcastRowToTable(videoTable, '', '', eventId, eventTitle);
				}
			}
			else
			{
				videoTable = addEventRowToTable(videoTable, eventId, eventTitle);
			}

			nameVideoParts(videoTable);
			$('.currentlySelectedVideos').removeClass('hidden');
			enableSaveButton();
		}

		e.preventDefault();
	};

	var addEventRowToTable = function (videoTable, eventId, eventTitle)
	{
		var videoRow = $('<tr/>');
		var videoCell = ($('<td/>')).append($('<a/>').attr({ 'href': 'https://www.youtube.com/watch?v=' + (eventId.length > 0 ? eventId : '#'), 'target': '_blank', 'eventId': eventId, 'eventTitle': eventTitle }).addClass('selectedEvent subMenuText').text(eventTitle));
		var buttonCell = ($('<td/>').css({ 'text-align': 'right' })).append(($('<span/>').attr({ 'role': 'button', 'title': 'Remove' }).css({ 'color': '#d20000', 'padding-left': '2em' }).addClass('glyphbutton text-negative button-spacing').off('click').on('click', removeEventRow)).append($('<span/>').addClass('fas fa-times')));

		videoRow.append(videoCell);
		videoRow.append(buttonCell);

		videoTable.append(videoRow);

		return videoTable;
	};

	var addBroadcastRowToTable = function(videoTable, broadcastId, channelId, youtubeId, title)
	{
		var videoRow = $('<tr/>');
		var textCell = ($('<td/>')).attr({ 'eventId': youtubeId, 'broadcastId': broadcastId, 'channelId': channelId, 'eventTitle': title }).addClass('selectedEvent subMenuText').text(title);
		var broadcastCell = ($('<td/>')).append($('<a/>').attr({ 'href': 'https://dashboard.boxcast.com/#/events/' + (broadcastId.length > 0 ? broadcastId : '#'), 'target': '_blank', 'eventId': broadcastId, 'eventTitle': title }).text(broadcastId.length > 0 ? "Broadcast" : ""));
		var youtubeCell = ($('<td/>')).append($('<a/>').attr({ 'href': 'https://www.youtube.com/watch?v=' + (youtubeId.length > 0 ? youtubeId : '#'), 'target': '_blank', 'eventId': youtubeId, 'eventTitle': title }).text(youtubeId.length > 0 ? "YouTube" : ""));
		var buttonCell = ($('<td/>').css({ 'text-align': 'right' })).append(($('<span/>').attr({ 'role': 'button', 'title': 'Remove' }).css({ 'color': '#d20000', 'padding-left': '2em' }).addClass('glyphbutton text-negative button-spacing').off('click').on('click', removeEventRow)).append($('<span/>').addClass('fas fa-times')));

		videoRow.append(textCell);
		videoRow.append(broadcastCell);
		videoRow.append(youtubeCell);
		videoRow.append(buttonCell);

		videoTable.append(videoRow);

		return videoTable;
	};

	var nameVideoParts = function (videoTable)
	{
		var partsText = [' (Part 1)', ' (Part 2)', ' (Part 3)', ' (Part 4)', ' (Part 5)', ' (Part 6)', ' (Part 7)', ' (Part 8)', ' (Part 9)']

		if (videoTable.children().length < 10)
		{
			var selectedVideoLinks = videoTable.find('.subMenuText');
			for (var i = 0; i < selectedVideoLinks.length; i++)
			{
				var videoName = $(selectedVideoLinks[i]).text();
				var partName = videoName.substring(videoName.length - partsText[0].length, videoName.length);
				if (partsText.indexOf(partName) > -1)
				{
					videoName = videoName.substring(0, videoName.length - partsText[0].length);
				}

				$(selectedVideoLinks[i]).text(videoName + (selectedVideoLinks.length > 1 ? partsText[i] : ''));
			}
		}

	};

	var enableSaveButton = function ()
	{
		var saveButton = $('#saveYouTubeEvents');
		saveButton.parent().addClass('wizard');
		saveButton.attr('disabled', false).css({ 'font-weight': 'bold' }).addClass('current');
	};

	var loadMoreVideos = function () {
		$('#addEventRow').attr({ 'disabled': 'disabled' });
		$('#loadMore').attr({ 'disabled': 'disabled' });
		$('#videoLoading').removeClass('hidden');

		populateYouTubeVideoDropDown(false);
	};

		this.populateYouTubeVideoDropDown = function ()
		{
				populateYouTubeVideoDropDown(false);
		};

	var populateYouTubeVideoDropDown = function (includeEvents, boxcast = false)
	{
		$.ajax({
			url: '/api/getvideos?nextPageToken=' + nextPageToken,
			contentType: 'application/json', dataType: 'json', async: true, cache: false, type: 'GET',
			success: function (response)
			{
				videoObjects = response.videos;
				nextPageToken = response.nextPageToken;
				var liveEventId = '';
				var liveEventName = '';
				liveEventExists = false;
				broadcastsChannels = {};

				var s = $('#videoEventId');
				// s.find('option').remove();
				if ($('#videoEventId option[value="0"]')?.length === 0) {
					s.prepend('<option value="0"></option>');
                }

				if (boxcast)
				{
					const boxcastVideos = videoObjects.filter((b) => b.type === "boxcast").sort((a, b) => (a.start < b.start ? 1 : a.start > b.start ? -1 : 0));

					$.each(boxcastVideos, function (key, value)
					{
						if (value.channelId)
						{
							broadcastsChannels[value.value] = value.channelId;
						}

						if ($('#videoEventId option[value="' + value.value + '"]')?.length === 0) {
							s.append('<option value=' + value.value + '>' + boxcastText + value.label + '</option>');
						}
					});

				}
				const youtubeVideos = (boxcast ? videoObjects.filter((b) => b.type === "youtube") : videoObjects).sort((a, b) => (a.start < b.start ? 1 : a.start > b.start ? -1 : 0));

				if (youtubeVideos != null && youtubeVideos.length > 0 && nextPageToken != null && nextPageToken.length > 0) {
					$('#loadMore').removeClass('hidden');
					$('#loadMore').removeAttr('disabled');
				} else {
					$('#loadMore').addClass('hidden');
				}

				$.each(youtubeVideos, function (key, value)
				{
					if (value.channelId)
					{
						broadcastsChannels[value.value] = value.channelId;
					}

					if (value.liveBroadcast == 'live')
					{
						liveEventId = value.value;
						liveEventName = value.label;
						liveEventExists = true;
					}
					else if (value.liveBroadcast == 'upcoming')
					{ 
						if (includeEvents)
						{
							if ($('#videoEventId option[value=' + value.value + ']')?.length === 0) {
								s.append('<option value="' + value.value + '">' + (boxcast ? youtubeText : "") + value.label + ' (Event)</option>');    
							}
						}
					}
					else
					{
						if ($('#videoEventId option[value="' + value.value + '"]')?.length === 0) {
							s.append('<option value=' + value.value + '>' + (boxcast ? youtubeText : "") + value.label + '</option>');
						}
					}
				});

				if (liveEventId.length > 0)
				{
					if ($('#videoEventId option[value="' + liveEventId + '"]')?.length === 0) {
						s.prepend('<option value=' + liveEventId + ' selected>**Live** ' + liveEventName + '</option>');
					}
					
					videoSelected = true;	
				}

				$('#addEventRow').removeAttr('disabled');
				$('#videoLoading').addClass('hidden');

				if (response.length < 800)
				{
					createYouTubeVideoCombobox();
				}
				else
				{
					$('#videoEventId').attr({'title': 'Select from the drop down the ' + (boxcast ? 'broadcast' : 'video') + ' you would like associated with this meeting' }).removeClass("hidden");
				}

				if (liveEventExists)
				{
					$('#videoSelectorInput').val('**Live** ' + liveEventName);
				}

			},
			error: function ()
			{
				//return '';
			}
		});
	};

	var createYouTubeVideoCombobox = function ()
	{
		$.widget("custom.combobox", {
			_create: function ()
			{
				this.wrapper = $("<span>")
					.addClass("custom-combobox")
					.insertAfter(this.element);

				this.element.hide();
				this._createAutocomplete();
				this._createShowAllButton();
			},

			_createAutocomplete: function ()
			{
				var selected = this.element.children(":selected"),
					value = selected.val() ? selected.text() : "";

				this.input = $("<input id='videoSelectorInput'>")
					.appendTo(this.wrapper)
					.val(value)
					.attr("title", "")
					.css({ 'width': '300px', 'max-width': '300px', 'background': 'white', 'height': '24px' })
					.addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left")
					.autocomplete({
						delay: 0,
						minLength: 0,
						source: $.proxy(this, "_source")
					})
					.tooltip({
						classes: {
							"ui-tooltip": "ui-state-highlight"
						}
					});

				this._on(this.input, {
					autocompleteselect: function (event, ui)
					{
						ui.item.option.selected = true;
						this._trigger("select", event, {
							item: ui.item.option
						});
					},

					autocompletechange: "_removeIfInvalid"
				});
			},

			_createShowAllButton: function ()
			{
				var input = this.input,
					wasOpen = false;

				$("<a>")
					.attr("tabIndex", -1)
					.attr("title", "Show All Items")
					.css({ 'height': '25px', 'vertical-align': 'top', 'margin-top': '2px', 'margin-right': '5px' })
					.tooltip()
					.appendTo(this.wrapper)
					.button({
						icons: {
							primary: "ui-icon-triangle-1-s"
						},
						text: false
					})
					.removeClass("ui-corner-all")
					.addClass("custom-combobox-toggle ui-corner-right")
					.on("mousedown", function ()
					{
						wasOpen = input.autocomplete("widget").is(":visible");
					})
					.on("click", function ()
					{
						input.trigger("focus");

						// Close if already visible
						if (wasOpen)
						{
							return;
						}

						// Pass empty string as value to search for, displaying all results
						input.autocomplete("search", "");
					});
			},

			_source: function (request, response)
			{
				var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
				response(this.element.children("option").map(function ()
				{
					var text = $(this).text();
					if (this.value && (!request.term || matcher.test(text)))
						return {
							label: text,
							value: text,
							option: this
						};
				}));
			},

			_removeIfInvalid: function (event, ui)
			{

				// Selected an item, nothing to do
				if (ui.item)
				{
					return;
				}

				// Search for a match (case-insensitive)
				var value = this.input.val(),
					valueLowerCase = value.toLowerCase(),
					valid = false;
				this.element.children("option").each(function ()
				{
					if ($(this).text().toLowerCase() === valueLowerCase)
					{
						this.selected = valid = true;
						return false;
					}
				});

				// Found a match, nothing to do
				if (valid)
				{
					return;
				}

				// Remove invalid value
				this.input
					.val("")
					.attr("title", value + " didn't match any item")
					.tooltip("open");
				this.element.val("");
				this._delay(function ()
				{
					this.input.tooltip("close").attr("title", "");
				}, 2500);
				this.input.autocomplete("instance").term = "";
			},

			_destroy: function ()
			{
				this.wrapper.remove();
				this.element.show();
			}
		});

		$("#videoEventId").combobox();

		$('.ui-autocomplete').css({ 'z-index': 14000, 'max-height': '165px', 'overflow': 'auto', 'border': '1px solid transparent' });
	};

	var createYouTubeEvent = function (e, meetingName)
	{
		var videoTable = $('#currentlySelectedVideosTable');

		if (videoTable.children().length < 9)
		{
			videoTable = addEventRowToTable(videoTable, '', meetingName);
			nameVideoParts(videoTable);
			$('.currentlySelectedVideos').removeClass('hidden');
			//problem with all events getting the title updated correctly in YouTube
			//var events = $('.selectedEvent');
			//if (events.length == 1)
			//{
			//	$('#createYouTubeEvent').attr('disabled', 'disabled').removeClass('background-color-hover').text('Creating...  ').append($('<span></span>').append($('<span></span>').addClass('fa fa-spinner fa-spin')));
			//	saveYouTubeEvents(e);
			//}
			//else
			//{
				enableSaveButton();
			//}
		}

		e.preventDefault();
	};

	var saveYouTubeEvents = function (e)
	{
		$('#saveYouTubeEvents').attr('disabled', 'disabled').text('Saving').css({ 'font-weight': 'normal' }).removeClass('current').append($('<span/>').addClass('fa fa-spinner fa-spin').css({ 'float': 'right', 'margin-left': '5px', 'margin-top': '4px' }));
		var eventsObject = [];
		var events = $('.selectedEvent');
		for (var i = 0; i < events.length; i++)
		{
			var eventId = $(events[i]).attr('eventId') != null ? $(events[i]).attr('eventId') : '';
			var broadcastId = $(events[i]).attr('broadcastId') != null ? $(events[i]).attr('broadcastId') : '';
			var channelId = $(events[i]).attr('channelId') ? $(events[i]).attr('channelId') : broadcastsChannels[broadcastId];
			var boxcasterId = $('#boxcastersId option:selected').val();
			var youtubeAccountId = $('#youtubeAccounts option:selected').val();
			var eventTitle = $(events[i]).text();
			var source = '';
			$.ajax({
				url: '/api/getevent/' + meetingId.toString(),
				contentType: 'application/json', dataType: 'json', async: false, cache: false, type: 'GET',
				success: function (result) {
					var data = JSON.parse(result);
					var rtmpSources = data.rtmpSources != null ? data.rtmpSources : [];
					if (rtmpSources.length > 0) {
						for (var i = 0; i < rtmpSources.length > 0; i++) {
							if (rtmpSources[i].id.toString() == boxcasterId.toString()) {
								source = 'rtmp';
							}
						}
					}
				},
				error: function () {
					//return '';
				}
			});

			eventsObject.push({ 'eventId': eventId, 'broadcastId': broadcastId, 'channelId': channelId, 'boxcasterId': boxcasterId, 'eventTitle': eventTitle, 'youtubeAccountId': youtubeAccountId, 'source': source });
		}

		saveVideoEventSettings(eventsObject, $('#startAtFirstTimestamp').prop('checked'));

		if (eventsObject.length > 1)
		{
			CivicWeb.Common.Instrumentation.recordAction('VMHD: Added multiple events - saveYouTubeEvents', meetingId);
		}

		e.preventDefault();
	};

	var getAdditionalEvents = function ()
	{
		var obj = {};
		obj.MeetingId = meetingId;
		obj.CurrentEvents = youTubeEvents;

		console.log('getAdditionalEvents');

		$.ajax({
			url: '/api/getadditionalevents/' + meetingId.toString(),
			contentType: 'application/json',
			dataType: 'json',
			async: true,
			cache: false,
			type: 'GET',
			success: function (response)
			{
				var nextNewEvent = addNewEventsAndGetNext(response);
				var nextNewEventId = nextNewEvent !=  null && nextNewEvent.eventId != null ? nextNewEvent.eventId : '';

				if (window.myPlayer != null && nextNewEventId.length > 0)
				{
					updateEventDropDown();
					window.myPlayer.loadVideoById(nextNewEventId, 0, "large");
				}
				else if (window.myPlayer != null && window.myPlayer.getPlayerState() == YT.PlayerState.BUFFERING)
				{
					//if still buffering
					//keep checking every 10 seconds
					setTimeout(function () { getAdditionalEvents(); }, 10000);
				}
			},
			error: function ()
			{
				//return '';
			}
		});
	};

	var eventIsYouTubeVideo = function (videoId)
	{
		const regex = /[a-zA-Z0-9_-]{11}/g;
		return videoId && videoId.length == 11 && videoId.search(regex) > -1;
	};

	var loadBoxCastVideo = function (containerId, broadcastChannelId)
	{
		var p = $('#videoDiv').detach();
		var timeStampVideoDiv = p.find("#timeStampVideoDiv");
		timeStampVideoDiv.css('height', '100%');
		timeStampVideoDiv.append($("<div id =\"boxcast-widget-" + broadcastChannelId + "\"></div><script type=\"text/javascript\" charset=\"utf-8\">(function(d, s, c, o) {var js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];var h = (('https:' == document.location.protocol) ? 'https:' : 'http:');js.src = h + '//js.boxcast.com/v3.min.js';js.onload = function() { boxcast.noConflict()('#boxcast-widget-'+c).loadChannel(c, o); };js.charset = 'utf-8';fjs.parentNode.insertBefore(js, fjs);}(document, 'script', '" + broadcastChannelId + "', {\"showTitle\":0,\"showDescription\":0,\"showHighlights\":0,\"showRelated\":false,\"defaultVideo\":\"next\",\"market\":\"partner\",\"showCountdown\":false,\"alwaysShowMediaControl\":1,\"showDocuments\":false,\"showIndex\":false,\"showDonations\":false}));</script>"));

		if (attachmentPane)
		{
			p.css('height', '100%');
			attachmentPane.prepend(p);
			setTimeout(function () { resizeVideoDiv(null); setVideoSize(); }, 100);
		}
		else if (documentBody)
		{
			documentBody.prepend(p);
			setTimeout(function () { resizeVideoDiv(null); setVideoSize(); }, 100);
		}
	};

	var loadYouTubeVideo = function (containerId)
	{
		var startAt = 0;

		if (startAtFirstTimestamp && firstTimeStamp < Number.MAX_SAFE_INTEGER)
		{
			startAt = firstTimeStamp;
		}
		if (window.location.href.indexOf('timestamp') > 0)
		{
			startAt = queryValues.timestamp;
		}

		var player = {
			playVideo: function (container, videoId)
			{
				if (typeof (YT) == 'undefined' || typeof (YT.Player) == 'undefined')
				{
					window.onYouTubePlayerAPIReady = function ()
					{
						player.loadPlayer(container, videoId);
					};

					var script = document.createElement('script');
					script.type = "text/javascript";
					script.src = "//www.youtube.com/player_api";
					$('body').append(script);

				} else
				{
					player.loadPlayer(container, videoId);
				}
			},
			loadPlayer: function (container, videoId)
			{
				window.myPlayer = new YT.Player(container, {
					playerVars: {
						modestbranding: 1,
						rel: 0,
						showinfo: 0,
						autoplay: (window.location.href.indexOf('timestamp') > 0 && queryValues.timestamp == startAt ? 0 : 1),
						start: startAt
					},
					height: videoHeight,
					width: videoWidth,
					videoId: videoId,
					events: {
						'onReady': onPlayerReady,
						'onStateChange': onPlayerStateChange
					}
				});

				p = $('#videoDiv').detach();

				if (attachmentPane)
				{
					p.css('height', '100%');
					attachmentPane.prepend(p);
					resizeVideoDiv(null);
				}
				else if (documentBody)
				{
					documentBody.prepend(p);
					resizeVideoDiv(null);
				}
			}
		};
		player.playVideo('timeStampVideoDiv', youTubeEventId);
	};

	var getCurrentUrlQueryValues = function ()
	{
		var vars = [], hash;
		var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
		for (var i = 0; i < hashes.length; i++)
		{
			hash = hashes[i].split('=');
			vars.push(hash[0]);
			vars[hash[0]] = hash[1];
		}
		return vars;
	};

	var updateEventDropDown = function ()
	{
		if (minutesBuild)
		{
			$('#multiVideoDropDown').remove();

			var events = CivicWeb.Integration.Video.getEvents();
			var eventDropDown = $('<select/>').attr({ 'id': 'multiVideoDropDown', 'width': (videoWidth - 2) + 'px' }).css({ 'width': (videoWidth - 2) + 'px', 'max-width': (videoWidth - 2) + 'px', 'margin': '0', 'padding': '0' }).change(function () { var currentEventId = $(this).val(); switchEvents(currentEventId); });
			if (events != null && events.length > 1)
			{
				for (var i = 0; i < events.length; i++)
				{
					eventDropDown.append($('<option/>').attr({ 'value': events[i].eventId }).css({ 'width': (videoWidth - 2) + 'px', 'max-width': (videoWidth - 2) + 'px' }).text(events[i].eventTitle));
				}
				eventDropDown.val(youTubeEventId);
				$('#timeStampVideoDiv').before(eventDropDown);
			}
		}
	};

	var addNewEventsAndGetNext = function(events)
	{
		var newEvent = '';
		var existingEventIds = []
		for (var i = 0; i < youTubeEvents.length; i++)
		{
			existingEventIds.push(youTubeEvents[i].eventId);
		}

		for (var j = 0; j < events.length; j++)
		{
			if (existingEventIds.indexOf(events[j].eventId) == -1)
			{
				currentVideo = j;
				youTubeEventId = events[j].eventId
				youTubeEvents = events;

				return events[j];
			}
		}

		return newEvent;
	};

	function onPlayerReady(event)
	{
		if (!isIOS)
		{
			event.target.playVideo();
		}
	};

	function onPlayerStateChange(event)
	{
		//if we hit any state change clear any search for additional events.
		clearTimeout(searchingForAdditionalEvents);

		//if the video has ended and there is another event then play the next one
		if (event.data == YT.PlayerState.ENDED)
		{
			if (currentVideo + 1 < youTubeEvents.length)
			{
				currentVideo = currentVideo + 1;
				youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';

				if (youTubeEventId.length > 0)
				{
					updateEventDropDown();
					window.myPlayer.loadVideoById(youTubeEventId, 0, "large");
				}
			}
			else
			{
				getAdditionalEvents();
			}
		}
		else if (event.data == YT.PlayerState.BUFFERING)
		{
			//BUFFERING may happend anytime during the stream
			//BUFFERING happens when the stream is paused i.e. hour lunch
			//BUFFERING happens when the stream is complete
			searchingForAdditionalEvents = setTimeout(
				function ()
				{
					if (currentVideo + 1 < youTubeEvents.length)
					{
						currentVideo = currentVideo + 1;
						youTubeEventId = youTubeEvents.length >= currentVideo && youTubeEvents[currentVideo].eventId != null ? youTubeEvents[currentVideo].eventId : '';

						if (youTubeEventId.length > 0)
						{
							updateEventDropDown();
							window.myPlayer.loadVideoById(youTubeEventId, 0, "large");
						}
					}
					else
					{
						getAdditionalEvents();
					}

				}, 10000);
		}
	};

	(function ()
	{
		if (manageVideo && meetingId != null && meetingId > 0)
		{
			setUpViewCreateEventLink(meetingId);
		}

		if (manageVideo && earthChannel)
		{
			var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
			var eventer = window[eventMethod];
			var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

			eventer(messageEvent, function (e)
			{
				var key = e.message ? "message" : "data";
				var data = e[key];
				if (data.indexOf("ECPlayerTime:") === 0)
				{
					var secs = data.split(":")[1];
					setVideoTimeStampDataCallback(itemId, secs, true);

				}
			}, false);
		}

		if (audioOnly)
		{
			$('#timeStampSyncVideo').attr({ 'title': 'Sync timestamps with recorded audio' });
			$('#timeStampVideoButton').attr({ 'title': 'Play the recorded audio' }).find('span').text('Play Audio');
		}

		if (minutesBuild)
		{
			setUpMinutesToTimeStamp(meetingId);
		}

		queryValues = getCurrentUrlQueryValues();

		isPhone = /android|webos|iphone|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase());
		isIOS = /ipad|iphone|ipod/i.test(navigator.userAgent.toLowerCase());

	})();
}

//Objects
CivicWeb.Integration.Video = {
	//Properties
	instance: null,


	createInstance: function (args)
	{
		if (this.instance)
		{
			delete this.instance;
		}
		this.instance = new CivicWeb.Integration.VideoClass(args);
	},

	getPublishedVideoUrl: function (id, f)
	{
		return this.instance.getPublishedVideoUrl(id, f);
	},

	addTimestampsAndVideoToMeetingDocument: function (meetingId, body, splitscreen)
	{
		return this.instance.addTimestampsAndVideoToMeetingDocument(meetingId, body, splitscreen);
	},

	moveVideoToAgendaFrame: function (moveBackToAttachmentFrame, i)
	{
		return this.instance.moveVideoToAgendaFrame(moveBackToAttachmentFrame, (i ? i : 1));
	},

	moveVideoToAttachmentFrame: function ()
	{
		return this.instance.moveVideoToAttachmentFrame();
	},

	addVideoButtonToPortal: function (meetingId, documentId, buttonClient)
	{
		return this.instance.addVideoButtonToPortal(meetingId, documentId, buttonClient);
	},

	getEvents: function ()
	{
		return this.instance.getEvents();
	},

	getCurrentEvent: function ()
	{
		return this.instance.getCurrentEvent();
	},

	getVideoTime: function (iframe, itemId, callback)
	{
		return this.instance.getVideoTime(iframe, itemId, callback);
	},

	getSyncMode: function ()
	{
		return this.instance.getSyncMode();
	},

	isAudioOnly: function ()
	{
		return this.instance.isAudioOnly();
	},

	isLive: function ()
	{
		return this.instance.isLive();
	},

	toggleTimeStampSyncMode: function ()
	{
		return this.instance.toggleTimeStampSyncMode();
	},

	hideVideo: function (e)
	{
		return this.instance.hideVideo(e);
	},

	convertSecondsToTimeString: function (secs, hyphens, itemId)
	{
		return this.instance.convertSecondsToTimeString(secs, hyphens, itemId);
	},

	resizeVideo: function ()
	{
		return this.instance.resizeVideo();
	},

	gotoMinutesVideoTimeStamp: function (e)
	{
		return this.instance.gotoMinutesVideoTimeStamp(e);
	},

	showPdfQuickViewVideoLink: function(meetingId, documentId)
	{
		return this.instance.showPdfQuickViewVideoLink(meetingId, documentId);
	},

		populateYouTubeVideoDropDown: function ()
		{
				return this.instance.populateYouTubeVideoDropDown();
		},

	events: {
	}
};
;
